Skip to main content.
IBAN   NL79 ABNA 0477 3565 08
EU-VAT NL170160656B01
Chamber of Commerce 32041148
http://www.compuphase.com
Eerste Industriestraat 19-21
1401VL  Bussum
tel. +31 35 693 9261
info@compuphase.com
CompuPhase

The Poly-Raster Image format

 

At a glance


Extension *.pri
Current version 0.3 (Software & tools; updated on 2007-01-06)
0.2 (Specification of the file format; updated on 2007-10-24).
Downloads Image converters (source code and binaries).
Image loader implementations (commented source code).
Documentation This page contains the full documentation of the format, plus a rationale for the design. The technical description of the file format is further down on this page.
Descriptions of the lay-outs of various displays and controllers are listed in the technical description too.

Introduction

The Poly-Raster Image format (file extension: ".pri") is a picture file format that holds one or more device-specific bitmaps along with descriptive headers. The Poly-Raster Image format is "yet another" image file format and the first (rhetoric) question to answer, then, is why we need to add another format to the many that exist already?

The goal of the Poly-Raster format is to be a flexible format that is easy to decode, using few resources. In particular, we should not assume that the loader/decoder can keep the entire image in memory. The Poly-Raster format is therefore particularly useful for embedded systems --especially the smallest of these embedded systems.

The display hardware in the "desktop PC" category is quite universal: memory is arranged in "scan lines" with the lowest address in video memory indicating the upper left pixel. Displays for embedded systems are more diverse: for example, for LED sign displays and wide graphic LCDs & VFDs, the display memory is often arranged in columns rather than in rows. Picture files for such displays are often in proprietary formats and only usable on a narrow range of devices. The Poly-Raster Image format brings three advantages over proprietary bitmap formats:

The reasoning behind the Poly-Raster format is that the image loader (on the embedded device) needs to support only a single sub-format. The image encoder, running on a desktop PC, has ample resources to perform the conversion from source image data to Poly-Raster images. In this case, the encoder has to convert the image data to a specific display --if the format does not match the one that the embedded device accepts, the file will simply be rejected. If you wish to make an image that is accepted by several devices, you can ask the encoder to build a multi-bitmap file. Each embedded image loader now chooses the entry that has the format that it supports.

In comparison with flexible and extensible image formats like TIFF, the Poly-Raster format avoids the complexity of parsing various options in order to interpret the pixel data, and the requirement to buffer the image data in RAM if the output device uses a column-ordered or banded lay-out. Instead, the pixel data is present multiple times in a poly-raster file and the loader chooses the most appropriate format. In comparison with "light" formats like WBMP, the Poly-Raster Image format is well-defined. Apart from the description of "sub-type 0" ("scan line" order, monochrome, maximum size 255 × 255 pixels) the WBMP specification essentially tells you that you are completely on your own to define formats for larger images or for a different lay-out of display memory. The WBMP specification, hence, is of no help at all.

section separator

File format

A ".pri" file is a collection of bitmaps. There may be only one bitmap in a file, or there may be several. Each bitmap has a header, but there is no "file header" describing the collection of bitmaps. It is up to the implementer or producer of the image to decide which bitmap formats are present in a file (and in what order).

The header of each bitmap gives the details of the format and the pixel lay-out. All multi-byte fields in the header are in Little Endian ("Intel" format). The header itself is 14 bytes in length.

field size description
size 4 the number of bytes that the bitmap takes in the file, including the header; if zero, it indicates a file terminator
id 2 a signature, which must be the value A201 (hexadecimal)
layout 2 bitmap type and flags, see the section "Bitmap lay-outs" for details
width 2 the width of the bitmap in pixels
height 2 the height of the bitmap in pixels
depth 1 the "colour depth", meaning the number of bits per pixel
chksum 1 this field is a checksum over the entire bitmap data including the header

An image file may contain multiple bitmaps and each bitmap will have a header. This way, a loader may pick the most appropriate bitmap from the file. In fact, most loaders will simply take the first bitmap in the file that they can support, so it is advised to store the highest resolution, most colourful images first in the file.

When browsing through the image file, the loader jumps from one bitmap to the next using the size field in the header. To see whether the end is reached, a loader can use the file size. In absence of a file system, e.g. streaming images, an alternative is to append a terminator to the image --the terminator is a four-byte field with all four bytes set to 0. When a loader tries to read a new header, the terminator takes the place of the size field, so a bitmap size of zero means that no more data will follow.

The bitmap data follows the header (plus an optional extended header) directly, without any padding. However, if there is a colour map ("palette") in the bitmap, the colour map precedes the pixel data. The layout field has bits to indicate the presence of an extended header and/or a colour map. The order of the data for a single bitmap is thus: header, (extended header), (colour map), pixel data; where the items between parentheses are only present if the respective bits in layout field are set.

The extended header is discussed separately in the section on animation.

If present, the colour map holds a number of three-byte entries with RGB components, in the order red-green-blue. The number of entries in the colour map depends on the colour depth: it is 2 for 1-bpp bitmaps, 4 for 2-bpp bitmaps, 16 for 4-bpp bitmaps and 256 for 8-bpp bitmaps; only pictures with 8-bpp or less can have a colour map. When no colour map is present in a bitmap and the colour depth is 8 or less, the bitmap uses a device-specific default palette.

