home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / netpbma.zip / pbm / atktopbm.c next >
C/C++ Source or Header  |  1993-10-04  |  9KB  |  345 lines

  1. /* atktopbm.c - convert Andrew Toolkit raster object to portable bitmap
  2. **
  3. ** Copyright (C) 1991 by Bill Janssen
  4. **
  5. ** Permission to use, copy, modify, and distribute this software and its
  6. ** documentation for any purpose and without fee is hereby granted, provided
  7. ** that the above copyright notice appear in all copies and that both that
  8. ** copyright notice and this permission notice appear in supporting
  9. ** documentation.  This software is provided "as is" without express or
  10. ** implied warranty.
  11. */
  12.  
  13. #include <stdio.h>
  14. #include <sys/types.h>
  15. #include "pbm.h"
  16.  
  17. void ReadATKRaster ARGS((FILE *file, int *rwidth, int *rheight, unsigned char **destaddr));
  18. static long ReadRow ARGS((register FILE *file, register unsigned char *row, register long length));
  19.  
  20. int
  21. main( argc, argv )
  22.     int argc;
  23.     char *argv[];
  24.     {
  25.     FILE *ifp;
  26.     register bit *bitrow, *bP;
  27.     int rows, cols, row, col, charcount;
  28.     unsigned char *data, mask;
  29.  
  30.  
  31.     pbm_init ( &argc, argv );
  32.  
  33.     if ( argc > 2 )
  34.     pm_usage( "[raster obj]" );
  35.     
  36.     if ( argc == 2 )
  37.     ifp = pm_openr( argv[1] );
  38.     else
  39.     ifp = stdin;
  40.  
  41.     ReadATKRaster( ifp, &cols, &rows, &data );
  42.  
  43.     pm_close( ifp );
  44.  
  45.     pbm_writepbminit( stdout, cols, rows, 0 );
  46.     bitrow = pbm_allocrow( cols );
  47.  
  48.     for ( row = 0; row < rows; ++row )
  49.     {
  50.     charcount = 0;
  51.     mask = 0x80;
  52.     for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
  53.         {
  54.         if ( charcount >= 8 )
  55.         {
  56.         ++data;
  57.         charcount = 0;
  58.         mask = 0x80;
  59.         }
  60.         *bP = ( *data & mask ) ? PBM_BLACK : PBM_WHITE;
  61.         ++charcount;
  62.         mask >>= 1;
  63.         }
  64.     ++data;
  65.     pbm_writepbmrow( stdout, bitrow, cols, 0 );
  66.     }
  67.  
  68.     pm_close( stdout );
  69.     exit( 0 );
  70.     }
  71.  
  72. /* readatkraster
  73. **
  74. ** Routine for reading rasters in .raster form.  (BE2 rasters version 2.)
  75. */
  76.  
  77. /* codes for data stream */
  78. #define WHITEZERO    'f'
  79. #define WHITETWENTY    'z'
  80. #define BLACKZERO    'F'
  81. #define BLACKTWENTY    'Z'
  82. #define OTHERZERO    0x1F
  83.  
  84. #define    WHITEBYTE    0x00
  85. #define    BLACKBYTE    0xFF
  86.  
  87. /* error codes (copied from $ANDREW/atk/basics/common/dataobj.ch) */
  88. /* return values from Read */
  89. #define    dataobject_NOREADERROR    0
  90. #define    dataobject_PREMATUREEOF    1
  91. #define    dataobject_NOTBE2DATASTREAM 2 /* backward compatibility */
  92. #define    dataobject_NOTATKDATASTREAM 2 /* preferred version */
  93. #define dataobject_MISSINGENDDATAMARKER 3
  94. #define    dataobject_OBJECTCREATIONFAILED    4
  95. #define dataobject_BADFORMAT 5
  96.  
  97. /* ReadRow(file, row, length) 
  98. ** Reads from 'file' the encoding of bytes to fill in 'row'.  Row will be
  99. ** truncated or padded (with WHITE) to exactly 'length' bytes.
  100. **
  101. ** Returns the code that terminated the row.  This may be
  102. **         '|'      correct end of line
  103. **         '\0'     if the length was satisfied (before a terminator)
  104. **         EOF     if the file ended
  105. **         '\'  '{'     other recognized ends. 
  106. ** The '|' is the expected end and pads the row with WHITE.
  107. ** The '\' and '{' are error conditions and may indicate the
  108. ** beginning of some other portion of the data stream.
  109. ** If the terminator is '\' or '{', it is left at the front of the input.
  110. ** '|' is gobbled up.
  111. */
  112.  
  113. /* macros to generate case entries for switch statement */
  114. #define case1(v) case v
  115. #define case4(v) case v: case (v)+1: case (v)+2: case(v)+3
  116. #define case6(v) case4(v): case ((v)+4): case ((v)+5)
  117. #define case8(v) case4(v): case4((v)+4)
  118.  
  119. static long
  120. ReadRow(file, row, length)
  121.     register FILE *file;        /* where to get them from */
  122.     register unsigned char *row;    /* where to put bytes */
  123.     register long length;    /* how many bytes in row must be filled */
  124. {
  125.     /* Each input character is processed by the central loop.  There are 
  126.     ** some input codes which require two or three characters for
  127.     ** completion; these are handled by advancing the state machine.
  128.     ** Errors are not processed; instead the state machine is reset
  129.     ** to the Ready state whenever a character unacceptable to the
  130.     ** current state is read.
  131.     */
  132.     enum stateCode {
  133.         Ready,         /* any input code is allowed */
  134.         HexDigitPending,    /* have seen the first of a hex digit pair */
  135.         RepeatPending,     /* repeat code has been seen:
  136.                    must be followed by two hex digits */
  137.         RepeatAndDigit};    /* have seen repeat code and its first
  138.                    following digit */
  139.     enum stateCode InputState;    /* current state */
  140.     register c;        /* the current input character */
  141.     register long repeatcount = 0;    /* current repeat value */
  142.     register long hexval;    /* current hex value */
  143.     long pendinghex = 0;    /* the first of a pair of hex characters */
  144.     
  145.     /* We cannot exit when length becomes zero because we need to check 
  146.     ** to see if a row ending character follows.  Thus length is checked
  147.     ** only when we get a data generating byte.  If length then is
  148.     ** zero, we ungetc the byte.
  149.     */
  150.  
  151.     InputState = Ready;
  152.     while ((c=getc(file)) != EOF) switch (c) {
  153.  
  154.     case8(0x0):
  155.     case8(0x8):
  156.     case8(0x10):
  157.     case8(0x18):
  158.     case1(' '):
  159.         /* control characters and space are legal and ignored */
  160.         break;
  161.     case1(0x40):    /* '@' */
  162.     case1(0x5B):    /* '[' */
  163.     case4(0x5D):    /*  ']'  '^'  '_'  '`' */
  164.     case4(0x7D):    /* '}'  '~'  DEL  0x80 */
  165.     default:        /* all above 0x80 */
  166.         /* error code:  Ignored at present.  Reset InputState. */
  167.         InputState = Ready;
  168.         break;
  169.  
  170.     case1(0x7B):    /* '{' */
  171.     case1(0x5C):    /* '\\' */
  172.         /* illegal end of line:  exit anyway */
  173.         ungetc(c, file);    /* retain terminator in stream */
  174.         /* DROP THROUGH */
  175.     case1(0x7C):    /* '|' */
  176.         /* legal end of row: may have to pad  */
  177.         while (length-- > 0)
  178.             *row++ = WHITEBYTE;
  179.         return c;
  180.     
  181.     case1(0x21):
  182.     case6(0x22):
  183.     case8(0x28):
  184.         /* punctuation characters: repeat byte given by two
  185.         ** succeeding hex chars
  186.         */
  187.         if (length <= 0) {
  188.             ungetc(c, file);
  189.             return('\0');
  190.         }
  191.         repeatcount = c - OTHERZERO;
  192.         InputState = RepeatPending;
  193.         break;
  194.  
  195.     case8(0x30):
  196.     case8(0x38):
  197.         /* digit (or following punctuation)  -  hex digit */
  198.         hexval = c - 0x30;
  199.         goto hexdigit;
  200.     case6(0x41):
  201.         /* A ... F    -  hex digit */
  202.         hexval = c - (0x41 - 0xA);
  203.         goto hexdigit;
  204.     case6(0x61):
  205.         /* a ... f  - hex digit */
  206.         hexval = c - (0x61 - 0xA);
  207.         goto hexdigit;
  208.  
  209.     case8(0x67):
  210.     case8(0x6F):
  211.     case4(0x77):
  212.         /* g ... z   -   multiple WHITE bytes */
  213.         if (length <= 0) {
  214.             ungetc(c, file);
  215.             return('\0');
  216.         }
  217.         repeatcount = c - WHITEZERO;
  218.         hexval = WHITEBYTE;
  219.         goto store;
  220.     case8(0x47):
  221.     case8(0x4F):
  222.     case4(0x57):
  223.         /* G ... Z   -   multiple BLACK bytes */
  224.         if (length <= 0) {
  225.             ungetc(c, file);
  226.             return('\0');
  227.         }
  228.         repeatcount = c - BLACKZERO;
  229.         hexval = BLACKBYTE;
  230.         goto store;
  231.  
  232. hexdigit:
  233.         /* process a hex digit.  Use InputState to determine
  234.             what to do with it. */
  235.         if (length <= 0) {
  236.             ungetc(c, file);
  237.             return('\0');
  238.         }
  239.         switch(InputState) {
  240.         case Ready:
  241.             InputState = HexDigitPending;
  242.             pendinghex = hexval << 4;
  243.             break;
  244.         case HexDigitPending:
  245.             hexval |= pendinghex;
  246.             repeatcount = 1;
  247.             goto store;
  248.         case RepeatPending:
  249.             InputState = RepeatAndDigit;
  250.             pendinghex = hexval << 4;
  251.             break;
  252.         case RepeatAndDigit:
  253.             hexval |= pendinghex;
  254.             goto store;
  255.         }
  256.         break;
  257.  
  258. store:
  259.         /* generate byte(s) into the output row 
  260.             Use repeatcount, depending on state.  */
  261.         if (length < repeatcount) 
  262.             /* reduce repeat count if it would exceed
  263.                 available space */
  264.             repeatcount = length;
  265.         length -= repeatcount;    /* do this before repeatcount-- */
  266.         while (repeatcount-- > 0)
  267.                 *row++ = hexval;
  268.         InputState = Ready;
  269.         break;
  270.  
  271.     } /* end of while( - )switch( - ) */
  272.     return EOF;
  273. }
  274. #undef case1
  275. #undef case4
  276. #undef case6
  277. #undef case8
  278.  
  279. void
  280. ReadATKRaster(file, rwidth, rheight, destaddr)
  281.      FILE *file;
  282.      unsigned char **destaddr;
  283.      int *rwidth, *rheight;
  284. {
  285.     register unsigned char *byteaddr;    /* where to store next row */
  286.     register long row, rowlen;    /* count rows;  byte length of row */
  287.     long version, options, xscale, yscale;
  288.     long xoffset, yoffset, subwidth, subheight;
  289.     char keyword[6];
  290.     long discardid, objectid;     /* id read for the incoming pixel image */
  291.     long tc;            /* temp */
  292.     long width, height;        /* dimensions of image */
  293.     long result;
  294.  
  295.     if (fscanf(file, "\\begindata{raster,%ld", &discardid) != 1
  296.                 || getc(file) != '}' || getc(file) != '\n')
  297.       pm_error ("input file not Andrew raster object");
  298.  
  299.     fscanf(file, " %d ", &version);
  300.     if (version < 2) 
  301.       pm_error ("version too old to parse");
  302.  
  303.     /* ignore all these features: */
  304.     fscanf(file, " %u %ld %ld %ld %ld %ld %ld",  
  305.         &options, &xscale, &yscale, &xoffset, 
  306.         &yoffset, &subwidth, &subheight);
  307.  
  308.     /* scan to end of line in case this is actually something beyond V2 */
  309.     while (((tc=getc(file)) != '\n') && (tc != '\\') && (tc != EOF)) {}
  310.  
  311.     /* read the keyword */
  312.     fscanf(file, " %5s", keyword);
  313.     if (strcmp(keyword, "bits") != 0)
  314.       pm_error ("keyword is not bits!");
  315.  
  316.     fscanf(file, " %d %d %d ", &objectid, &width, &height);
  317.  
  318.     if (width < 1 || height < 1 || width > 1000000 || height > 1000000) 
  319.       pm_error ("bad width or height");
  320.  
  321.     *rwidth = width;
  322.     *rheight = height;
  323.     rowlen = (width + 7) / 8;
  324.     *destaddr = (unsigned char *) malloc (sizeof(unsigned char) * height *
  325. rowlen);
  326.     for (row = 0;   row < height;   row++)
  327.       {
  328.         long c;
  329.  
  330.         c = ReadRow(file, *destaddr + (row * rowlen), rowlen);
  331.         if (c != '|')
  332.           {
  333.         if (c == EOF)
  334.           pm_error ("premature EOF");
  335.         else
  336.           pm_error ("bad format");
  337.         break;
  338.           }
  339.       }
  340.     while (! feof(file) && getc(file) != '\\') {};    /* scan for \enddata */
  341.     if (fscanf(file, "enddata{raster,%d", &discardid) != 1
  342.         || getc(file) != '}' || getc(file) != '\n')
  343.       pm_error ("missing end-of-object marker");
  344. }
  345.