Example Pictor Decoder
From Wikipedia, the free encyclopedia
This page is a candidate to be copied to Wikibooks using the Import process. If the page can be re-written into an encyclopedic article, please do so and remove this message. Before you move this content to Wikibooks, verify that it conforms to Wikibooks policies of acceptable content at What is Wikibooks? Often content unacceptable to Wikipedia may not be acceptable on Wikibooks either; facilitate the copying of this article by listing it on Wikibooks:Requests for Import. |
[edit] Pictor PCPaint PIC image format
PICtor is an image file format developed by John Bridges, the principal author of PCPaint, the first Paintbrush program for the PC. It was also the native file format for Pictor Paint and GRASP (multimedia authoring software) (also by Bridges) and became the first widely accepted DOS imaging standard.
The PICtor format is quite well documented, but lacks a programming example like the one below.
[edit] Typical Pictor Decoder
// This source code is herewith released by me into the Public Domain. // Bill Buckels, May 21, 2007 // You have a royalty-free right to use, modify, reproduce and distribute this // source code and the binaries that it produces in any way you find useful // this decoder is only a portion of the actual code required to // display a Pictor PIC. // It is based on the Pseudo-Code in the Pictor PC Paint File Format Summary // http://www.fileformat.info/format/pictor/ // Reading of header information etc. is outside of here. // The maximum display size in this particular example is 640 x 400 // Decoded Data is translated to 8bpp during the decoding term // Doing so highly simplifies color translation. // The usual amount of fiddling with data outside of here may not be // entirely clear to someone who has never written an image loader. // Other than that, reading this example in addition to the Pseudo-Code // should clarify what John Bridges wrote. // Any display considerations would be exactly the same, whether we // were decoding Pictor PIC, a PCX or whatever if we were translating from // older native modes to a GUI display. 'Nuff said. // The code below works for monochrome, 2 bit CGA, 4 bit EGA, and 8 bit MCGA // I am assuming a 32 bit Windows platform with a BOOL and a TRUE and a FALSE // no hardship to compile this in 'nix tho' #define PICTOR_Int unsigned short // for 32 bit Windows #define SUCCESS 0 #define FAILURE -1 unsigned char *picBlockBuf=NULL; unsigned char *picScreenBuf=NULL; int UnpackPictorData(FILE *fpPictor, int *scale, BOOL *spread) { // this routine uses a triple buffer method before handing-off to our // standard MCGA image loader. // 1. The block buffer expands the encoded data to raw data specific to the native mode. // - for 4 plane EGA images this is a contiguous block of monochrome data. // - for single plane images (all the other images that we handle), the bytes are stored // similarly to a windows BMP in their respective packed pixel format which contains // the color indices according to bit depths. Unlike the windows BMP these blocks // are not padded on scanline boundaries to a DWORD value (thank goodness). // 2. After unpacking each block, the block buffer is expanded into an 1 byte per pixel // contiguous buffer. Each subsequent block unpacks at the offset where the previous // block left-off. // - for single plane images this results in a buffer of width x height x 1 byte per pixel // - for 4 plane EGA images this results in a quadruple buffer width x height x 1 byte x 4, // with the entire image of each of the 4 planes' monochrome pixels repeated once // for each plane. // 3. If the image is a 4 plane EGA it is then given an extra massage, and the planes are // combined and expanded to an EGA indices into a width x height x 1 byte per pixel. // 4. By that time all pixels are 8 bit values and according to how we will be // positioning and scaling the image for display in our standard MCGA mode routines // the image is prepared for display by moving into position in the rawbuffer. // 5. The image is still upside-down but will be flipped, and CGA Mode monochrome images // will be corrected for aspect before final display by the standard MCGA loader. unsigned char buf[256], RunValue; PICBLOCKHEADER h; int c, status = FAILURE; unsigned width; unsigned long offset, y, yoff, ymax, x, xoff, xmax, ystart, realx; unsigned long bufx, bufy, target; unsigned char backcolor = 0; PICTOR_Int byteCount, byteRunLength, blockCount, idx; status = SUCCESS; blockCount = 0; if (NULL!=picBlockBuf) { free(picBlockBuf); picBlockBuf = NULL; } if (NULL!=picScreenBuf) { free(picScreenBuf); picScreenBuf = NULL; } offset = 0; realx = (unsigned long)Pictor_head.xsize; // put other exceptions here or allow for uneven boundaries switch(Pictor_head.pictortype) { case Pictor_MONO: while (Pictor_head.xsize%8 != 0)Pictor_head.xsize++; break; case Pictor_CGA: while (Pictor_head.xsize%4 != 0)Pictor_head.xsize++; break; case Pictor_EGA1: while (Pictor_head.xsize%2 != 0)Pictor_head.xsize++; break; case Pictor_EGA4: while (Pictor_head.xsize%8 != 0)Pictor_head.xsize++; break; case Pictor_VGA: break; // never a problem with these } bufx = (unsigned long)Pictor_head.xsize; bufy = (unsigned long)Pictor_head.ysize; target = bufx; target *= bufy; target *= (unsigned long) Pictor_head.planes; // safety picScreenBuf = malloc(target + 640); if (NULL == picScreenBuf)return FAILURE; // set-up complete // start unpacking here StartOfDataBlock: if (NULL != picBlockBuf) { // unpack the block segment into the raster-aligned 8 bit screen buffer // by now we have ended-up with contiguous data in the block // that can be unpacked 1 pixel at a time for each plane of color data width = (unsigned)Pictor_head.pixeldivisor; width *= (unsigned)h.RunLength; // safety play if ((offset + width) > target) width = (unsigned)target - offset; // we are handling specific formats only // everything is expanded from the picBlockBuf to 8bpp into the picScreenBuf switch(Pictor_head.pictortype) { case Pictor_MONO: Mono2Svga(picBlockBuf,(unsigned char *)&picScreenBuf[offset],(unsigned)h.RunLength); break; case Pictor_CGA: Cga2Svga(picBlockBuf,(unsigned char *)&picScreenBuf[offset],(unsigned)h.RunLength); break; case Pictor_EGA1: Vga2Svga(picBlockBuf,(unsigned char *)&picScreenBuf[offset],(unsigned)h.RunLength); break; case Pictor_EGA4: Mono2Svga(picBlockBuf,(unsigned char *)&picScreenBuf[offset],(unsigned)h.RunLength); break; case Pictor_VGA: memcpy((unsigned char *)&picScreenBuf[offset], picBlockBuf,(unsigned)h.RunLength); break; } width = (unsigned)Pictor_head.pixeldivisor; width *= (unsigned)h.RunLength; offset += width; blockCount += 1; // free the last block we used after putting the pixels into the 8 bit buffer free(picBlockBuf); picBlockBuf = NULL; } // safety plays if (offset > target)goto EndOfRead; // done if (Pictor_head.numblocks == blockCount || Pictor_head.numblocks < blockCount) goto EndOfRead; // done memset(&h,0,sizeof(PICBLOCKHEADER)); // Read BlockSize value from data block header // Read RunLength value from data block header // Read RunMarker value from data block header if (1 != fread(buf,5,1,fpPictor))goto EndOfRead; // done h.BlockSize = Shorty((unsigned char *)&buf[0]); h.RunLength = Shorty((unsigned char *)&buf[2]); h.RunMarker = buf[4]; /* Start-of-run indicator */ byteCount = 0; if (h.RunLength == 0 || h.BlockSize == 0) { goto EndOfRead; // something is wrong } picBlockBuf = malloc((unsigned)h.RunLength); if (NULL == picBlockBuf)goto EndOfRead; StartOfRun: if ((c = fgetc(fpPictor))==EOF)goto EndOfRead; // done RunValue = (unsigned char)c; // If the byte is a RunMarker if (RunValue == h.RunMarker) { if ((c = fgetc(fpPictor))==EOF)goto EndOfRead; // done byteRunLength = (PICTOR_Int)c; // If the byte following the RunMarker is not 0 it is the the ByteRunLength if (byteRunLength !=0) { // Read this byte as the ByteRunLength // Read the next byte as the RunValue if ((c = fgetc(fpPictor))==EOF)goto EndOfRead; // done // Write the RunValue `RunLength' times. RunValue = (unsigned char)c; for (idx = 0; idx < byteRunLength; idx++) { picBlockBuf[byteCount] = RunValue; byteCount += 1; if (byteCount < h.RunLength)continue; break; } } // If the byte following the RunMarker is 0 else { // Read the next word as the ByteRunLength // Read the next byte as the RunValue if (1 != fread(buf,2,1,fpPictor))goto EndOfRead; // done byteRunLength = Shorty((unsigned char *)&buf[0]); if ((c = fgetc(fpPictor))==EOF)goto EndOfRead; // done // Write the RunValue `RunLength' times. RunValue = (unsigned char)c; for (idx = 0; idx < byteRunLength; idx++) { picBlockBuf[byteCount] = RunValue; byteCount += 1; if (byteCount < h.RunLength)continue; break; } } } else { // If the byte following the header is not a RunMarker // Write the byte as a literal RunValue picBlockBuf[byteCount] = RunValue; byteCount += 1; } // now check the byte count // If the number of bytes written so far does not equal the RunLength if (byteCount < h.RunLength) goto StartOfRun; // If the number of bytes written so far equals the RunLength goto StartOfDataBlock; EndOfRead: if (NULL!=picBlockBuf) { free(picBlockBuf); picBlockBuf = NULL; } // clear the background with something that makes sense // subject to fine-tuning switch(Pictor_head.pictortype) { case Pictor_MONO: if (picScreenBuf[0] == 0)backcolor = 1; else backcolor = 0; break; case Pictor_CGA: if (picScreenBuf[0] == 3)backcolor = 0; else backcolor = 3; break; case Pictor_EGA1: case Pictor_EGA4: backcolor = 0xf; break; case Pictor_VGA: backcolor = 0xff; break; } for (y = 0; y < 400; y++) memset(&rawbuffer[y*640], backcolor, 640); // planar EGA's have been expanded to 4 times the buffered size of a single plane image // these are now stored like a mono image and must be consolidated into an EGA value // and then repacked as an 8 bit indices at the start of the buffer if (Pictor_head.pictortype == Pictor_EGA4) { unsigned char c0,c1,c2,c3; unsigned long offset1, offset2, offset3; // combine the 4 bit planes into an MCGA byte and use the normal routines from here offset = 0; offset1 = bufx * bufy; offset2 = offset1 * 2; offset3 = offset1 * 3; for (y = 0; y < bufy; y++) { for (x = 0; x < bufx; x++) { c0 = picScreenBuf[offset]; c1 = picScreenBuf[offset1]; c2 = picScreenBuf[offset2]; c3 = picScreenBuf[offset3]; picScreenBuf[offset] = ((c3<<3) | (c2<<2) | (c1<<1) | c0); offset++; offset1++; offset2++; offset3++; } } } // move the pictor image into the rawbuffer switch(scale[0]) { case 1: spread[0] = FALSE; yoff = (long) 200 - Pictor_head.ysize; yoff = (yoff/2); xoff = (long) 320 - Pictor_head.xsize; xoff = (xoff/2); ystart = 0; xmax = 320; ymax = 200; break; case 2: default: if (spread[0] == TRUE && Pictor_head.ysize < 201) { yoff = (long) 200 - Pictor_head.ysize; yoff = (yoff/2); ystart = 0; } else { spread[0] = FALSE; if (Pictor_head.ysize > 400) { yoff = 0; ystart = bufy - 400; } else { yoff = (long) 400 - Pictor_head.ysize; yoff = (yoff/2); ystart = 0; } } xoff = (long) 640 - Pictor_head.xsize; xoff = (xoff/2); xmax = 640; ymax = 400; break; } for (y = ystart; y < bufy; y++, yoff++) { offset = y * bufx; target = (yoff * xmax) + xoff; for (x = 0; x < bufx; x++) { rawbuffer[target] = picScreenBuf[offset]; offset++; target++; } } if (Pictor_head.pictortype == Pictor_MONO || Pictor_head.pictortype == Pictor_CGA) { // remap CGA and Mono to VGA 16 Color Order Now offset = 0; for (y = 0; y < 400; y++) { for (x = 0; x < 640; x++) { switch(rawbuffer[offset]) { case 1: if (Pictor_head.pictortype == Pictor_MONO) rawbuffer[offset] = BWHITE; else rawbuffer[offset] = BLUE; break; case 2: rawbuffer[offset] = RED; break; case 3: rawbuffer[offset] = BWHITE; break; } offset++; } } } if (NULL != picScreenBuf)free(picScreenBuf); picScreenBuf = NULL; return SUCCESS; }
[edit] References
Encyclopedia of Graphics File Formats, 2nd Edition by Murray, James D. , Van Ryper, William ISBN: 1-56592-161-5 http://www.fileformat.info/resource/book/1565921615/index.htm
Pictor PC Paint File Format Summary http://www.fileformat.info/format/pictor/
GRASP File Format Summary http://www.fileformat.info/format/grasp/
GLPRO http://en.wikipedia.org/wiki/GLPro
PCPAINT/Pictor Page Format Description Format by John Bridges. Document by Microtex Industries, Inc. Revision Date: 2/9/88 http://netghost.narod.ru/gff/vendspec/pictor/pictor.txt
The Graphics File Formats Page GL - Another animation format Dr. Martin Reddy Technical Lead, R & D, Pixar Animation Studios http://www.martinreddy.net/gfx/2d/GL.txt
The formats of GRASP animation files By George Phillips http://www.programmersheaven.com/download/2157/Zipfilelist.aspx