home *** CD-ROM | disk | FTP | other *** search
- /* ppmtopcx.c - read a portable pixmap and produce a PCX file
- **
- ** Copyright (C) 1990 by Michael Davidson.
- **
- ** Permission to use, copy, modify, and distribute this software and its
- ** documentation for any purpose and without fee is hereby granted, provided
- ** that the above copyright notice appear in all copies and that both that
- ** copyright notice and this permission notice appear in supporting
- ** documentation. This software is provided "as is" without express or
- ** implied warranty.
- */
-
- #include <stdio.h>
- #include "ppm.h"
- #include "ppmcmap.h"
-
- #define MAXCOLORS 256
- #define MAXPLANES 4
-
- /*
- * Pointer to function returning an int
- */
- typedef void (* vfunptr) ARGS(( int, int, unsigned char*, int, int ));
-
- static void PCXEncode ARGS(( FILE* fp, int GWidth, int GHeight, int Colors, int Red[], int Green[], int Blue[], vfunptr GetPlanes ));
- static void PutPlane ARGS(( FILE* fp, unsigned char* buf, int Size ));
- static void ReadPlanes ARGS(( int y, int width, unsigned char* buf, int planes, int bits ));
- static void Putword ARGS(( int w, FILE* fp ));
- static void Putbyte ARGS(( int b, FILE* fp ));
-
- static pixel** pixels;
- static colorhash_table cht;
-
- int
- main( argc, argv )
- int argc;
- char* argv[];
- {
- FILE* ifp;
- int argn, rows, cols, colors, i;
- pixval maxval;
- pixel black_pixel;
- colorhist_vector chv;
- int Red[MAXCOLORS], Green[MAXCOLORS], Blue[MAXCOLORS];
- char* usage = "[ppmfile]";
-
-
- ppm_init( &argc, argv );
-
- argn = 1;
-
- if ( argn < argc )
- {
- ifp = pm_openr( argv[argn] );
- ++argn;
- }
- else
- ifp = stdin;
-
- if ( argn != argc )
- pm_usage( usage );
-
- pixels = ppm_readppm( ifp, &cols, &rows, &maxval );
-
- pm_close( ifp );
-
- /* Figure out the colormap. */
- pm_message( "computing colormap..." );
- chv = ppm_computecolorhist( pixels, cols, rows, MAXCOLORS, &colors );
- if ( chv == (colorhist_vector) 0 )
- pm_error(
- "too many colors - try doing a 'ppmquant %d'", MAXCOLORS );
- pm_message( "%d colors found", colors );
-
- /* Force black to slot 0 if possible. */
- PPM_ASSIGN(black_pixel, 0, 0, 0 );
- ppm_addtocolorhist(chv, &colors, MAXCOLORS, &black_pixel, 0, 0 );
-
- /* Now turn the ppm colormap into the appropriate PCX colormap. */
- if ( maxval > 255 )
- pm_message(
- "maxval is not 255 - automatically rescaling colors" );
- for ( i = 0; i < colors; ++i )
- {
- if ( maxval == 255 )
- {
- Red[i] = PPM_GETR( chv[i].color );
- Green[i] = PPM_GETG( chv[i].color );
- Blue[i] = PPM_GETB( chv[i].color );
- }
- else
- {
- Red[i] = (int) PPM_GETR( chv[i].color ) * 255 / maxval;
- Green[i] = (int) PPM_GETG( chv[i].color ) * 255 / maxval;
- Blue[i] = (int) PPM_GETB( chv[i].color ) * 255 / maxval;
- }
- }
-
- /* And make a hash table for fast lookup. */
- cht = ppm_colorhisttocolorhash( chv, colors );
- ppm_freecolorhist( chv );
-
- /* All set, let's do it. */
- PCXEncode( stdout, cols, rows, colors, Red, Green, Blue, ReadPlanes );
-
- exit( 0 );
- }
-
- /*****************************************************************************
- *
- * PCXENCODE.C - PCX Image compression interface
- *
- * PCXEncode( FName, GHeight, GWidth, Colors, Red, Green, Blue, GetPlanes )
- *
- *****************************************************************************/
-
- #define TRUE 1
- #define FALSE 0
-
- /* public */
-
- static void
- PCXEncode(fp, GWidth, GHeight, Colors, Red, Green, Blue, GetPlanes )
- FILE* fp;
- int GWidth, GHeight;
- int Colors;
- int Red[], Green[], Blue[];
- vfunptr GetPlanes;
- {
- int BytesPerLine;
- int Planes;
- int BitsPerPixel;
- unsigned char *buf;
- int i;
- int n;
- int y;
-
- /*
- * select number of planes and number of bits
- * per pixel according to number of colors
- */
- /*
- * 16 colors or less are handled as 1 bit per pixel
- * with 1, 2, 3 or 4 color planes.
- * more than 16 colors are handled as 8 bits per pixel
- * with 1 plane
- */
- if (Colors > 16)
- {
- BitsPerPixel = 8;
- Planes = 1;
- }
- else
- {
- BitsPerPixel = 1;
- if (Colors > 8)
- Planes = 4;
- else if (Colors > 4)
- Planes = 3;
- else if (Colors > 2)
- Planes = 2;
- else
- Planes = 1;
- }
-
- /*
- * Write the PCX header
- */
- Putbyte( 0x0a, fp); /* .PCX magic number */
- Putbyte( 0x05, fp); /* PC Paintbrush version */
- Putbyte( 0x01, fp); /* .PCX run length encoding */
- Putbyte( BitsPerPixel, fp); /* bits per pixel */
-
- Putword( 0, fp ); /* x1 - image left */
- Putword( 0, fp ); /* y1 - image top */
- Putword( GWidth-1, fp ); /* x2 - image right */
- Putword( GHeight-1, fp ); /* y2 - image bottom */
-
- Putword( GWidth, fp ); /* horizontal resolution */
- Putword( GHeight, fp ); /* vertical resolution */
-
- /*
- * Write out the Color Map for images with 16 colors or less
- */
- n = (Colors <= 16) ? Colors : 16;
- for (i = 0; i < n; ++i)
- {
- Putbyte( Red[i], fp );
- Putbyte( Green[i], fp );
- Putbyte( Blue[i], fp );
- }
- for (; i < 16; ++i)
- {
- Putbyte( 255, fp );
- Putbyte( 255, fp );
- Putbyte( 255, fp );
- }
-
- Putbyte( 0, fp); /* reserved byte */
-
- Putbyte( Planes, fp); /* number of color planes */
-
- BytesPerLine = ((GWidth * BitsPerPixel) + 7) / 8;
- Putword( BytesPerLine, fp ); /* number of bytes per scanline */
-
- Putword( 1, fp); /* pallette info */
-
- for (i = 0; i < 58; ++i) /* fill to end of header */
- Putbyte( 0, fp );
-
- buf = (unsigned char *)malloc( MAXPLANES * BytesPerLine );
-
- for (y = 0; y < GHeight; ++y)
- {
- (*GetPlanes)(y, GWidth, buf, Planes, BitsPerPixel);
-
- for (i = 0; i < Planes; ++i)
- PutPlane(fp, buf + (i * BytesPerLine), BytesPerLine);
- }
-
- /*
- * color map for > 16 colors is at end of file
- */
- if (Colors > 16)
- {
- Putbyte( 0x0c, fp); /* magic for 256 colors */
- for (i = 0; i < Colors; ++i)
- {
- Putbyte( Red[i], fp );
- Putbyte( Green[i], fp );
- Putbyte( Blue[i], fp );
- }
- for (; i < MAXCOLORS; ++i)
- {
- Putbyte( 255, fp );
- Putbyte( 255, fp );
- Putbyte( 255, fp );
- }
- }
-
- fclose( fp );
- }
-
- static void
- PutPlane(fp, buf, Size)
- FILE *fp;
- unsigned char *buf;
- int Size;
- {
- unsigned char *end;
- int c;
- int previous;
- int count;
-
- end = buf + Size;
-
- previous = *buf++;
- count = 1;
-
- while (buf < end)
- {
- c = *buf++;
- if (c == previous && count < 63)
- {
- ++count;
- continue;
- }
-
- if (count > 1 || (previous & 0xc0) == 0xc0)
- {
- count |= 0xc0;
- Putbyte ( count , fp );
- }
- Putbyte(previous, fp);
- previous = c;
- count = 1;
- }
-
- if (count > 1 || (previous & 0xc0) == 0xc0)
- {
- count |= 0xc0;
- Putbyte ( count , fp );
- }
- Putbyte(previous, fp);
- }
-
- static unsigned long PixMap[8][16] =
- {
- 0x00000000L, 0x00000080L, 0x00008000L, 0x00008080L,
- 0x00800000L, 0x00800080L, 0x00808000L, 0x00808080L,
- 0x80000000L, 0x80000080L, 0x80008000L, 0x80008080L,
- 0x80800000L, 0x80800080L, 0x80808000L, 0x80808080L,
- };
-
- static void
- ReadPlanes(y, width, buf, planes, bits)
- int y;
- int width;
- unsigned char *buf;
- int planes;
- int bits;
- {
- static int first_time = 1;
- unsigned char *plane0, *plane1, *plane2, *plane3;
- int i, j, x;
-
- /*
- * 256 color, 1 plane, 8 bits per pixel
- */
- if (planes == 1 && bits == 8)
- {
- for (x = 0; x < width; ++x)
- buf[x] = ppm_lookupcolor( cht, &pixels[y][x] );
- return;
- }
-
- /*
- * must be 16 colors or less, 4 planes or less, 1 bit per pixel
- */
- if (first_time)
- {
- for (i = 1; i < 8; ++i)
- for (j = 0; j < 16; ++j)
- PixMap[i][j] = PixMap[0][j] >> i;
- first_time = 0;
- }
-
- i = (width + 7) / 8;
-
- plane0 = buf;
- plane1 = plane0 + i;
- plane2 = plane1 + i;
- plane3 = plane2 + i;
-
- i = 0;
- x = 0;
-
- while ( x < width )
- {
- register unsigned long t;
-
- t = PixMap[0][ppm_lookupcolor( cht, &pixels[y][x++] )];
- t |= PixMap[1][ppm_lookupcolor( cht, &pixels[y][x++] )];
- t |= PixMap[2][ppm_lookupcolor( cht, &pixels[y][x++] )];
- t |= PixMap[3][ppm_lookupcolor( cht, &pixels[y][x++] )];
- t |= PixMap[4][ppm_lookupcolor( cht, &pixels[y][x++] )];
- t |= PixMap[5][ppm_lookupcolor( cht, &pixels[y][x++] )];
- t |= PixMap[6][ppm_lookupcolor( cht, &pixels[y][x++] )];
- t |= PixMap[7][ppm_lookupcolor( cht, &pixels[y][x++] )];
-
- plane0[i] = t;
- plane1[i] = t >> 8;
- plane2[i] = t >> 16;
- plane3[i++] = t >> 24;
- }
- }
-
- /*
- * Write out a word to the PCX file
- */
- static void
- Putword( w, fp )
- int w;
- FILE *fp;
- {
- fputc( w & 0xff, fp );
- fputc( (w / 256) & 0xff, fp );
- }
-
- /*
- * Write out a byte to the PCX file
- */
- static void
- Putbyte( b, fp )
- int b;
- FILE *fp;
- {
- fputc( b & 0xff, fp );
- }
-
- /* The End */
-