[This is a not very good translation from Japanese, I am deeply sorry] ///////////////////////////////////////////////////////////////////// Pi 16-color graphic loader/saver Specification (2nd Edition) 1991-03-24 copyright 1990,91 (c) Yanagisawa PC-VAN : LVB06263 UNCLE : UNC10103 IIDA-Apple : IAN00159 Nifty-Serve : NCD01745 ///////////////////////////////////////////////////////////////////// This document describes my 16-color graphics compression format "Pi". =========================== Introduction ============================ There are many cases where image decompression is explained, but compression methods are not explained, which I regret. To help you progress, the "Pi" format is described here. I hope this article will be helpful to anyone interested in image compression or porting. =============================== Name ================================ Pi is read as "pie". This is because it has less Colors than PIC. ============================== Header =============================== The file header is described below. It feels a bit redundant, but it may as well be described. I had planned to make it like PIC, but decided against it. From start of file (Numbers are big-endian, unless noted otherwise) 'P' 1 byte Pi signature. 'i' 1 byte any bytes Comment section (can be displayed by decompressor) except EOF 26(EOF) 1 byte End of comment section. any bytes Dummy data. except 0 0 1 byte True end of comment section. (Skip to first 0 after reading the EOF above.) The intent is, that this will work with or without the EOF, or when copied with the DOS Copy command. 0 1 byte Mode: When bit 7 (MSB) is 1, palette data is omitted, and a default palette must be used. This was introduced because the palette is too large in VA-256 mode. Bits 0-6 are not used currently. n 1 byte Screen ratio data. m 1 byte n / m is the pixel aspect ratio. This must be used when drawing to ensure the image looks right. If either is 0, set n / m = 1. Usually both are 0. 4 1 byte Number of planes. Possible values currently are 4 (16 colors), and 8 (VA-256 colors). The 16-color plane can be used for 8-color images too. 'X68K' 4 bytes Identifier for the compressor's system model, for example 'PC98' etc. This also indicates what to do with the following system-specific data. s 2 bytes Size in bytes of the following system-specific data. x s bytes This can contain any information at the compressor developer's discretion, but please don't use this for anything that decompression won't work without. 640 2 bytes Image width in pixels. 400 2 bytes Image height in pixels. p 3*16 bytes This is the palette data, which may be omitted depending on the mode. The palette is stored sequentially from 0 to 15, where each consists of 3 bytes in the order RGB. (0:rgb) -> (1:rgb) -> (2:rgb) ... Make sure to shift each byte, since palette intensities on X68000 only use 6 bits. (msb) 76543210 (lsb) xxxxxx00 4096-color models can only use 4 bits. (msb) 76543210 (lsb) xxxx0000 So the palette is 16 colors from a total color space of 16 million colors. (Or 256 colors, if plane is 8.) (Perhaps the lowest bit should not be set to 0. When the color is 0, zeroing the lowest bits means the color is still 0. But if the color is at maximum brightness, zeroing the lowest bits results in less than maximum brightness. For example, if the saving system has n bitdepth, then brightness P should really become: (P * (1 << 8-1) / (1 << n-1)) Is that correct? It would be easier to zero out the lowest bits when the value is 0, otherwise fill with ones. Might be good enough?) =========================== Image format ============================ * Overall flow Pixels will be treated as horizontal pairs. 1) First, record the color of the first (top left) 2 pixels. Assume that the two pixels meet the two lines above the target screen. 2) Next, record from the upper left to the lower right, row by row. (Each row's right end connects to the next row's left end.) 3) Comparing to the pixel pair, check if the same pair is found in any of five locations: above right, above left, straight above, two rows above, or two left. 4) Record the location with the longest repetition of this pair, and record the repetition length. Move the read position ahead, and if there is more image data left, return to (3) and repeat. 5) If the pattern in (3) doesn't repeat in any location, record the same location as the previous time. (Since you can't have the same repetition location more than once in a row otherwise.) 6) Record the color of the pixel pair at the read position, and move the read position ahead by a pixel pair. 7) Check for repetition again like in (3), and if you can't find repetition, record 1 (single bit). If you did find it, record 0 (single bit). Then return to (4) and repeat. (There is also a way to return to (3) without the single bit, or to record the length indicating that the pattern cannot be found.) (Flow diagram) +-----------------+ | ^ v | (Start) First a |c pixel pair (1) ---> location -+- length +-----------------+---> (End) ^ (4) | (4') ^ | (5) v b | | +- pair -- continue? --+----+ d | ^ (6) (7) | | | | v | | +----------------------+ | | v +-----------------------------------+ a) If location is same as previously recorded location, go down. b) Go right when continue is 0, or go down when it is 1. c) When compression is complete, go right, else go up. d) When compression is complete, go up, else go down. Compression ends when the pixel is outside the image bounds. * Location Use the following five locations relative to the read position: Location 0: This one's special. :-) If the current pixel pair is two of the same color, then this location is one pixel pair to the left. If the current pair are of different colors, the location is two pixel pairs to the left. This should take care of 4x4 pixel dithering patterns. In most cases, repeating a single pixel pair gives better compression, but don't ignore 4x4 patterns even though the difference is small. And if you increased the location to 3 pairs, the coding length would increase and it wouldn't work. There's also a way to scan the image at the beginning and dividing the mode, but since it was of little benefit in practice, this was left out. (I prefer to avoid mode division as much as possible.) However, I do feel a bit awkward for including this special case. (;_;) Location 1: Pixel pair one row above. Location 2: Pixel pair two rows above. Location 3: Pixel pair on the above row, one pair to the right. Location 4: Pixel pair on the above row, one pair to the left. Note: Although I wrote that the same location can't be repeated twice in a row, in section (5), but since location 0 has special handling, it is possible for location 0 to appear more than once in a row. So flag it so that you won't record a location 0 again if the previous location was 0. (^^) * Location encoding method (Maybe there's a way to combine this with the length) Location 0 --> 00 Location 1 --> 01 Location 2 --> 10 Location 3 --> 110 Location 4 --> 111 (The code length is 2 or 3 bits.) * Length I will be using the following method. This uses a slightly more statistical approach, but it's not too scary. :-) 1 0 2-3 10x 4-7 110xx 8-15 1110xxx 16-31 11110xxxx and so on. (Each x is a single bit) * Continue-flag The flag to indicate whether to record more pixel pair colors. Can continue --> 1 No continue --> 0 (This is recorded as a single bit) * Color Although each pixel pair's colors are treated as a single unit, the colors are recorded one at a time. This method encodes the colors in the order they were used most recently. For example, 0 to use the same color as the last time, 1 to use the same color as two colors ago. Then, this is divided further into 16 arrays, one for each possible previous pixel color. This is because the closer colors are, the more likely they are to appear again, and the patterns correlate more strongly with the previous pixel's color. There are many ways to do this. Let's use the following method: Prepare the following table with these initial values. (previous pixel) (old...) (...new) 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F (0 to F each indicate a color code in one digit hexadecimal) For example, you want to record color 8 (the previous pixel's color is 5). 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 This means you must record 13, since 8 is 13 away from 5. Then bring color 8 to the front, and the row ends up looking like this: 5 6 7 9 A B C D E F 0 1 2 3 4 5 8 As you move the 8, everything else shifts backward accordingly. Then just repeat this for each color you record. * Color coding Much like before. 0-1 1x 2-3 00x 4-7 010xx 8-15 011xxx (Each x is a single bit) * Special case If image width is 2 pixels or less, then as a special case only color data is encoded for all pixels, without repetition. (So it is saved almost as a bitmap, but at least color compression still happens.) * Attention At end of compression, output an additional 32 bits of zeroes. (There are different methods of bit buffering, so it is best to output extra bits.) * Default 16-color palette If the top bit of mode is 1 in the header, use the fixed palette in this table. It is 1 byte for each RGB component, but although 0 is 0, F0 should be displayed as FF. This is because the data range is 0-F. +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | 0| 1| 2| 3| 4| 5| 6| 7| 8| 9| A| B| C| D| E| F| +---+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | R | 0| 0|70|70| 0| 0|70|70| 0| 0|F0|F0| 0| 0|F0|F0| | G | 0| 0| 0| 0|70|70|70|70| 0| 0| 0| 0|F0|F0|F0|F0| | B | 0|70| 0|70| 0|70| 0|70| 0|F0| 0|F0| 0|F0| 0|F0| +---+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ (the palette values are in hexadecimal) =========================== VA-256 colors =========================== The optional VA-256 specification is also supported. * 256-color header The number of planes is 8. Mode's msb is 1, and the default palette is used. (There are no models currently offering a 256-color palette.) * Color record The color table is expanded to 256*256, but otherwise works the same way. (It'll be a bit painful having 256 colors in the air simultaneously.) Color coding is as follows: 0-1 1x 2-3 00x 4-7 010xx 8-15 0110xxx 16-31 01110xxxx 32-63 011110xxxxx 64-127 0111110xxxxxx 128-255 0111111xxxxxxx * Default 256-color palette This is in 8-bit color, as follows: (msb) | | (lsb) 7 6 5|4 3 2|1 0 G | R | B 3 | 3 | 2 G/R/B indicate green, red, and blue. * When not using the default palette As with 16 colors, there is a 256-color palette present, but each palette entry consists of a single RGB byte. ======================= Copying this document ======================= I assert copyright over this material, but it can be copied freely, just like Pi itself. ========================= Porting requests ========================== Please tell me when you start, if possible. (I'd like to avoid multiple ports to the same computer model.) Please upload the port somewhere I can download it. (Also contact me when doing the upload.) Please give me permission to copy. (I will contact you) Please do not change the specification arbitrarily. Please tell me if you use the model-specific data for something. Please give me permission to publish information about the port. Please credit me somewhere as the original author. The port should be free. (Of course, the port has its own copyright.) If you satisfy the above conditions, we will make it an official port. The VA-256-color support is optional. It must support a minimum of 640x400/16 to be considered Pi. I hope you will set the copying conditions as free as possible. Despite all of the above, I have no intention of causing trouble even if someone does port it independently, but since this is the original author's wish, let's respect it (^^) ============= System models used by current Pi authors ============== X68000 (c) Yanagisawa PC98 (c) Mr. JUNTA / Mr. LOCKE PC88VA (c) Mr. LOCKE There's also a pretty good X-WINDOW version (which is omniscient and dependent on the model :-). (It's running on the company's HP 9000/300 :-) ============================ Conclusion ============================= I tried to be careful not to make mistakes in this specification, but I can't guarantee it. Please forgive the responsibility in that case. I'm happy to answer any questions about the format. If you have any questions, please contact us.