home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / xloadimg.zip / xloadimage.4.1 / pcx.c < prev    next >
C/C++ Source or Header  |  1993-10-28  |  11KB  |  382 lines

  1. /*
  2. ** pcx.c - load a ZSoft PC Paintbrush (PCX) file for use inside xloadimage
  3. **
  4. **    Tim Northrup <tim@BRS.Com>
  5. **    Adapted from code by Jef Poskanzer (see Copyright below).
  6. **
  7. **    Version 0.1 --  4/25/91 -- Initial cut
  8. **
  9. **  Copyright (c) 1991 Tim Northrup
  10. **    (see file "tgncpyrght.h" for complete copyright information)
  11. */
  12. /*
  13. ** Copyright (C) 1988 by Jef Poskanzer.
  14. **
  15. ** Permission to use, copy, modify, and distribute this software and its
  16. ** documentation for any purpose and without fee is hereby granted, provided
  17. ** that the above copyright notice appear in all copies and that both that
  18. ** copyright notice and this permission notice appear in supporting
  19. ** documentation.  This software is provided "as is" without express or
  20. ** implied warranty.
  21. **
  22. ** This program (pcxtopbm) is based on the pcx2rf program by:
  23. **   Mike Macgirvin
  24. **   Stanford Relativity Gyro Program GP-B
  25. **   Stanford, Calif. 94503
  26. **   ARPA: mike@relgyro.stanford.edu
  27. */
  28.  
  29. #include <stdio.h>
  30. #include "image.h"
  31. #include "tgncpyrght.h"
  32. #include "pcx.h"
  33.  
  34. /*
  35. **  pcxIdent
  36. **
  37. **    Identify passed file as a PC Paintbrush image or not
  38. **
  39. **    Returns 1 if file is a PCX file, 0 otherwise
  40. */
  41.  
  42.  
  43. unsigned int pcxIdent ( fullname, name )
  44.     char *fullname, *name;
  45. {
  46.     ZFILE *zf;
  47.     unsigned int ret;
  48.     int xmin;
  49.     int xmax;
  50.     int ymin;
  51.     int ymax;
  52.     int colors;
  53.     char *type;
  54.  
  55.     ret = 0;
  56.     if (! (zf = zopen ( fullname )))
  57.         return ( 0 );
  58.     PCXH = (PCXHeader *) lmalloc ( PCXHsize );
  59.     if (zread ( zf, (byte *)PCXH, PCXHsize ) == PCXHsize) {
  60.         if ((PCXH->Zid == PCX_MAGIC) && (PCXH->Zver <= 5)) {
  61.         xmin = Word ( PCXH->Zxminlo, PCXH->Zxminhi); 
  62.         xmax = Word ( PCXH->Zxmaxlo, PCXH->Zxmaxhi); 
  63.         ymin = Word ( PCXH->Zyminlo, PCXH->Zyminhi); 
  64.         ymax = Word ( PCXH->Zymaxlo, PCXH->Zymaxhi); 
  65.         xmax = xmax - xmin + 1;
  66.         ymax = ymax - ymin + 1;
  67.         colors = 1 << (PCXH->Zbpp * PCXH->Znplanes);
  68.         type = " PC Paintbrush image\n";
  69.         if (colors == 2) 
  70.              printf ( "%s is a %dx%d monochrome%s",
  71.                 name, xmax, ymax, type );
  72.         else printf ( "%s is a %dx%d %d color%s",    
  73.                 name, xmax, ymax, colors, type );
  74.         ret = 1;
  75.         }
  76.     }
  77.     zclose ( zf );
  78.     lfree ( (byte *)PCXH );
  79.     return ( ret );
  80. }
  81.  
  82.  
  83. /*
  84. **  PCX_Load_Raster
  85. **
  86. **    Load raster image data into passed image structure. Raster Data
  87. **
  88. **    means : Every bit is a pixel (if depth is 1) or every byte is a 
  89. **
  90. **    pixel (if depth is 8).
  91. **
  92. **    Returns no value (void function)
  93. */
  94.  
  95. static void PCX_Load_Raster ( zf, image, depth )
  96.     ZFILE *zf;
  97.     Image *image;
  98.     int depth;
  99.     /* Assertion : depth is 1 or 8 */
  100. {
  101.     byte *ptr    = &(image->data[0]);
  102.     int row        = 0;
  103.     int by_this_row = 0;
  104.     int by_per_row;
  105.     int linelen;
  106.     int corrector;
  107.     int i, b, cnt;
  108.  
  109.     by_per_row   = Word ( PCXH->Zbprlo, PCXH->Zbprhi);
  110.     if (depth == 1)
  111.         linelen  = (image->width / 8) + (image->width % 8 ? 1 : 0);
  112.     else linelen = image->width;
  113.     corrector    = by_per_row - linelen;
  114.     /* bytes per row is always even, which means that there is an    */
  115.     /* excess byte if an odd nr of bytes would be sufficient.    */
  116.     /* As newBitImage allocated memory without this    excess, we have */
  117.     /* to read one less. But as there are two cases of reading,    */
  118.     /* inside and outside of a run, I correct it afterwards, when    */
  119.     /* the line is complete.                    */
  120.     while ((b = zgetc(zf)) != EOF) {     /* Are we done ?    */
  121.         if ((b & 0xC0) == 0xC0) {        /* have a rep. count    */
  122.         cnt = b & 0x3F;            /* mask rep. bits out    */
  123.         b = zgetc ( zf );        /* get real bits    */
  124.         if (b == EOF) {            /* Shouldn't happen !    */
  125.             printf ( "Unexpected EOF\n" );
  126.             return;
  127.         }
  128.         }
  129.         else cnt = 1;            /* no repeating this one*/
  130.         if (depth ==1) b = 255 - b;        /* Have to invert    */
  131.         for ( i = 0; i < cnt; i++ ) {    /* store count times    */
  132.         *ptr++ = (byte) b;
  133.         if (++by_this_row == by_per_row) {
  134.             row++;            /* start of a new line    */
  135.             by_this_row = 0;        /* reset counter    */
  136.             if (corrector) ptr--;    /*evtlly correct pointer*/
  137.             if ( row >= image->height ) {
  138. #if 0
  139.             /* happens a lot on valid images - jimf 10.28.91 */
  140.             if (depth == 1)        /* Color : Map follows    */
  141.                 printf ("Warning: excess data ignored\n");
  142. #endif
  143.             return;
  144.             }
  145.         }
  146.         }
  147.     }
  148. }    
  149.  
  150. /*
  151. **  PCX_Planes
  152. **
  153. **    Load plane image data into passed image structure. Plane data
  154. **
  155. **    means : There are N planes, each containing M bits of a pixel
  156. **
  157. **    byte, where N * M is not greater than 8 and M divides 8. (The
  158. **
  159. **    cases M = 1 or 8, N = 1 are covered by PCX_Load_Raster).
  160. **
  161. **    Returns no value (void function)
  162. */
  163.  
  164.  
  165. static void PCX_Planes ( zf, image, bpp, nr_pl )
  166.     ZFILE *zf;
  167.     Image *image;
  168.     int bpp, nr_pl;
  169.     /* Assertion :                             */
  170.     /* bpp is 1, 2 or 4 only, dividing 8 without remainder anyways,    */
  171.     /* bpp * nr_pl <= 8                        */
  172. {
  173.     byte *ptr, *sptr;
  174.     register byte *tptr;    
  175.     int row        = 0;
  176.     int by_this_row = 0;
  177.     int by_per_row;
  178.     int this_plane    = 0;
  179.     int shifter    = 0;
  180.     register int j;
  181.     int i, b, cnt;
  182.             
  183.     ptr = &(image->data[0]);
  184.     by_per_row  = Word ( PCXH->Zbprlo, PCXH->Zbprhi);
  185.     sptr = tptr = (byte *) lcalloc ( by_per_row*8 );
  186.     /* We can't correct as easy as above, because we handle several    */
  187.     /* bit planes simultaneously, and we must not load beyond row    */
  188.     /* limits. So we load into a temporary row and copy it into    */
  189.     /* image structure when the row is completed.            */
  190.     while ((b = zgetc(zf)) != EOF) { 
  191.         if ((b & 0xC0) == 0xC0) {    /* Get count and data as above    */
  192.         cnt = b & 0x3F;    
  193.         b = zgetc ( zf );
  194.         if (b == EOF) {
  195.             printf ( "Unexpected EOF\n" );
  196.             return;
  197.         }
  198.         }
  199.         else cnt = 1;
  200.         for ( i = 0; i < cnt; i++ ) {    /* Load data into temp.    */
  201.         switch (bpp) {
  202.             case 1 : 
  203.             *tptr++ |= (byte) (((b & 0x80 ) >> 7) << shifter);
  204.             *tptr++ |= (byte) (((b & 0x40 ) >> 6) << shifter);
  205.             *tptr++ |= (byte) (((b & 0x20 ) >> 5) << shifter);
  206.             *tptr++ |= (byte) (((b & 0x10 ) >> 4) << shifter);
  207.             *tptr++ |= (byte) (((b & 0x08 ) >> 3) << shifter);
  208.             *tptr++ |= (byte) (((b & 0x04 ) >> 2) << shifter);
  209.             *tptr++ |= (byte) (((b & 0x02 ) >> 1) << shifter);
  210.             *tptr++ |= (byte)  ((b & 0x01 )       << shifter);
  211.             /* This is not a loop for performance reasons.    */
  212.             /* Can't write e.g. ">> 2 - shifter", because     */
  213.             /* that expression would get negative.        */
  214.             break;
  215.             case 2 :
  216.             *tptr++ |= (byte) (((b & 0xC0 ) >> 6) << shifter);
  217.             *tptr++ |= (byte) (((b & 0x30 ) >> 4) << shifter);
  218.             *tptr++ |= (byte) (((b & 0x0C ) >> 2) << shifter);
  219.             *tptr++ |= (byte)  ((b & 0x03 )       << shifter);
  220.             break;
  221.             case 4 :
  222.             *tptr++ |= (byte) (((b & 0xF0) >> 4) << shifter);
  223.             *tptr++ |= (byte)  ((b & 0x0F)       << shifter);
  224.             break;
  225.             default :; /* Can't happen if assertion holds    */
  226.         }
  227.         if (++by_this_row == by_per_row) {    /* Row done ?    */
  228.             by_this_row = 0;         /* reset counter    */
  229.             if (++this_plane == nr_pl) { /* was it last plane ?    */
  230.             row++;             /* inc counter        */
  231.             tptr = sptr;         /* get saved ptr    */
  232.             this_plane = shifter = 0;/* reset plane Nr    */
  233.             for (j = 0; j < image->width; j++) {
  234.                 *ptr++  = *tptr;    /* store final data    */
  235.                 *tptr++ = 0;    /* clear temp data    */
  236.             }
  237.             if ( row >= image->height ) 
  238.                 return;        /* Done with image ?    */
  239.             }
  240.             else            /* Prepare next plane    */
  241.             shifter = this_plane * bpp;
  242.             tptr = sptr;        /* Get saved ptr    */
  243.         }
  244.         }
  245.     }
  246. }  
  247.  
  248.  
  249. /*
  250. **  PCX_LoadImage
  251. **
  252. **    Load PC Paintbrush file into the passed Image structure.
  253. **
  254. **    Returns no value (void function)
  255. */
  256.  
  257.  
  258. static void PCX_LoadImage ( zf ,image )
  259.     ZFILE *zf;
  260.     Image *image;
  261. {
  262.     int pl;
  263.     switch (PCXH->Zbpp) {    /* What kind of plane do we have ?    */
  264.         case 1 :            /* Bit planes            */
  265.         if (PCXH->Znplanes == 1)    /* Only one : Read it    */
  266.             PCX_Load_Raster ( zf, image, 1 );
  267.         else PCX_Planes ( zf, image, 1, PCXH->Znplanes );
  268.         break;
  269.         case 2 :            /* Two or four bits per plane    */
  270.         case 4 :            /*      are read plane by plane */
  271.         PCX_Planes ( zf, image, PCXH->Zbpp, PCXH->Znplanes );
  272.         break;
  273.         case 8 :            /* Byte planes            */
  274.         if (PCXH->Znplanes == 1)    /* Only one : Read it    */
  275.             PCX_Load_Raster ( zf, image, 8 );
  276.         else {                /* More not allowed    */
  277.             printf ("Only 1 plane allowed if 8 bits per plane\n");
  278.             exit (1);
  279.         }
  280.         break;
  281.         default :                /* Neither case found    */
  282.         printf ("%d bits per plane not supported\n", PCXH->Zbpp );
  283.         exit (1);
  284.     }
  285. }
  286.  
  287.  
  288. /*
  289. **  pcxLoad
  290. **
  291. **    Load PCX Paintbrush file into an Image structure.
  292. **
  293. **    Returns pointer to allocated struct if successful, NULL otherwise
  294. */
  295.  
  296. Image *pcxLoad ( fullname, name, verbose )
  297.     char *fullname, *name;
  298.     unsigned int verbose;
  299. {
  300.     ZFILE *zf;
  301.     unsigned int i, ret;
  302.     int xmin;
  303.     int xmax;
  304.     int ymin;
  305.     int ymax;
  306.     int colors;
  307.     PCXcolor *cmap;
  308.     int clen;
  309.     Image *image;
  310.     
  311.     if ( ! (zf = zopen ( fullname )))    /* Open input file    */
  312.         return ( (Image *) NULL);
  313.     PCXH = (PCXHeader *) lmalloc ( PCXHsize );
  314.     if (zread ( zf, (byte *)PCXH, PCXHsize ) != PCXHsize) {    /* Read header    */
  315.         zclose ( zf );
  316.         return ( (Image *) NULL );
  317.     }
  318.     if ((PCXH->Zid != PCX_MAGIC) || (PCXH->Zver > 5)) {    
  319.         zclose ( zf );        /* Is it PCX, Version less 5 ?    */
  320.         return ( (Image *) NULL );
  321.     }
  322.     znocache(zf);            /* don't need caching anymore    */
  323.     xmin = Word ( PCXH->Zxminlo, PCXH->Zxminhi); /* Calculate sizes    */
  324.     xmax = Word ( PCXH->Zxmaxlo, PCXH->Zxmaxhi); 
  325.     ymin = Word ( PCXH->Zyminlo, PCXH->Zyminhi); 
  326.     ymax = Word ( PCXH->Zymaxlo, PCXH->Zymaxhi); 
  327.     xmax = xmax - xmin + 1;
  328.     ymax = ymax - ymin + 1;    
  329.     colors = 1 << (PCXH->Zbpp * PCXH->Znplanes); /* Calculate colors*/
  330.     if (verbose) {                /* Print Information    */
  331.          if (colors == 2) 
  332.         printf ( "%s is a %dx%d monochrome PC Paintbrush image\n",
  333.                 name, xmax, ymax );
  334.          else printf ( "%s is a %dx%d %d color PC Paintbrush image\n",
  335.                 name, xmax, ymax, colors );
  336.     }
  337.     if (colors > 256) {
  338.         printf ( "No more than 256 colors allowed in PCX format\n" );
  339.         exit (1);
  340.     }
  341.     if (PCXH->Zenc == 0) {
  342.         printf ( "Unencoded PCX format not yet supported. Please" );
  343.         printf ( " email the uuencoded image\n to erueg@cfgauss." );
  344.         printf ( "uni-math.gwdg.de\n" );
  345.         exit (1);
  346.     }
  347.     if (colors == 2)    /* Allocate appropriate pbm array    */
  348.         image = newBitImage ( xmax, ymax );
  349.     else {
  350.         image = newRGBImage ( xmax, ymax, 8 );    
  351.     }
  352.     PCX_LoadImage ( zf, image );
  353.     if (colors > 16) {        /* Handle external colormap    */
  354.         while ((i = zgetc(zf)) != PCX_MAPSTART);
  355.         clen = colors * 3;
  356.         cmap = (PCXcolor *) lmalloc ( clen );
  357.         if (zread ( zf, (byte *)cmap, clen ) != clen) {
  358.         printf ( "EOF while reading colormap" );
  359.         exit (1);
  360.         }
  361.         for ( i = 0; i < colors; i++) {
  362.         *(image->rgb.red   + i) = (cmap [i].Zred   << 8);
  363.         *(image->rgb.green + i) = (cmap [i].Zgreen << 8);
  364.         *(image->rgb.blue  + i) = (cmap [i].Zblue  << 8);
  365.         }
  366.         image->rgb.used = colors;
  367.         lfree ( (byte *)cmap );
  368.     }
  369.     else if (colors > 2) {        /* Handle internal colormap    */
  370.         for ( i = 0; i < colors; i++) {
  371.         *(image->rgb.red   + i) = (PCXH->Zcmap [i].Zred   << 8);
  372.         *(image->rgb.green + i) = (PCXH->Zcmap [i].Zgreen << 8);
  373.         *(image->rgb.blue  + i) = (PCXH->Zcmap [i].Zblue  << 8);
  374.         }
  375.         image->rgb.used = colors;
  376.     }
  377.     zclose ( zf );    
  378.     lfree ( (byte *)PCXH );
  379.     image->title = dupString(name);
  380.     return ( image );
  381. }
  382.