/* * This software is copyrighted as noted below. It may be freely copied, * modified, and redistributed, provided that the copyright notice is * preserved on all copies. * * There is no warranty or other guarantee of fitness for this software, * it is provided solely "as is". Bug reports or fixes may be sent * to the author, who may or may not act on them as he desires. * * You may not include this software in a program or other software product * without supplying the source, or without informing the end-user that the * source is available for no extra charge. * * If you modify this software, you should include a notice giving the * name of the person performing the modification, the date of modification, * and the reason for such modification. */ /* * pcx.c - interface with Zsoft's PCX format. * * Author: Raul Rivero * Mathematics Dept. * University of Oviedo * Date: Sun Feb 9 1992 * Copyright (c) 1992, Raul Rivero * */ /* * * Raul Rivero - 04/09/94 * * Fixed several bugs into the algorithm which * read < 256 color images. * */ #include #include #define PCX_HEADERSIZE 128 #define PCX_MAGICNUMBER 0x0a #define PCX_256COLORS 0x0c #define PCX_COMPRESS 0xc0 extern int LUGverbose; read_pcx_file( name, bitmap ) char *name; bitmap_hdr *bitmap; { FILE *handle; /* Open the file descriptor */ if ( name != NULL ) handle = Fopen( name, "rb" ); else error( 20 ); /* Read the bitmap */ read_pcx( handle, bitmap ); rm_compress(); /* Close the file */ Fclose( handle ); } read_pcx( handle, image ) FILE *handle; bitmap_hdr *image; { register int i, j, k; byte header[ PCX_HEADERSIZE ]; int bitsperpixel; int xsize, ysize; int xmax, ymax; int xmin, ymin; byte version; int bytesperline; byte *r, *g, *b; byte *buffer; long position; int mask; int paletteinfo; int truecolor = 0; /* * Read the header. */ VPRINTF( stderr, "Reading PCX header\n" ); Fread( header, PCX_HEADERSIZE, 1, handle ); if ( header[0] != PCX_MAGICNUMBER ) /* a PCX file ? */ error( 5 ); /* * Get some data from this header. */ version = header[1]; VPRINTF( stderr, "PCX file version: %d\n", version ); if ( header[2] != 1 ) /* file with PCX RLE encode ? */ error( 9 ); bitsperpixel = ( header[3] == 1 ? header[65] : header[3] ); VPRINTF( stderr, "Bits per pixel: %d\n", bitsperpixel ); xmin = (header[ 5] << 8) | header[ 4]; ymin = (header[ 7] << 8) | header[ 6]; xmax = (header[ 9] << 8) | header[ 8]; ymax = (header[11] << 8) | header[10]; xsize = xmax - xmin + 1; ysize = ymax - ymin + 1; bytesperline = (header[67] << 8) | header[66]; paletteinfo = (header[69] << 8) | header[68]; VPRINTF( stderr, "Bytes per line: %d\n", bytesperline ); VPRINTF( stderr, "Palete info: %d\n", paletteinfo ); /* * Fill our header. */ image->xsize = xsize; image->ysize = ysize; r = image->r = (byte *) Malloc( xsize * ysize ); /* * Cmap info. */ image->magic = LUGUSED; image->depth = bitsperpixel; image->colors = ( 1 << image->depth ); /* * Read the cmap tag. */ if ( version >= 5 && bitsperpixel == 8 ) { /* We could have 256 colors, check it ! */ position = ftell( handle ); fseek( handle, -769L, 2 ); if ( getc( handle ) == PCX_256COLORS ) { /* Really, we have 256 colors */ VPRINTF( stderr, "Reading additional color map\n" ); image->cmap = (byte *) Malloc( 3 * 256 ); Fread( image->cmap, 256, 3, handle ); }else { /* * Wow !, we have a true color image. We need * more memory. */ truecolor = 1; g = image->g = (byte *) Malloc( xsize * ysize ); b = image->b = (byte *) Malloc( xsize * ysize ); image->depth = 24; image->colors = ( 1 << image->depth ); } /* Go back to the original position */ fseek( handle, position, 0 ); }else { /* We have (2**bitsperpixel) colors */ image->cmap = (byte *) Malloc( 3 * image->colors ); if ( bitsperpixel == 1 ) { /* * A monochrome palette isn't stored. Why ???!!!, there is a * reserved space !!!. */ image->cmap[3] = image->cmap[4] = image->cmap[5] = 255; }else { /* * This cmap is stored on header space ( and we have * this header, so we only nedd copy it ). */ bcopy( &(header[16]), image->cmap, 3*image->colors ); } } /* * Read the raster information. */ VPRINTF( stderr, "Unpacking raster information\n"); if ( bitsperpixel > 4 ) { /* * Read a 'normal' image, one byte is one pixel. */ for ( i = 0; i < ysize; i++ ) { decodePCX( handle, r, bytesperline ); r += image->xsize; if ( truecolor ) { decodePCX( handle, g, bytesperline ); g += image->xsize; decodePCX( handle, b, bytesperline ); b += image->xsize; } } }else { byte *ptrplane; int totalbytes = bytesperline * bitsperpixel; /* * The image was built by planes, so we need * join all planes ( arrggg ! ). */ buffer = (byte *) Malloc( totalbytes ); for ( i = 0; i < ysize; i++ ) { decodePCX( handle, buffer, totalbytes ); ptrplane = buffer; for ( j = 0; j < bitsperpixel; j++ ) { /* * Glue planes. */ mask = 1 << j; for ( k = 0; k < xsize; k++ ) { if ( ptrplane[ k >> 3 ] & (0x80 >> (k & 0x0007 )) ) r[ k ] |= mask; } /* Move the pointer to the next plane */ ptrplane += bytesperline; } r += image->xsize; } Free( buffer ); } } decodePCX( handle, buffer, linesize ) FILE *handle; byte *buffer; int linesize; { int cin; int count; while ( linesize > 0 ) { cin = getc( handle ); if ( (cin & PCX_COMPRESS) == PCX_COMPRESS ) { /* A block compressed */ count = cin & 0x3f; /* 00111111 */ if ( count > linesize ) error( 6 ); /* Get the real data to copy */ cin = getc( handle ); memset( buffer, cin, count ); /* Update pointers */ linesize -= count; buffer += count; }else { /* Only one data */ *buffer++ = cin; linesize--; } } } write_pcx_file( name, image ) char *name; bitmap_hdr *image; { FILE *handle; /* Open the file descriptor */ if ( name != NULL ) handle = Fopen( name, "wb" ); else handle = stdout; /* Write the bitmap */ write_pcx( handle, image ); /* Close the file */ Fclose( handle ); } write_pcx( handle, image ) FILE *handle; bitmap_hdr *image; { register int i; byte *raster; if ( image->magic != LUGUSED ) error( 19 ); if ( image->depth > 8 ) error( 15 ); write_pcx_header( handle, image->xsize, image->ysize ); raster = image->r; for ( i = 0; i < image->ysize; i++ ) { encodePCX( handle, raster, image->xsize ); raster += image->xsize; } write_pcx_cmap( handle, image->colors, image->cmap ); } write_pcx_header( handle, xsize, ysize ) FILE *handle; int xsize, ysize; { byte header[PCX_HEADERSIZE]; bzero( header, PCX_HEADERSIZE ); /* * We always write an image with 256 colors. I'm soory * but it's more easy ( and, ... a image with less than * 256 colors, what is it ? ). */ /* * Fill the PCX header. */ header[ 0] = PCX_MAGICNUMBER; header[ 1] = 0x05; /* version 3.0 */ header[ 2] = 0x01; /* PCX RLE encode */ header[ 3] = 0x08; /* eight bytes per pixel */ /* Image left */ header[ 4] = 0; header[ 5] = 0; /* Image top */ header[ 6] = 0; header[ 7] = 0; /* Image right */ header[ 8] = LSB( xsize - 1 ); header[ 9] = MSB( xsize - 1 ); /* Image bottom */ header[10] = LSB( ysize - 1 ); header[11] = MSB( ysize - 1 ); /* Screen width */ header[12] = LSB( xsize ); header[13] = MSB( xsize ); /* Screen bottom */ header[14] = LSB( ysize ); header[15] = MSB( ysize ); header[65] = 1; /* one plane */ /* Bytes per line */ header[66] = LSB( xsize ); header[67] = MSB( xsize ); /* Interpret palette as color/bw */ header[68] = 0x01; header[69] = 0; Fwrite( header, PCX_HEADERSIZE, 1, handle ); } write_pcx_cmap( handle, colors, cmap ) FILE *handle; int colors; byte *cmap; { byte auxcmap[ 3*256 ]; bzero( auxcmap, 3*256 ); bcopy( cmap, auxcmap, 3*colors ); /* 256 colors signature */ fputc( PCX_256COLORS, handle ); Fwrite( auxcmap, 256, 3, handle ); } encodePCX( handle, buffer, size ) FILE *handle; byte *buffer; int size; { int count = 1; byte *end, *ptr; byte out[2560]; int current, new; ptr = out; current = *buffer++; end = buffer + size; while ( buffer < end ) { new = *buffer++; while ( current == new && count < 63 && buffer < end ) { count++; new = *buffer++; } if ( count > 1 || ( current & PCX_COMPRESS ) == PCX_COMPRESS ) *ptr++ = count | PCX_COMPRESS; *ptr++ = current; count = 1; current = new; } count = ptr - out; Fwrite( out, count, 1, handle ); }