home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / NETWORK / netpbm_src.lzh / NETPBM / PPM / pcxtoppm.c < prev    next >
C/C++ Source or Header  |  1996-11-18  |  16KB  |  539 lines

  1. /*
  2.  * pcxtoppm.c - Converts from a PC Paintbrush PCX file to a PPM file.
  3.  *
  4.  * Copyright (c) 1990 by Michael Davidson
  5.  *
  6.  * Permission to use, copy, modify, and distribute this software and its
  7.  * documentation for any purpose and without fee is hereby granted,
  8.  * provided that the above copyright notice appear in all copies and that
  9.  * both that copyright notice and this permission notice appear in
  10.  * supporting documentation.
  11.  *
  12.  * This file is provided AS IS with no warranties of any kind.  The author
  13.  * shall have no liability with respect to the infringement of copyrights,
  14.  * trade secrets or any patents by this file or any part thereof.  In no
  15.  * event will the author be liable for any lost revenue or profits or
  16.  * other special, indirect and consequential damages.
  17.  *
  18.  * Modifications by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
  19.  * 20/Apr/94:
  20.  *  - checks if 16-color-palette is completely black -> use standard palette
  21.  *  - "-stdpalette" option to enforce this
  22.  *  - row-by-row operation (PPM output)
  23.  *  11/Dec/94:
  24.  *  - support for 24bit and 32bit (24bit + 8bit intensity) images
  25.  *  - row-by-row operation (PCX input, for 16-color and truecolor images)
  26.  *  - some code restructuring
  27.  *  15/Feb/95:
  28.  *  - bugfix for 16 color-images: few bytes allocated for rawrow in some cases
  29.  *  - added sanity checks for cols<->BytesPerLine
  30.  *  17/Jul/95:
  31.  *  - moved check of 16-color-palette into pcx_16col_to_ppm(),
  32.  *    now checks if it contains only a single color
  33.  */
  34. #include        "ppm.h"
  35.  
  36. #define DEBUG
  37.  
  38. #define PCX_MAGIC       0x0a            /* PCX magic number             */
  39. #define PCX_HDR_SIZE    128             /* size of PCX header           */
  40. #define PCX_256_COLORS  0x0c            /* magic number for 256 colors  */
  41.  
  42. #define PCX_MAXVAL      (pixval)255
  43.  
  44. /* prototypes */
  45. static void pcx_16col_to_ppm ARGS((FILE *ifp, int cols, int rows,
  46.                 int BytesPerLine, int BitsPerPixel, int Planes, pixel *cmap));
  47. static void pcx_256col_to_ppm ARGS((FILE *ifp, int cols, int rows, int BytesPerLine));
  48. static void pcx_truecol_to_ppm ARGS((FILE *ifp, int cols, int rows, int BytesPerLine, int Planes));
  49. static void GetPCXRow ARGS((FILE *ifp, unsigned char *pcxrow, int bytesperline));
  50. static void pcx_planes_to_pixels ARGS(( unsigned char *pixels, unsigned char *bitplanes, int bytesperline, int planes, int bitsperpixel ));
  51. static void pcx_unpack_pixels ARGS(( unsigned char *pixels, unsigned char *bitplanes, int bytesperline, int planes, int bitsperpixel ));
  52. static int GetByte ARGS(( FILE *fp ));
  53. static int GetWord ARGS(( FILE *fp ));
  54.  
  55. /* standard palette */
  56. static unsigned char StdRed[]   = { 0, 255,   0,   0, 170, 170, 170, 170, 85,  85,  85,  85, 255, 255, 255, 255 };
  57. static unsigned char StdGreen[] = { 0, 255, 170, 170,   0,   0, 170, 170, 85,  85, 255, 255,  85,  85, 255, 255 };
  58. static unsigned char StdBlue[]  = { 0, 255,   0, 170,   0, 170,   0, 170, 85, 255,  85, 255,  85, 255,  85, 255 };
  59.  
  60.  
  61. int
  62. main(argc, argv)
  63.     int         argc;
  64.     char        *argv[];
  65. {
  66.     register int  i;
  67.     FILE *ifp;
  68.     int Version, Xmin, Ymin, Xmax, Ymax, Width, Height, Encoding;
  69.     int Planes, BitsPerPixel, BytesPerLine, PaletteInfo;
  70.     pixel cmap16[16];
  71.     int argn;
  72.     short use_std_palette = 0;
  73.     char *usage = "[-stdpalette] [pcxfile]";
  74.  
  75.     ppm_init( &argc, argv );
  76.  
  77.     argn = 1;
  78.     while( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) {
  79.         if( pm_keymatch(argv[argn], "-stdpalette", 2) ) {
  80.             use_std_palette = 1;
  81.         }
  82.         else
  83.             pm_usage(usage);
  84.         ++argn;
  85.     }
  86.     if( argn < argc ) {
  87.         ifp    = pm_openr(argv[argn]);
  88.         ++argn;
  89.     }
  90.     else
  91.         ifp    = stdin;
  92.     if( argn != argc )
  93.         pm_usage(usage);
  94.  
  95.     /*
  96.      * read the PCX header
  97.      */
  98.     if (GetByte(ifp) != PCX_MAGIC)
  99.          pm_error("bad magic number - not a PCX file");
  100.  
  101.     Version = GetByte(ifp);  /* get version # */
  102.  
  103.     Encoding = GetByte(ifp);
  104.     if( Encoding != 1 )       /* check for PCX run length encoding   */
  105.          pm_error("unknown encoding scheme: %d", Encoding);
  106.  
  107.     BitsPerPixel= GetByte(ifp);
  108.     Xmin        = GetWord(ifp);
  109.     Ymin        = GetWord(ifp);
  110.     Xmax        = GetWord(ifp);
  111.     Ymax        = GetWord(ifp);
  112.  
  113.     Width       = (Xmax - Xmin) + 1;
  114.     Height      = (Ymax - Ymin) + 1;
  115.  
  116.     (void) GetWord(ifp);                /* ignore horizontal resolution */
  117.     (void) GetWord(ifp);                /* ignore vertical resolution   */
  118.  
  119.     /*
  120.      * get the 16-color color map
  121.      */
  122.     for (i = 0; i < 16; i++) {
  123.         int r, g, b;
  124.         r = GetByte(ifp);
  125.         g = GetByte(ifp);
  126.         b = GetByte(ifp);
  127.         PPM_ASSIGN(cmap16[i], r, g, b);
  128.     }
  129.  
  130.     (void) GetByte(ifp);                /* skip reserved byte       */
  131.     Planes      = GetByte(ifp);         /* # of color planes        */
  132.     BytesPerLine= GetWord(ifp);         /* # of bytes per line      */
  133.     PaletteInfo = GetWord(ifp);         /* palette info (ignored)   */
  134.  
  135. #ifdef DEBUG
  136.     pm_message("Version: %d", Version);
  137.     pm_message("BitsPerPixel: %d", BitsPerPixel);
  138.     pm_message("Xmin: %d   Ymin: %d   Xmax: %d   Ymax: %d", Xmin, Ymin, Xmax, Ymax);
  139.     pm_message("Planes: %d    BytesPerLine: %d    PaletteInfo: %d", Planes, BytesPerLine, PaletteInfo);
  140. #endif
  141.  
  142.     if( fseek(ifp, (long)PCX_HDR_SIZE, 0) != 0 )
  143.         pm_error("error seeking past header");
  144.  
  145.     if( use_std_palette ) {
  146.         for( i = 0; i < 16; i++ )
  147.             PPM_ASSIGN(cmap16[i], StdRed[i], StdGreen[i], StdBlue[i]);
  148.     }
  149.  
  150.     ppm_writeppminit(stdout, Width, Height, PCX_MAXVAL, 0);
  151.     switch (BitsPerPixel) {
  152.         case 1:
  153.             if( Planes >= 1 && Planes <= 4 )
  154.                 pcx_16col_to_ppm(ifp, Width, Height, BytesPerLine, BitsPerPixel, Planes, cmap16);
  155.             else
  156.                 goto fail;
  157.             break;
  158.         case 2:
  159.         case 4:
  160.             if( Planes == 1 )
  161.                 pcx_16col_to_ppm(ifp, Width, Height, BytesPerLine, BitsPerPixel, Planes, cmap16);
  162.             else
  163.                 goto fail;
  164.             break;
  165.         case 8:
  166.             switch( Planes ) {
  167.                 case 1:
  168.                     pcx_256col_to_ppm(ifp, Width, Height, BytesPerLine);
  169.                     break;
  170.                 case 3:
  171.                 case 4:
  172.                     pcx_truecol_to_ppm(ifp, Width, Height, BytesPerLine, Planes);
  173.                     break;
  174.                 default:
  175.                     goto fail;
  176.             }
  177.             break;
  178.         default:
  179. fail:
  180.             pm_error("can't handle %d bits per pixel image with %d planes",
  181.                         BitsPerPixel,Planes);
  182.     }
  183.     pm_close(ifp);
  184.     exit(0);
  185. }
  186.  
  187.  
  188. static void
  189. pcx_16col_to_ppm(ifp, cols, rows, BytesPerLine, BitsPerPixel, Planes, cmap)
  190.     FILE *ifp;
  191.     int cols, rows;
  192.     int BytesPerLine, BitsPerPixel, Planes;
  193.     pixel *cmap;    /* colormap from header */
  194. {
  195.     int row, col, rawcols, colors;
  196.     unsigned char *pcxrow, *rawrow;
  197.     pixel *ppmrow;
  198.     short palette_ok = 0;
  199.  
  200. #ifdef DEBUG
  201.     pm_message("16 color -> ppm");
  202. #endif
  203.  
  204.     /* check if palette is ok  */
  205.     colors = (1 << BitsPerPixel) * (1 << Planes);
  206.     for( col = 0; col < colors-1; col++ ) {
  207.         if( !PPM_EQUAL(cmap[col], cmap[col+1]) ) {
  208.             palette_ok = 1;
  209.             break;
  210.         }
  211.     }
  212.     if( !palette_ok ) {
  213.         pm_message("warning - useless header palette, using builtin standard palette");
  214.         for( col = 0; col < colors; col++ )
  215.             PPM_ASSIGN(cmap[col], StdRed[col], StdGreen[col], StdBlue[col]);
  216.     }
  217.  
  218.     /*  BytesPerLine should be >= BitsPerPixel * cols / 8  */
  219.     rawcols = BytesPerLine * 8 / BitsPerPixel;
  220.     if( cols > rawcols ) {
  221.         pm_message("warning - BytesPerLine = %d, truncating image to %d pixels",
  222.                     BytesPerLine, rawcols);
  223.         cols = rawcols;
  224.     }
  225.     pcxrow = (unsigned char *)pm_allocrow(Planes * BytesPerLine, sizeof(unsigned char));
  226.     rawrow = (unsigned char *)pm_allocrow(rawcols, sizeof(unsigned char));
  227.     ppmrow = ppm_allocrow(cols);
  228.  
  229.     for( row = 0; row < rows; row++ ) {
  230.         GetPCXRow(ifp, pcxrow, Planes * BytesPerLine);
  231.  
  232.         if (Planes == 1)
  233.             pcx_unpack_pixels(rawrow, pcxrow, BytesPerLine, Planes, BitsPerPixel);
  234.         else
  235.             pcx_planes_to_pixels(rawrow, pcxrow, BytesPerLine, Planes, BitsPerPixel);
  236.  
  237.         for( col = 0; col < cols; col++ )
  238.             ppmrow[col] = cmap[rawrow[col]];
  239.         ppm_writeppmrow(stdout, ppmrow, cols, PCX_MAXVAL, 0);
  240.     }
  241.  
  242. #ifdef DEBUG
  243.     pm_message("done!");
  244. #endif
  245.     ppm_freerow(ppmrow);
  246.     pm_freerow(rawrow);
  247.     pm_freerow(pcxrow);
  248. }
  249.  
  250.  
  251. static void
  252. pcx_256col_to_ppm(ifp, cols, rows, BytesPerLine)
  253.     FILE *ifp;
  254.     int cols, rows;
  255.     int BytesPerLine;
  256. {
  257.     pixel colormap[256];
  258.     pixel *ppmrow;
  259.     unsigned char **image;
  260.     int row, col;
  261.  
  262. #ifdef DEBUG
  263.     pm_message("256 color -> ppm, reading index array...");
  264. #endif
  265.  
  266.     if( cols > BytesPerLine ) {
  267.         pm_message("warning - BytesPerLine = %d, truncating image to %d pixels",
  268.                     BytesPerLine,  BytesPerLine);
  269.         cols = BytesPerLine;
  270.     }
  271.  
  272.     image = (unsigned char **)pm_allocarray(BytesPerLine, rows, sizeof(unsigned char));
  273.     for( row = 0; row < rows; row++ )
  274.         GetPCXRow(ifp, image[row], BytesPerLine);
  275.  
  276. #ifdef DEBUG
  277.     pm_message("ok, now reading colormap...");
  278. #endif
  279.  
  280.     /*
  281.      * 256 color images have their color map at the end of the file
  282.      * preceeded by a magic byte
  283.      */
  284.     if (GetByte(ifp) != PCX_256_COLORS)
  285.         pm_error("bad color map signature" );
  286.     for( col = 0; col < 256; col++ ) {
  287.         int r, g, b;
  288.         r = GetByte(ifp);
  289.         g = GetByte(ifp);
  290.         b = GetByte(ifp);
  291.         PPM_ASSIGN(colormap[col], r, g, b);
  292.     }
  293.  
  294. #ifdef DEBUG
  295.     pm_message("ok, converting...");
  296. #endif
  297.  
  298.     ppmrow = ppm_allocrow(cols);
  299.     for( row = 0; row < rows; row++ ) {
  300.         for( col = 0; col < cols; col++ )
  301.             ppmrow[col] = colormap[image[row][col]];
  302.         ppm_writeppmrow(stdout, ppmrow, cols, PCX_MAXVAL, 0);
  303.     }
  304. #ifdef DEBUG
  305.     pm_message("done!");
  306. #endif
  307.  
  308.     ppm_freerow(ppmrow);
  309.     pm_freearray(image, rows);
  310. }
  311.  
  312.  
  313. static void
  314. pcx_truecol_to_ppm(ifp, cols, rows, BytesPerLine, Planes)
  315.     FILE *ifp;
  316.     int cols, rows;
  317.     int BytesPerLine, Planes;
  318. {
  319.     unsigned char *redrow, *greenrow, *bluerow, *intensityrow;
  320.     pixel *ppmrow;
  321.     int row, col;
  322.     int r, g, b, i;
  323.  
  324. #ifdef DEBUG
  325.     pm_message("%dbit truecolor -> ppm", Planes * 8);
  326. #endif
  327.  
  328.     if( cols > BytesPerLine ) {
  329.         pm_message("warning - BytesPerLine = %d, truncating image to %d pixels",
  330.                     BytesPerLine,  BytesPerLine);
  331.         cols = BytesPerLine;
  332.     }
  333.  
  334.     redrow       = (unsigned char *)pm_allocrow(BytesPerLine, sizeof(unsigned char*));
  335.     greenrow     = (unsigned char *)pm_allocrow(BytesPerLine, sizeof(unsigned char*));
  336.     bluerow      = (unsigned char *)pm_allocrow(BytesPerLine, sizeof(unsigned char*));
  337.     if( Planes == 4 )
  338.         intensityrow = (unsigned char *)pm_allocrow(BytesPerLine, sizeof(unsigned char*));
  339.     else
  340.         intensityrow = (unsigned char *)NULL;
  341.  
  342.     ppmrow = ppm_allocrow(cols);
  343.     for( row = 0; row < rows; row++ ) {
  344.         GetPCXRow(ifp, redrow, BytesPerLine);
  345.         GetPCXRow(ifp, greenrow, BytesPerLine);
  346.         GetPCXRow(ifp, bluerow, BytesPerLine);
  347.         if( intensityrow )
  348.             GetPCXRow(ifp, intensityrow, BytesPerLine);
  349.         for( col = 0; col < cols; col++ ) {
  350.             r = redrow[col];
  351.             g = greenrow[col];
  352.             b = bluerow[col];
  353.             if( intensityrow ) {
  354.                 i = intensityrow[col];
  355.                 r = r * i / 256;
  356.                 g = g * i / 256;
  357.                 b = b * i / 256;
  358.             }
  359.             PPM_ASSIGN(ppmrow[col], r, g, b);
  360.         }
  361.         ppm_writeppmrow(stdout, ppmrow, cols, PCX_MAXVAL, 0);
  362.     }
  363. #ifdef DEBUG
  364.     pm_message("done!");
  365. #endif
  366.  
  367.     ppm_freerow(ppmrow);
  368.     if( intensityrow )
  369.         pm_freerow(intensityrow);
  370.     pm_freerow(bluerow);
  371.     pm_freerow(greenrow);
  372.     pm_freerow(redrow);
  373. }
  374.  
  375.  
  376. /*
  377.  * convert multi-plane format into 1 pixel per byte
  378.  */
  379. static void
  380. pcx_planes_to_pixels(pixels, bitplanes, bytesperline, planes, bitsperpixel)
  381. unsigned char   *pixels;
  382. unsigned char   *bitplanes;
  383. int             bytesperline;
  384. int             planes;
  385. int             bitsperpixel;
  386. {
  387.     int  i, j;
  388.     int  npixels;
  389.     unsigned char    *p;
  390.  
  391.     if (planes > 4)
  392.          pm_error("can't handle more than 4 planes" );
  393.     if (bitsperpixel != 1)
  394.          pm_error("can't handle more than 1 bit per pixel" );
  395.  
  396.     /*
  397.      * clear the pixel buffer
  398.      */
  399.     npixels = (bytesperline * 8) / bitsperpixel;
  400.     p    = pixels;
  401.     while (--npixels >= 0)
  402.          *p++ = 0;
  403.  
  404.     /*
  405.      * do the format conversion
  406.      */
  407.     for (i = 0; i < planes; i++)
  408.     {
  409.          int pixbit, bits, mask;
  410.  
  411.          p    = pixels;
  412.          pixbit    = (1 << i);
  413.          for (j = 0; j < bytesperline; j++)
  414.          {
  415.              bits = *bitplanes++;
  416.              for (mask = 0x80; mask != 0; mask >>= 1, p++)
  417.                  if (bits & mask)
  418.                      *p |= pixbit;
  419.          }
  420.      }
  421. }
  422.  
  423. /*
  424.  * convert packed pixel format into 1 pixel per byte
  425.  */
  426. static void
  427. pcx_unpack_pixels(pixels, bitplanes, bytesperline, planes, bitsperpixel)
  428. unsigned char   *pixels;
  429. unsigned char   *bitplanes;
  430. int             bytesperline;
  431. int             planes;
  432. int             bitsperpixel;
  433. {
  434.     register int        bits;
  435.  
  436.     if (planes != 1)
  437.          pm_error("can't handle packed pixels with more than 1 plane" );
  438. #if 0
  439.     if (bitsperpixel == 8)
  440.     {
  441.         while (--bytesperline >= 0)
  442.             *pixels++ = *bitplanes++;
  443.     }
  444.     else
  445. #endif
  446.     if (bitsperpixel == 4)
  447.     {
  448.         while (--bytesperline >= 0)
  449.         {
  450.             bits        = *bitplanes++;
  451.             *pixels++   = (bits >> 4) & 0x0f;
  452.             *pixels++   = (bits     ) & 0x0f;
  453.         }
  454.     }
  455.     else if (bitsperpixel == 2)
  456.     {
  457.         while (--bytesperline >= 0)
  458.         {
  459.             bits        = *bitplanes++;
  460.             *pixels++   = (bits >> 6) & 0x03;
  461.             *pixels++   = (bits >> 4) & 0x03;
  462.             *pixels++   = (bits >> 2) & 0x03;
  463.             *pixels++   = (bits     ) & 0x03;
  464.         }
  465.     }
  466.     else if (bitsperpixel == 1)
  467.     {
  468.         while (--bytesperline >= 0)
  469.         {
  470.             bits        = *bitplanes++;
  471.             *pixels++   = ((bits & 0x80) != 0);
  472.             *pixels++   = ((bits & 0x40) != 0);
  473.             *pixels++   = ((bits & 0x20) != 0);
  474.             *pixels++   = ((bits & 0x10) != 0);
  475.             *pixels++   = ((bits & 0x08) != 0);
  476.             *pixels++   = ((bits & 0x04) != 0);
  477.             *pixels++   = ((bits & 0x02) != 0);
  478.             *pixels++   = ((bits & 0x01) != 0);
  479.         }
  480.     }
  481.     else
  482.         pm_error("pcx_unpack_pixels - can't handle %d bits per pixel", bitsperpixel);
  483. }
  484.  
  485. static int
  486. GetByte(fp)
  487. FILE    *fp;
  488. {
  489.     int    c;
  490.  
  491.     if ((c = fgetc(fp)) == EOF)
  492.          pm_error("unexpected end of file" );
  493.  
  494.     return c;
  495. }
  496.  
  497. static int
  498. GetWord(fp)
  499. FILE    *fp;
  500. {
  501.     int c;
  502.     c  = GetByte(fp);
  503.     c |= (GetByte(fp) << 8);
  504.     return c;
  505. }
  506.  
  507.  
  508. /*
  509.  *  read a single row encoded row, handles encoding across rows
  510.  */
  511. static void
  512. GetPCXRow(ifp, pcxrow, bytesperline)
  513.     FILE *ifp;
  514.     unsigned char *pcxrow;
  515.     int bytesperline;
  516. {
  517.     static int count = 0;
  518.     static int c;
  519.     int i;
  520.  
  521.     i = 0;
  522.     while( i < bytesperline ) {
  523.         if( count ) {
  524.             pcxrow[i++] = c;
  525.             --count;
  526.         }
  527.         else {
  528.             c = GetByte(ifp);
  529.             if( (c & 0xc0) != 0xc0 )
  530.                 pcxrow[i++] = c;
  531.             else {
  532.                 count = c & 0x3f;
  533.                 c = GetByte(ifp);
  534.             }
  535.         }
  536.     }
  537. }
  538.  
  539.