/* %kw # %v %n %d %t # */ /* Version # 1 PCXREMAP.C 7-Jan-94 18:26:50 # */ /* ************************************************** */ /* METAGRAPHICS SOFTWARE CORPORATION (c) 1993 */ /* Demonstrates use of incremental PCX operations */ /* to map reserved colors in a file to the closest */ /* other non-reserved colors */ /* Functions: OpenPCX(), NextPCX(), ClosePCX() */ /* XlateImage() */ /* ************************************************** */ #include #include #include #include #include #include #include "metawndo.h" /* master MetaWINDOW include file */ #include "pcxlab.h" /* PCX lab include file */ /* special stack size declaration if using Turbo or Borland C++ */ #ifdef TurboC extern unsigned _stklen = 14336U; /* stack size 14K */ #endif /* global vaiables */ int GrafixCard,GrafixInput; /* function prototype */ long FindClosestRGB( palData targetRGB, palData *RGBsource ); int XlatePCX( char *filename, long *xltable ); void main( int argc, char *argv[] ) { int i; rect scrnR; pcxHead pcxHeader; /* buffer for reading the files PCX header */ palData RGBInfo[256]; /* buffer for reading the files palette */ long xTable[256]; /* color translation table */ palData RsvdRGBInfo[16]; /* buffer for holding reserved RGB values */ /* check for a file name on the command line */ if( argc < 2 ) { printf("PCXXLATE - Read and translate PCX file\n"); printf("Usage: PCXXLATE filename\n"); exit(10); } /* let user select display type */ MetQuery(argc,argv); /* init the system */ i = InitGraphics( GrafixCard ); if( i != 0 ) { printf("MetaWINDOW Initialization error #%d\n", i); exit(1); } /* read header information */ i = ReadPCXInfo( argv[1], &pcxHeader, RGBInfo ); if( i == 0) { printf("%s is not a valid pcx file\n", argv[1] ); StopGraphics(); exit(2); /* not a valid pcx file */ } /* put into graphics mode */ SetDisplay( GrafPg0 ); /* clear the screen */ ScreenRect( &scrnR ); EraseRect( &scrnR ); /* draw something in the reserved colors */ MoveTo( 10, scrnR.Ymax - 50 ); for( i = 0; i < 16; i++ ) { PenColor( i ); DrawChar( 'A' + i ); } scrnR.Ymax -= 100; ClipRect( &scrnR ); /* now generate a translation table to re-map those colors in the PCX file that are in reserved locations to other locations */ /* record the pcx palette entries that are in reserved locations */ for( i = 0; i < 16; i++ ) RsvdRGBInfo[i] = RGBInfo[i]; /* replace the reserved palette data with the current palette settings */ ReadPalette( 0, 0, 15, RGBInfo ); /* set palette, based on palette in PCX file */ WritePalette( 0, 0, (int) QueryColors(), RGBInfo ); // start with a 1:1 translaton table for( i = 0; i < 256; i ++ ) xTable[i] = (long) i; /* translate the reserved colors of the pcx file to others in the current displays palette */ for( i = 0; i < 16; i++ ) xTable[i] = FindClosestRGB( RsvdRGBInfo[i], RGBInfo ); /* read it in */ i = XlatePCX( argv[1], xTable ); /* wait for a key press */ getch(); /* switch back to text mode*/ SetDisplay( TextPg0 ); /* display any error messages */ switch( i ) { case 1: /* file read correctly */ break; case -1: printf("%s is not a valid pcx file\n", argv[1] ); break; case -2: printf("can't allocate image buffer\n"); break; case -3: printf("can't allocate translation buffer\n"); break; default: printf("error reading PCX file\n"); break; } StopGraphics(); i = QueryError(); printf("QueryError=%d/%d\n",i >> 7,i & 127); exit(i); } /* XlatePCX: read and translate a pcx file to be compatible with current display Returns; 1 = file read correctly 0 = error reading PCX file -1 = not a valid pcx file -2 = can't allocate image buffer -3 = can't allocate translation buffer */ int XlatePCX( char *filename, long *xltable ) { int i, height,y; pcxHead pcxHeader; /* buffer for reading the files PCX header */ unsigned imsize; /* size of required image buffer */ image *srcImage; /* pointer to allocated source image buffer*/ image *dstImage; /* pointer to allocated dest image buffer */ grafPort *myport; /* pointer to current port */ rect dstR; /* rectangle used to WriteImage() raster */ /* Open the PCX File and read header information */ imsize = OpenPCX( filename, &pcxHeader, NULL ); if( imsize == 0) return -1; /* not a valid pcx file */ GetPort( &myport ); /* file needs to be color translated */ /* each raster will be processed individually */ /* allocate an image buffer large enough for one raster of the pcx file */ srcImage = malloc( imsize ); if( srcImage == NULL ) { ClosePCX( &pcxHeader ); return -2; /* can't allocate */ } /* calculate a translation image buffer size based on source image */ /* get a 'taste' of the pcx files image format */ NextPCX( &pcxHeader, srcImage ); imsize = (unsigned) XlateImage( srcImage, NULL, myport->portMap->pixBits, myport->portMap->pixPlanes, NULL ); dstImage = malloc( imsize ); if( dstImage == NULL ) { free( srcImage ); ClosePCX( &pcxHeader ); return -3; /* can't allocate */ } /* reset file to beginning */ ClosePCX( &pcxHeader ); OpenPCX( filename, &pcxHeader, NULL ); /* set up a rectangle for the destination WriteImage() */ ScreenRect( &dstR ); dstR.Ymax = dstR.Ymin + 1; /* compute number of rasters in the pcx file */ height = pcxHeader.pcxWndo.Ymax - pcxHeader.pcxWndo.Ymin + 1; /* process each pcx file raster individually */ for( y = 0; y < height; y++ ) { /* read next raster into an image buffer */ i = NextPCX( &pcxHeader, srcImage ); if( i == False ) { ClosePCX( &pcxHeader ); free( srcImage ); free( dstImage ); return 0; /* error reading */ } /* translate the image to destination format */ XlateImage( srcImage, dstImage, myport->portMap->pixBits, myport->portMap->pixPlanes, xltable ); /* put the translated image on the current bitmap */ WriteImage( &dstR, dstImage ); /* advance destination rectangle to next raster*/ OffsetRect( &dstR, 0, 1 ); } /* for Y */ /* close the PCX file opened via OpenPCX */ ClosePCX( &pcxHeader ); /* free the image buffers */ free( srcImage ); free( dstImage ); return 1; } long FindClosestRGB( palData targetRGB, palData *RGBsource ) /* Use the Pythagorean distance formula to compute the closest value in the RGBsource array to the targetRGB value */ { unsigned long l, diffSq, nearestSq; int i, r,g,b, j, maxclr, nearestNdx; /* scale components down to 8 bit values */ r = targetRGB.palRed >> 8; g = targetRGB.palGreen >> 8; b = targetRGB.palBlue >> 8; /* hunt for nearest squared difference in array */ maxclr = (int) QueryColors(); nearestSq = 0xFFFFFFFFL; for( i = 0; i <= maxclr; i++ ) { /* sum the squares of the difference between each component */ j = RGBsource[i].palRed >> 8; j = abs( r - j ); l = (long) j; diffSq = l * l; j = RGBsource[i].palGreen >> 8; j = abs( g - j ); l = (long) j; diffSq += l * l; j = RGBsource[i].palBlue >> 8; j = abs( b - j ); l = (long) j; diffSq += l * l; /* record the smallest squared difference */ if( diffSq < nearestSq ) { nearestSq = diffSq; nearestNdx = i; } } return nearestNdx; } #include "metquery.c"