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