An image loader can verify the checksum by summing up all bytes in the bitmap, including the bytes in the header, the extended header and the colour map. The resulting value should be 255 --a byte with all bits set. While summing the bytes, the image loader should use the bytes as stored in the poly-raster file, without unpacking pixels or applying any transformations. The summing is in two's complement and with truncating to 8-bits, meaning that 255 + 1 sums to 0. The image encoder calculates the checksum by first storing zero in the checksum field, computing the sum over all data and then subtracting the result from 255.

Bitmap lay-out

The layout field defines the lay-out of the pixels in the bitmap.

bit description
0 Column order: if set the pixels are ordered in columns rather than in rows ("scan lines")
1 Banded lay-out: if set, each byte represents a set of pixels in the opposite lay-out as the general lay-out
2 Reversed pixel order: if set, bit 0 of the first byte is part of the top left pixel; otherwise bit 7 of the first byte is part of the top left pixel. For RGB images, this flag indicates that the colour order in each pixel is BGR instead of RGB.
3 Planar: if set, the depth field refers to the bit depth of planes rather than the number of bits-per-pixels
4 Inverted Y-axis: if set, coordinate (0,0) is the lower left corner of the display rather than the upper left corner
5 Extended header present: if set, an extended header is present (immediately after the header)
6 Colour map present: if set, a colour map is present (it comes after the extended header, or after the header in absence of an extended header)
7 Loop frame: if set, this image is a loop-back frame at the end of an animated sequence

The next few figures give some examples for the bitmap lay-outs. In each case, the bitmap is a monochrome (1-bpp) picture. The first figure has all bits in the layout field set to zero. This is a common bitmap lay-out for standard PC graphics and image file formats; for example, the monochrome BMP and PBM image file formats use this very lay-out. In the figure, memory address zero is in the upper left. Vertically, the address jumps with "row" bytes and horizontally, it increments with 1 byte.

Standard bitmap lay-out (not lay-out modifier bits set)

Column order is common for displays and LED signs where data has to scroll horizontally (rather than vertically). You might almost say that a display with column order looks similar to a row-order display that is rotated 90°. In the figure, memory address zero is in the upper left. Horizontally, the address jumps with "col" bytes and vertically, it increments with 1 byte.

Column-order bitmap lay-out

A banded lay-out mixes row and column modes. From a memory addressing perspective, a banded row-order lay-out is indeed row-order: the address increments by one along the horizontal axis. However, a row is now eight pixels high, rather than just one pixel. A banded row-order lay-out is common for dot matrix printers, ink-jet printers and thermal transfer printers.

Banded row-order bitmap lay-out

Reversed pixel order only changes the order of the pixels in a byte, in the case that multiple pixels fit in a byte. Compare the figure below to that of the layout = 0x00 case.

Standard bitmap lay-out with reversed pixel order

The bits in the lay-outs may be combined too. I have only presented a lay-out for a banded row-order bitmap, but in similar ways, you can imagine a banded column-order bitmap.

Depending on the number of bits per pixel, some of the lay-out bits are irrelevant. For example, for an 8-bpp image there is exactly one pixel in a byte and bit 2 in the layout field does not make sense (except for the very special case that an 8-bpp device with be planar, but I am unaware of such devices). Similarly, 1-bpp images are never "planar", as there is only one plane. Only 1-bpp images can be "banded". Image writers should clear any irrelevant flags.

The table below lists the lay-outs for a few well-known devices. The "label" column refers to the symbolic name that you can use in the command-line image converter utilities.

controller lay-out label description
VGA, PC-graphics 0x00 vgamono The most common lay-out for standard PC video cards and bitmap file formats (GIF, PNG, PCX, binary PBM, etc.). The data is ordered in "scan lines" with the most significant bit of a byte denoting the left-most pixel (for monochrome images).
Windows BMP 0x10 (inverted Y-axis) bmp The Microsoft Windows BMP file format uses (0,0) as the left-bottom coordinate.
Dot matrix printer 0x02 (banded rows) esc_p2 Most dot-matrix and thermal printers use the ESC/P2 control language originally developed by Epson. The command set is primarily aimed at ASCII text, but it includes commands for single-precision and double-precision graphics. The graphics data must then be sent as banded rows.
KS0107/KS0108 0x06 (banded rows, reversed pixel order) ks0108 The controller pair KS0107/KS0108 drives a 64×64 pixel area. In a typical set-up, two KS0108 controllers are combined with a single KS0107 controller to form a 128×64 resolution display. Compatible alternatives to the KS0107/KS0108 are: HD61202/HD61203, AX6108/AX6107, KS0708, S6B0708, S6B0108A, S6B2108, S6B0108 and NT7108.
Noritake 372
Noritake 900
Noritake 3000
0x01 (column order) gu372
gu900
gu3000
The Noritake-Itron 372 series, Noritake-Itron 900 series and Noritake-Itron 3000 series, all use column order for the graphic data. Displays from these series are, for example, the GU256x64-372, the GU256x64-900a and the GU256x64-3900.
Noritake 7000 0x06( banded rows, reversed pixel order) gu7000 The Noritake-Itron 7000 series uses a lay-out similar to that of the KS0107/KS0108 controllers.
Noritake 7800 0x00 to 0x03 (multiple configuration) gu7000 The Noritake-Itron 7800 series has a configurable lay-out for graphic data; it can either use a VGA-compatible "scan line" lay-out (0x00), column-mode, banded mode, and banded column mode. Popular displays from this series are the GU140x32F-7806 and the GU140x16G-7806.

