Example Pictor Encoder
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 Encoder
// 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 is a highly simplified run length encoder for encoding a raw image block // of up to 8 bit pixel depth into an encoded block for a Pictor File. // if the buffer contains all 256 ascii values the LEAST used byte is used for a marker. // Note also, if you are encoding a planar image such as an ega 4 plane // image, each bit plane must be split into 4 separate contiguous blocks // of monochrome data (sometimes referred to a "SEGMENTS") of the height and width // of the image that you are encoding before encoding takes place (below). // This is done outside of here. // 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 int WritePictorBlock(unsigned char *buf, unsigned buflen, FILE *fp) { unsigned idx, jdx, writecnt = 0, offset = 1, runcnt = 1, markerbuf[256]; unsigned char markertest, RunMarker, lastbyte, nextbyte, leastused; PICTOR_Int RunLength, BlockSize, RunCount; BOOL bfound = FALSE, endofrun = FALSE; FILE *fpTmp; int c; // I am limiting myself to maximum 64000 byte blocks here // since this seems probably enough memory for pictor to allocate // for an unpacking buffer. // my particular algorithm also will not encode less than 2 bytes // which in the grand scheme of things is not a hardship. if (buflen < 2 || buflen > 64000)return FAILURE; // record all ascii values used in this block // and use one that isn't used for a marker. for (idx = 0; idx < 256; idx++) { markerbuf[idx] = 0; // initial count } for (idx = 0; idx < buflen; idx++) { markertest = buf[idx]; markerbuf[markertest] += 1; } // count backwards, I prefer the highest value possible for a marker. markertest = 255; for(;;) { if (markerbuf[markertest] == 0) { bfound = TRUE; RunMarker = markertest; break; } if (markertest == 0) break; markertest -= 1; } // if we found no available markers in this block // all 256 byte values are in use // ROT - to avoid complicated algorithms that consider patterning etc. // take John Bridges' early advice... // no unique bytes in scanline, so use the LEAST used byte as a marker // again counting backwards if (bfound == FALSE) { leastused = 255; jdx = markerbuf[255]; markertest = 254; for(;;) { idx = (unsigned) markerbuf[markertest]; if (idx < jdx) { // only switch for less jdx = idx; leastused = markertest; } if (markertest == 0) break; markertest -= 1; } RunMarker = leastused; } // now we know what the marker will be so we encode the runs // for this block into a temporary file which tells us the // sum of the compressed block which we require for our header. // I could also have done a dry-run, allocated memory and encoded into // a buffer but I am being lazy and these days computers are fast and disk space abundant fpTmp = fopen("ClipShop.$$$", "wb"); if (NULL == fpTmp)return FAILURE; endofrun = FALSE; // we are using a look-ahead method, so set a pre-emptive flag // so we know in advance when we have reached the end // so we can encode the last data run before end the encoding term writecnt = 0; // we need to track the sum of the packed data lastbyte = buf[0]; // seed value for comparison offset = 1; // set to second byte - for comparison (one byte delay) runcnt = 1; // ditto... do { nextbyte = buf[offset]; offset++; // Kiss and Dirty // comes to here after doing the last byte in the buffer // dump the last bytes we read using the same code again RunEnd: // end of run if (nextbyte != lastbyte || endofrun == TRUE) { // the data has changed so lets decide what to do if (runcnt < 3 && lastbyte != RunMarker) { // write raw bytes if below an efficent blocksize // but never run raw bytes for a run marker. // the ratio of lost efficiency is variable // depending on the pattern alternation and repetition of // the image and it could be great or negligible. // this encoder is not sophisticated enough to decide // to do a precalc on whether or not to encode. // it is very efficient for 8 bit non-planar images but will // probably not do so well for EGA style 4 plane images. // 'Nuff Said. for (idx = 0; idx < runcnt; idx++)fputc(lastbyte,fpTmp); writecnt += runcnt; } else if (runcnt < 256) { // write the 3 byte block fputc(RunMarker,fpTmp); fputc((unsigned char)runcnt,fpTmp); fputc(lastbyte,fpTmp); writecnt += 3; } else { // write the 6 byte block fputc(RunMarker,fpTmp); // 1 fputc(0,fpTmp); // 2 RunCount = (PICTOR_Int)runcnt; // 3,4 fwrite(&RunCount,2,1,fpTmp); fputc(lastbyte,fpTmp); // 5 writecnt += 5; } lastbyte = nextbyte; runcnt = 0; } if (endofrun == TRUE)break; // we dumped so break runcnt++; if (offset < buflen)continue; // if we are not done get another endofrun = TRUE; // set done and dump the last bytes before breaking goto RunEnd; // the following test is never actually used } while (offset < buflen); // left in place for some semblance of clarity fclose(fpTmp); fpTmp = fopen("ClipShop.$$$", "rb"); if (NULL == fpTmp)return FAILURE; // write the block header BlockSize = 5; BlockSize += writecnt; // blocksize includes header RunLength = 0; RunLength += buflen; fwrite(&BlockSize,2,1,fp); fwrite(&RunLength,2,1,fp); fputc(RunMarker,fp); // write the block for (idx = 0; idx < writecnt; idx++) { c = fgetc(fpTmp); if (EOF == c) break; fputc((unsigned char)c,fp); } fclose(fpTmp); remove("ClipShop.$$$"); if (EOF == c) return FAILURE; 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