home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Resource Library: Graphics
/
graphics-16000.iso
/
general
/
convrtrs
/
pbmplus
/
ntpbmsrc.lha
/
netpbm
/
ppm
/
ppmtopcx.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-10-04
|
9KB
|
382 lines
/* 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 */