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
/
ppmtopcx.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-11-18
|
12KB
|
443 lines
/* ppmtopcx.c - convert a portable pixmap to PCX
**
** Copyright (C) 1994 by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
** based on ppmtopcx.c 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.
**
** 11/Dec/94: first version
** 12/Dec/94: added support for "packed" format (16 colors or less)
*/
#include "ppm.h"
#include "ppmcmap.h"
/*#define DEBUG*/
#define MAXCOLORS 256
#define PCX_MAGIC 0x0a /* PCX magic number */
#define PCX_256_COLORS 0x0c /* magic number for 256 colors */
#define PCX_MAXVAL (pixval)255
/* prototypes */
static void ppm_to_16col_pcx ARGS((pixel **pixels, int cols, int rows,
pixel *cmap, int colors, colorhash_table cht));
static void ppm_to_256col_pcx ARGS((pixel **pixels, int cols, int rows,
pixel *cmap, int colors, colorhash_table cht));
static void ppm_to_truecol_pcx ARGS((pixel **pixels, int cols, int rows, int maxval));
static void write_header ARGS((FILE *fp, int cols, int rows, int BitsPerPixel, int Planes, pixel *cmap16));
static void PCXEncode ARGS(( FILE* fp, unsigned char* buf, int Size ));
static void ToPlanes ARGS((unsigned char *rawrow, int width, unsigned char *buf, int planes));
static void PackBits ARGS((unsigned char *rawrow, int width, unsigned char *buf, int bits));
static void Putword ARGS(( int w, FILE* fp ));
static void Putbyte ARGS(( int b, FILE* fp ));
static short force24 = 0;
static short packbits = 0;
int
main( argc, argv )
int argc;
char* argv[];
{
FILE* ifp;
int argn, rows, cols, colors, i;
pixval maxval;
pixel black_pixel, *cmap, **pixels;
colorhist_vector chv;
colorhash_table cht;
char* usage = "[-24bit] [-packed] [ppmfile]";
ppm_init(&argc, argv);
argn = 1;
while( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) {
if( pm_keymatch(argv[argn], "-24bit", 3) )
force24 = 1;
else
if( pm_keymatch(argv[argn], "-packed", 2) )
packbits = 1;
else
pm_usage(usage);
++argn;
}
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 );
if( !force24 ) {
/* Figure out the colormap. */
pm_message( "computing colormap..." );
chv = ppm_computecolorhist( pixels, cols, rows, MAXCOLORS, &colors );
if ( chv == (colorhist_vector) 0 ) {
pm_message("too many colors - writing a 24bit PCX file");
pm_message("if you want a non-24bit file, do a \'ppmquant %d\'", MAXCOLORS);
force24 = 1;
}
}
if( maxval != PCX_MAXVAL )
pm_message("maxval is not %d - automatically rescaling colors", PCX_MAXVAL);
if( force24 )
ppm_to_truecol_pcx(pixels, cols, rows, maxval);
else {
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 );
/* build colormap */
cmap = ppm_allocrow(MAXCOLORS);
for( i = 0; i < colors; i++ ) {
pixval r, g, b;
r = PPM_GETR(chv[i].color); g = PPM_GETG(chv[i].color); b = PPM_GETB(chv[i].color);
if( maxval != PCX_MAXVAL ) {
r = r * PCX_MAXVAL / maxval; g = g * PCX_MAXVAL / maxval; b = b * PCX_MAXVAL / maxval;
}
PPM_ASSIGN(cmap[i], r, g, b);
}
for( ; i < MAXCOLORS; i++ )
PPM_ASSIGN(cmap[i], 0,0,0);
/* make a hash table for fast color lookup */
cht = ppm_colorhisttocolorhash(chv, colors);
ppm_freecolorhist( chv );
/* convert image */
if( colors <= 16 )
ppm_to_16col_pcx(pixels, cols, rows, cmap, colors, cht);
else
ppm_to_256col_pcx(pixels, cols, rows, cmap, colors, cht);
}
exit(0);
}
static void
ppm_to_16col_pcx(pixels, cols, rows, cmap, colors, cht)
pixel **pixels;
int cols, rows;
pixel *cmap;
int colors;
colorhash_table cht;
{
int Planes, BytesPerLine, BitsPerPixel;
unsigned char *rawrow, *planesrow;
register int col, row;
#ifdef DEBUG
pm_message("ppm -> %d colors", colors);
#endif
if( packbits ) {
Planes = 1;
if( colors > 4 ) BitsPerPixel = 4;
else if( colors > 2 ) BitsPerPixel = 2;
else BitsPerPixel = 1;
}
else {
BitsPerPixel = 1;
if( colors > 8 ) Planes = 4;
else if( colors > 4 ) Planes = 3;
else if( colors > 2 ) Planes = 2;
else Planes = 1;
}
BytesPerLine = ((cols * BitsPerPixel) + 7) / 8;
rawrow = (unsigned char *)pm_allocrow(cols, sizeof(unsigned char));
planesrow = (unsigned char *)pm_allocrow(BytesPerLine, sizeof(unsigned char));
#ifdef DEBUG
pm_message("Planes = %d, BitsPerPixel = %d, BytesPerLine = %d",
Planes, BitsPerPixel, BytesPerLine);
#endif
write_header(stdout, cols, rows, BitsPerPixel, Planes, cmap);
for( row = 0; row < rows; row++ ) {
register pixel *pP = pixels[row];
for( col = 0; col < cols; col++, pP++ )
rawrow[col] = (unsigned char)ppm_lookupcolor(cht, pP) & 0x0f;
if( packbits ) {
PackBits(rawrow, cols, planesrow, BitsPerPixel);
PCXEncode(stdout, planesrow, BytesPerLine);
}
else {
for( col = 0; col < Planes; col++ ) {
ToPlanes(rawrow, cols, planesrow, col);
PCXEncode(stdout, planesrow, BytesPerLine);
}
}
}
#ifdef DEBUG
pm_message("done!");
#endif
pm_freerow(planesrow);
pm_freerow(rawrow);
}
static void
ppm_to_256col_pcx(pixels, cols, rows, cmap, colors, cht)
pixel **pixels;
int cols, rows;
pixel *cmap;
int colors;
colorhash_table cht;
{
register int col, row, i;
unsigned char *rawrow;
#ifdef DEBUG
pm_message("ppm -> 256 color, writing index array...");
#endif
rawrow = (unsigned char *)pm_allocrow(cols, sizeof(unsigned char));
/* 8 bits per pixel, 1 plane */
write_header(stdout, cols, rows, 8, 1, (pixel *)NULL);
for( row = 0; row < rows; row++ ) {
register pixel *pP = pixels[row];
for( col = 0; col < cols; col++, pP++ )
rawrow[col] = ppm_lookupcolor(cht, pP);
PCXEncode(stdout, rawrow, cols);
}
#ifdef DEBUG
pm_message("ok, writing colormap...");
#endif
Putbyte(PCX_256_COLORS, stdout);
for( i = 0; i < MAXCOLORS; i++ ) {
Putbyte(PPM_GETR(cmap[i]), stdout);
Putbyte(PPM_GETG(cmap[i]), stdout);
Putbyte(PPM_GETB(cmap[i]), stdout);
}
#ifdef DEBUG
pm_message("done!");
#endif
pm_freerow(rawrow);
}
static void
ppm_to_truecol_pcx(pixels, cols, rows, maxval)
pixel **pixels;
int cols, rows, maxval;
{
unsigned char *redrow, *greenrow, *bluerow;
register int col, row;
#ifdef DEBUG
pm_message("ppm -> 24bit");
#endif
redrow = (unsigned char *)pm_allocrow(cols, sizeof(unsigned char));
greenrow = (unsigned char *)pm_allocrow(cols, sizeof(unsigned char));
bluerow = (unsigned char *)pm_allocrow(cols, sizeof(unsigned char));
/* 8 bits per pixel, 3 planes */
write_header(stdout, cols, rows, 8, 3, (pixel *)NULL);
for( row = 0; row < rows; row++ ) {
register pixel *pP = pixels[row];
for( col = 0; col < cols; col++, pP++ ) {
if( maxval != PCX_MAXVAL ) {
redrow[col] = (long)PPM_GETR(*pP) * PCX_MAXVAL / maxval;
greenrow[col] = (long)PPM_GETG(*pP) * PCX_MAXVAL / maxval;
bluerow[col] = (long)PPM_GETB(*pP) * PCX_MAXVAL / maxval;
}
else {
redrow[col] = PPM_GETR(*pP);
greenrow[col] = PPM_GETG(*pP);
bluerow[col] = PPM_GETB(*pP);
}
}
PCXEncode(stdout, redrow, cols);
PCXEncode(stdout, greenrow, cols);
PCXEncode(stdout, bluerow, cols);
}
#ifdef DEBUG
pm_message("done!");
#endif
pm_freerow(bluerow);
pm_freerow(greenrow);
pm_freerow(redrow);
}
static void
write_header(fp, cols, rows, BitsPerPixel, Planes, cmap16)
FILE *fp;
int cols, rows;
int BitsPerPixel, Planes;
pixel *cmap16;
{
int i, BytesPerLine;
Putbyte( PCX_MAGIC, 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( cols-1, fp ); /* x2 - image right */
Putword( rows-1, fp ); /* y2 - image bottom */
Putword( cols, fp ); /* horizontal resolution */
Putword( rows, fp ); /* vertical resolution */
/* Write out the Color Map for images with 16 colors or less */
if( cmap16 )
for (i = 0; i < 16; ++i) {
Putbyte( PPM_GETR(cmap16[i]), fp );
Putbyte( PPM_GETG(cmap16[i]), fp );
Putbyte( PPM_GETB(cmap16[i]), fp );
}
else
for (i = 0; i < 16; ++i) {
Putbyte( 0, fp );
Putbyte( 0, fp );
Putbyte( 0, fp );
}
Putbyte( 0, fp); /* reserved byte */
Putbyte( Planes, fp); /* number of color planes */
BytesPerLine = ((cols * 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 );
}
static void
PCXEncode(fp, buf, Size)
FILE *fp;
unsigned char *buf;
int Size;
{
unsigned char *end;
int c, previous, 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 void
PackBits(rawrow, width, buf, bits)
unsigned char *rawrow;
int width;
unsigned char *buf;
int bits;
{
register int x, i, shift;
shift = i = -1;
for( x = 0; x < width; x++ ) {
if( shift < 0 ) {
shift = 8-bits;
buf[++i] = 0;
}
buf[i] |= (rawrow[x] << shift);
shift -= bits;
}
}
static const unsigned char bitmask[] = {1, 2, 4, 8, 16, 32, 64, 128};
static void
ToPlanes(rawrow, width, buf, plane)
unsigned char *rawrow;
int width;
unsigned char *buf;
int plane;
{
int cbit, x, mask;
unsigned char *cp = buf-1;
mask = 1 << plane;
cbit = -1;
for( x = 0; x < width; x++ ) {
if( cbit < 0 ) {
cbit = 7;
*++cp = 0;
}
if( rawrow[x] & mask )
*cp |= bitmask[cbit];
--cbit;
}
}
/*
* Write out a word to the PCX file
*/
static void
Putword( w, fp )
int w;
FILE *fp;
{
Putbyte( w & 0xff, fp );
Putbyte( (w / 256) & 0xff, fp );
}
/*
* Write out a byte to the PCX file
*/
static void
Putbyte( b, fp )
int b;
FILE *fp;
{
if( fputc( b & 0xff, fp ) == EOF )
pm_error("write error");
}