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

  1. /* ppmtopcx.c - read a portable pixmap and produce a PCX file
  2. **
  3. ** Copyright (C) 1990 by Michael Davidson.
  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 "ppm.h"
  15. #include "ppmcmap.h"
  16.  
  17. #define MAXCOLORS    256
  18. #define    MAXPLANES    4
  19.  
  20. /*
  21.  * Pointer to function returning an int
  22.  */
  23. typedef void (* vfunptr) ARGS(( int, int, unsigned char*, int, int ));
  24.  
  25. static void PCXEncode ARGS(( FILE* fp, int GWidth, int GHeight, int Colors, int Red[], int Green[], int Blue[], vfunptr GetPlanes ));
  26. static void PutPlane ARGS(( FILE* fp, unsigned char* buf, int Size ));
  27. static void ReadPlanes ARGS(( int y, int width, unsigned char* buf, int planes, int bits ));
  28. static void Putword ARGS(( int w, FILE* fp ));
  29. static void Putbyte ARGS(( int b, FILE* fp ));
  30.  
  31. static pixel** pixels;
  32. static colorhash_table cht;
  33.  
  34. int
  35. main( argc, argv )
  36.     int argc;
  37.     char* argv[];
  38.     {
  39.     FILE* ifp;
  40.     int argn, rows, cols, colors, i;
  41.     pixval maxval;
  42.     pixel black_pixel;
  43.     colorhist_vector chv;
  44.     int Red[MAXCOLORS], Green[MAXCOLORS], Blue[MAXCOLORS];
  45.     char* usage = "[ppmfile]";
  46.  
  47.  
  48.     ppm_init( &argc, argv );
  49.  
  50.     argn = 1;
  51.  
  52.     if ( argn < argc )
  53.     {
  54.     ifp = pm_openr( argv[argn] );
  55.     ++argn;
  56.     }
  57.     else
  58.     ifp = stdin;
  59.  
  60.     if ( argn != argc )
  61.     pm_usage( usage );
  62.  
  63.     pixels = ppm_readppm( ifp, &cols, &rows, &maxval );
  64.  
  65.     pm_close( ifp );
  66.  
  67.     /* Figure out the colormap. */
  68.     pm_message( "computing colormap..." );
  69.     chv = ppm_computecolorhist( pixels, cols, rows, MAXCOLORS, &colors );
  70.     if ( chv == (colorhist_vector) 0 )
  71.     pm_error(
  72.         "too many colors - try doing a 'ppmquant %d'", MAXCOLORS );
  73.     pm_message( "%d colors found", colors );
  74.  
  75.     /* Force black to slot 0 if possible. */
  76.     PPM_ASSIGN(black_pixel, 0, 0, 0 );
  77.     ppm_addtocolorhist(chv, &colors, MAXCOLORS, &black_pixel, 0, 0 );
  78.  
  79.     /* Now turn the ppm colormap into the appropriate PCX colormap. */
  80.     if ( maxval > 255 )
  81.     pm_message(
  82.         "maxval is not 255 - automatically rescaling colors" );
  83.     for ( i = 0; i < colors; ++i )
  84.     {
  85.     if ( maxval == 255 )
  86.         {
  87.         Red[i] = PPM_GETR( chv[i].color );
  88.         Green[i] = PPM_GETG( chv[i].color );
  89.         Blue[i] = PPM_GETB( chv[i].color );
  90.         }
  91.     else
  92.         {
  93.         Red[i] = (int) PPM_GETR( chv[i].color ) * 255 / maxval;
  94.         Green[i] = (int) PPM_GETG( chv[i].color ) * 255 / maxval;
  95.         Blue[i] = (int) PPM_GETB( chv[i].color ) * 255 / maxval;
  96.         }
  97.     }
  98.  
  99.     /* And make a hash table for fast lookup. */
  100.     cht = ppm_colorhisttocolorhash( chv, colors );
  101.     ppm_freecolorhist( chv );
  102.  
  103.     /* All set, let's do it. */
  104.     PCXEncode( stdout, cols, rows, colors, Red, Green, Blue, ReadPlanes );
  105.  
  106.     exit( 0 );
  107.     }
  108.  
  109. /*****************************************************************************
  110.  *
  111.  * PCXENCODE.C    - PCX Image compression interface
  112.  *
  113.  * PCXEncode( FName, GHeight, GWidth, Colors, Red, Green, Blue, GetPlanes )
  114.  *
  115.  *****************************************************************************/
  116.  
  117. #define TRUE 1
  118. #define FALSE 0
  119.  
  120. /* public */
  121.  
  122. static void
  123. PCXEncode(fp, GWidth, GHeight, Colors, Red, Green, Blue, GetPlanes )
  124. FILE* fp;
  125. int GWidth, GHeight;
  126. int Colors;
  127. int Red[], Green[], Blue[];
  128. vfunptr GetPlanes;
  129. {
  130.     int        BytesPerLine;
  131.     int        Planes;
  132.     int        BitsPerPixel;
  133.     unsigned char    *buf;
  134.     int        i;
  135.     int        n;
  136.     int        y;
  137.  
  138.     /*
  139.      * select number of planes and number of bits
  140.      * per pixel according to number of colors
  141.      */
  142.     /*
  143.      * 16 colors or less are handled as 1 bit per pixel
  144.      * with 1, 2, 3 or 4 color planes.
  145.      * more than 16 colors are handled as 8 bits per pixel
  146.      * with 1 plane
  147.      */
  148.     if (Colors > 16)
  149.     {
  150.         BitsPerPixel    = 8;
  151.         Planes        = 1;
  152.     }
  153.     else
  154.     {
  155.         BitsPerPixel    = 1;
  156.         if (Colors > 8)
  157.             Planes = 4;
  158.         else if (Colors > 4)
  159.             Planes = 3;
  160.         else if (Colors > 2)
  161.             Planes = 2;
  162.         else
  163.             Planes = 1;
  164.     }
  165.  
  166.         /*
  167.          * Write the PCX header
  168.          */
  169.     Putbyte( 0x0a, fp);        /* .PCX magic number        */
  170.     Putbyte( 0x05, fp);        /* PC Paintbrush version    */
  171.     Putbyte( 0x01, fp);        /* .PCX run length encoding    */
  172.     Putbyte( BitsPerPixel, fp);    /* bits per pixel        */
  173.  
  174.         Putword( 0, fp );        /* x1    - image left        */
  175.         Putword( 0, fp );        /* y1    - image top        */
  176.     Putword( GWidth-1, fp );    /* x2    - image right        */
  177.     Putword( GHeight-1, fp );    /* y2    - image bottom        */
  178.  
  179.     Putword( GWidth, fp );        /* horizontal resolution    */
  180.     Putword( GHeight, fp );        /* vertical resolution        */
  181.  
  182.         /*
  183.          * Write out the Color Map for images with 16 colors or less
  184.          */
  185.     n = (Colors <= 16) ? Colors : 16;
  186.         for (i = 0; i < n; ++i)
  187.     {
  188.                 Putbyte( Red[i], fp );
  189.                 Putbyte( Green[i], fp );
  190.                 Putbyte( Blue[i], fp );
  191.         }
  192.         for (; i < 16; ++i)
  193.     {
  194.                 Putbyte( 255, fp );
  195.                 Putbyte( 255, fp );
  196.                 Putbyte( 255, fp );
  197.         }
  198.  
  199.     Putbyte( 0, fp);        /* reserved byte        */
  200.  
  201.     Putbyte( Planes, fp);        /* number of color planes    */
  202.  
  203.     BytesPerLine    = ((GWidth * BitsPerPixel) + 7) / 8;
  204.     Putword( BytesPerLine, fp );    /* number of bytes per scanline    */
  205.  
  206.     Putword( 1, fp);        /* pallette info        */
  207.  
  208.     for (i = 0; i < 58; ++i)    /* fill to end of header    */
  209.         Putbyte( 0, fp );
  210.  
  211.     buf    = (unsigned char *)malloc( MAXPLANES * BytesPerLine );
  212.  
  213.     for (y = 0; y < GHeight; ++y)
  214.     {
  215.         (*GetPlanes)(y, GWidth, buf, Planes, BitsPerPixel);
  216.  
  217.         for (i = 0; i < Planes; ++i)
  218.             PutPlane(fp, buf + (i * BytesPerLine), BytesPerLine);
  219.     }
  220.  
  221.     /*
  222.      * color map for > 16 colors is at end of file
  223.      */
  224.     if (Colors > 16)
  225.     {
  226.         Putbyte( 0x0c, fp);        /* magic for 256 colors */
  227.             for (i = 0; i < Colors; ++i)
  228.         {
  229.                     Putbyte( Red[i], fp );
  230.                     Putbyte( Green[i], fp );
  231.                     Putbyte( Blue[i], fp );
  232.             }
  233.             for (; i < MAXCOLORS; ++i)
  234.         {
  235.                     Putbyte( 255, fp );
  236.                     Putbyte( 255, fp );
  237.                     Putbyte( 255, fp );
  238.             }
  239.     }
  240.  
  241.         fclose( fp );
  242. }
  243.  
  244. static void
  245. PutPlane(fp, buf, Size)
  246. FILE        *fp;
  247. unsigned char    *buf;
  248. int        Size;
  249. {
  250.     unsigned char    *end;
  251.     int        c;
  252.     int        previous;
  253.     int        count;
  254.  
  255.     end    = buf + Size;
  256.  
  257.     previous = *buf++;
  258.     count     = 1;
  259.  
  260.     while (buf < end)
  261.     {
  262.         c = *buf++;
  263.         if (c == previous && count < 63)
  264.         {
  265.             ++count;
  266.             continue;
  267.         }
  268.  
  269.         if (count > 1 || (previous & 0xc0) == 0xc0)
  270.         {
  271.             count |= 0xc0;
  272.             Putbyte ( count , fp );
  273.         }
  274.         Putbyte(previous, fp);
  275.         previous = c;
  276.         count    = 1;
  277.     }
  278.  
  279.     if (count > 1 || (previous & 0xc0) == 0xc0)
  280.     {
  281.         count |= 0xc0;
  282.         Putbyte ( count , fp );
  283.     }
  284.     Putbyte(previous, fp);
  285. }
  286.  
  287. static unsigned long PixMap[8][16] =
  288. {
  289.     0x00000000L,    0x00000080L,    0x00008000L,    0x00008080L,
  290.     0x00800000L,    0x00800080L,    0x00808000L,    0x00808080L,
  291.     0x80000000L,    0x80000080L,    0x80008000L,    0x80008080L,
  292.     0x80800000L,    0x80800080L,    0x80808000L,    0x80808080L,
  293. };
  294.  
  295. static void
  296. ReadPlanes(y, width, buf, planes, bits)
  297. int        y;
  298. int        width;
  299. unsigned char    *buf;
  300. int        planes;
  301. int        bits;
  302. {
  303.     static int    first_time = 1;
  304.     unsigned char    *plane0, *plane1, *plane2, *plane3;
  305.     int        i, j, x;
  306.  
  307.     /*
  308.      * 256 color, 1 plane, 8 bits per pixel
  309.      */
  310.     if (planes == 1 && bits == 8)
  311.     {
  312.         for (x = 0; x < width; ++x)
  313.             buf[x] = ppm_lookupcolor( cht, &pixels[y][x] );
  314.         return;
  315.     }
  316.  
  317.     /*
  318.      * must be 16 colors or less, 4 planes or less, 1 bit per pixel
  319.      */
  320.     if (first_time)
  321.     {
  322.         for (i = 1; i < 8; ++i)
  323.             for (j = 0; j < 16; ++j)
  324.                 PixMap[i][j] = PixMap[0][j] >> i;
  325.         first_time = 0;
  326.     }
  327.  
  328.     i = (width + 7) / 8;
  329.  
  330.     plane0    = buf;
  331.     plane1    = plane0 + i;
  332.     plane2    = plane1 + i;
  333.     plane3    = plane2 + i;
  334.  
  335.     i    = 0;
  336.     x    = 0;
  337.  
  338.     while ( x < width )
  339.     {
  340.         register unsigned long    t;
  341.  
  342.         t     = PixMap[0][ppm_lookupcolor( cht, &pixels[y][x++] )];
  343.         t    |= PixMap[1][ppm_lookupcolor( cht, &pixels[y][x++] )];
  344.         t    |= PixMap[2][ppm_lookupcolor( cht, &pixels[y][x++] )];
  345.         t    |= PixMap[3][ppm_lookupcolor( cht, &pixels[y][x++] )];
  346.         t    |= PixMap[4][ppm_lookupcolor( cht, &pixels[y][x++] )];
  347.         t    |= PixMap[5][ppm_lookupcolor( cht, &pixels[y][x++] )];
  348.         t    |= PixMap[6][ppm_lookupcolor( cht, &pixels[y][x++] )];
  349.         t    |= PixMap[7][ppm_lookupcolor( cht, &pixels[y][x++] )];
  350.  
  351.         plane0[i] = t;
  352.         plane1[i] = t >> 8;
  353.         plane2[i] = t >> 16;
  354.         plane3[i++] = t >> 24;
  355.     }
  356. }
  357.  
  358. /*
  359.  * Write out a word to the PCX file
  360.  */
  361. static void
  362. Putword( w, fp )
  363. int w;
  364. FILE *fp;
  365. {
  366.         fputc( w & 0xff, fp );
  367.         fputc( (w / 256) & 0xff, fp );
  368. }
  369.  
  370. /*
  371.  * Write out a byte to the PCX file
  372.  */
  373. static void
  374. Putbyte( b, fp )
  375. int b;
  376. FILE *fp;
  377. {
  378.         fputc( b & 0xff, fp );
  379. }
  380.  
  381. /* The End */
  382.