GemPrint file format ==================== All words are little-endian. +0 'PDGP' magic word to indicate the format +4 Version number*100 (currently 100) +8 Structured data describing the job : +0 number of rows on page (height) +4 number of pixels per row (width) +8 first non-empty row encoded +12 last non-empty row encoded +16 first non-empty pixel +20 leftmost pixel found +24 rightmost pixel found +32 number of rows to skip at top +36 number of cols to skip at left +40 job flags : bit 0: Image is colour +44 number of copies requested +48 paper width in millipoints +52 paper height in millipoints +56 printable area (x0,y0,x1,y1) +72 x resolution (DPI?) +76 y resolution (DPI?) +80 offset in file of short printer name +84 offset in file of long printer name +88 offset in file of resolution name' +92 offset from start of file to first encoded row Rows may be compressed in the file, and consist of RGB data. Each row starts with a 4 byte header indicating the number of bytes used to store the row. An empty row, therefore is represented by a value 4. This header is then followed by a row header which describes just that row, the full header being : +0 length +4 leftmost pixel in row +8 rightmost pixel in row +12 (1 byte) 'compression type': 0 = uncompressed data 1 = simple run length encoding (RLE) +13 (3 bytes) extradata, dependant on compression type: Type 0: +13 (3 bytes) Reserved, must be 0 Type 1: +13 (1 byte) Escaping byte value +14 (2 bytes) Reserved, must be 0 The 'leftmost' to 'rightmost' pixels are stored in the file - the pixels outside this range are assumed to be white (&FFFFFF) and not stored in the file. The 'leftmost' and 'rightmost' values are for the complete page, not just for the printed area, and thus are not relative to the entire job 'leftmost' and 'rightmost' values. Uncompressed data is stored in the file as-is as 3 byte sequences in the order (unknown). RLE compressed data is compressed using a run-length encoding system, with the escaping byte indicated by the header (at offset +13). // Decoder for RLE is thus : // (actual code can be found in GPDriver.c.image function 'decompress_row') WHILE NumberOfPixelsLeft > 0 R = GetByte IF R = EscapeByte THEN // RLE compressed data NumberOfRepetitions = GetByte R = GetByte G = GetByte B = GetByte FOR NumberOfRepititions TIMES WriteData(R,G,B) NumberOfPixelsLeft -- END FOR ELSE // Raw data for one pixel G = GetByte B = GetByte WriteData(R,G,B) NumberOfPixelsLeft -- ENDIF END WHILE