Pixel encoding

If a bitmap has planes (and assuming a row-encoded bitmap), the file holds in sequence the pixels for layer 0 for a row, then layer 1 for that row, and so forth for the number of planes, before moving on to row 1 (and restarting with layer 0). Column-encoding bitmaps follow the same procedure, but with columns instead of rows.

A row or column (or plane in a row or column) is always padded up to a full byte; no partial bytes are stored. This is only relevant when the number of bits per pixel is less than 8. Other than writing full bytes, no other padding occurs.

Currently, no compression scheme is defined, as we have not found a simple compression algorithm that performs well on image data and that does not require RAM tables. In current configurations, the images are usually small and monochrome (1 bit-per-pixel).

Animation with poly-raster images

The poly-raster format allows for simple animations by storing several bitmaps in a file that all have the same value for the layout field. The first bitmap is a full and plain image; all other bitmaps have an extended header that gives the amount of time to wait before putting the next frame on screen, plus deltas for the horizontal and vertical position of the section of the image that changes from the previous frame.

The presence of an extended header must be signalled with bit 6 in the layout field in the standard header. If present, the extended header follows the standard header immediately. The fields in the extended header are in the following table.

field size description
delay 2 the number of milliseconds to wait before displaying this bitmap, relative to the time that the previous bitmap was displayed
dx 2 a value to add to the horizontal position where the pixel is displayed
dy 2 a value to add to the vertical position where the pixel is displayed

The dx and dy fields allow, in combination with the width and height fields of the header, to restrict the stored bitmap to a rectangular area inside the full image. If only part of the frame changes, only that part needs to be stored in the bitmap of the frame.

The (dx, dy) and (width, height) coordinates are restricted to indicate a byte-aligned subset of the image. For example, if the image is monochrome (1 bit-per-pixel) and in row-order, the dx and width are aligned to multiples of eight pixels. For a column-ordered monochrome image, the dy and height fields are aligned to eight pixels. For a 2 bits-per-pixel image, the alignment would be a multiple of four pixels, since four pixels fit a byte in this case. These alignment restrictions make it easier on the image loader, because no partial bytes need to be processed.

The delay field indicates the amount of time (in milliseconds) that should pass before the frame appears on the screen. In other words, it indicates how long the previous frame should be displayed.

One can, of course, combine animations with multiple lay-outs in a file. The bitmaps that have the same layout code are part of an animation for that lay-out. Bitmaps with different layout codes in the same file are part of animations for a different display.

Image readers that do not support animations read the first (full) image only. To support animation, an image reader should look for bitmaps with the same layout code and an extended header further on in the file.

When an animation is a "looping" animation, the last frame should have bit 7 in the layout field set. This field indicates that the respective frame brings back the image to be identical to the first (full) image. After the image reader loads this image, it jumps back to the second frame in the animation. That is, an image reader decodes the full image, the one without an extended header, only once, as the very first image.

Miscellaneous notes

When the images are transferred in real-time rather than present in (ROM) memory or on a disk, instead of sending each device every supported format, a server could negotiate which format the client accepts, and send poly-raster files with only the bitmap in that format.

If the image generator were to create an image with bitmaps in every possible lay-out, it would need to include 16 bitmaps for a monochrome image, and more for colour images, especially when the colour image also includes fall-back bitmaps for monochrome displays. In practice, an application or server creates images for a particular group of devices. In this group, some uniformity may be expected. For example, for an application for creating scrolling banners for LED signs may restrict itself to column ordered formats, which are easier to scroll horizontally.

Although a loader may opt to support exactly one bitmap format, it may also choose to do some conversions itself. For example, when a display is laid out in rows (scan lines), it takes only little extra code to supporting an inverted Y-axis in addition to a normal Y-axis. To support both bit orders, you could add a table with reverse byte mapping, which takes 256 bytes of ROM and no RAM.

An image writer should always store a checksum, but it is entirely up to the image loader whether it verifies checksums in images. Verifying the checksum makes the loader a little more robust, but it also increases the complexity of the loader. Many network protocols and storage media are quite reliable, and the extra bit of robustness may not be worth the complexity that it adds to the code.

section separator

Software downloads

Image converters

MakePri converter screen shot (GUI version)
Screen shot of the GUI version of the poly-raster image converter

Image loaders

All image loaders come with source code. The portable versions create a PBM image from the poly-raster file, extracting the best matching bitmap. The Microsoft Windows versions display the bitmap after loading it.