.so ../ADM/mac .XX 36 571 "A Research Picture File Format and I/O Library" .fp 5 T CW \" T for Typewriter .TL A Research Picture File Format and I/O Library .AU Tom Duff Don Mitchell .AI .MH .SP .2C .NH Introduction .PP Researchers in centers 1122, 1125 and 1127 have for several years used a general file format for storing digital images, depth maps, mattes, and other two-dimensional digital signals. We have a convenient, portable library of C-language functions for manipulating picture files and a rapidly growing collection of graphics and image-processing software that uses the picfile format and library. .1C .KF bottom .P1 0 TYPE=dump WINDOW=0 0 512 512 NCHAN=1 CHAN=m COMMAND= antiquantize 'halftone CLASSIC' 512.halftone LIBERTY.anticlassic COMMAND= halftone CLASSIC 512.liberty 512.halftone 1.75 512.halftone COMMAND= transpose IN OUT COMMAND= resample 512 IN OUT COMMAND= transpose IN OUT COMMAND= resample 512 IN OUT COMMAND= clip 400 400 LIBERTY OUT .P2 .ce Figure 1 .KE .2C .NH The File Format .PP A picture file (often called a `picfile') contains a variable-length ascii header followed by a optional color-look-up table and binary data representing a two-dimensional array of multi-byte pixels. .PP The header is a list of attribute/value pairs separated by newlines, terminated by an empty line. A pure ascii header is machine independent. Its open-ended form allows applications to annotate pictures any way that they wish. Figure 1 shows a typical header. Each header line is of the form .I `attribute=value' where .I attribute is any string not containing an equal sign `=', an ascii nul (zero byte), or a newline, and .I value is any string not containing a newline or nul. The newline-terminated entries are separated from the binary data by an empty line (i.e. a pair of newlines). Thus, .P1 0 sed '/^$/q' \fIfilename\fP .P2 will print a picfile's header. .PP Several attributes are mandatory. The .CW TYPE attribute .I must come first, acting as a ``magic number'' and specifying the binary encoding of the image data. Currently, five binary formats are supported: .IP \fTTYPE=dump\fP 5n .br The binary data follows in traditional scan-line order. The first pixel in the file is at the upper left corner of the image. .I X coordinates increase to the .I right on a display, and .I y coordinates increase .I down. Pixels are stored in row-major order (i.e., .I x increases faster than .I y ). .IP \fTTYPE=runcode\fP .br Each pixel is preceded by a one-byte count that indicates how many adjacent pixels have the given value. Count values of 0 to 255 represent a replication factor of 1 to 256. No run may extend from one scan-line to the next. This format is useful in reducing the size of mattes or pictures containing large areas of constant color, but it may be a poor choice for digitized natural images or pictures containing noise. .IP \fTTYPE=bitmap\fP .br Pixels are one bit each, packed 8 bits to a byte, with the leftmost pixel in the high-order bit of the first byte. Each row must be an even number of bytes, so there can be up to 15 zero bits after the right-most pixel. A bit value of 1 represents black; 0 represents white. This is exactly the encoding used by SUN Microsystems and compatible manufacturers. .IP \fTTYPE=ccitt-g4\fP .br A black-and-white image encoded according to the CCITT FAX Group 4 standard. This is highly compressive on printed text and sparse line-graphics. .IP \fTTYPE=ccir601\fP .br The image is encoded according to the IEEE digital component video standard. (Y,U,V) values are stored as 8-bit values with chrominance compressed to half as much bandwidth as luminance. The layout of each row is Y U Y V Y U Y V ... .LP The other mandatory attribute is: .IP "\fTWINDOW=\fIx0 y0 x1 y1\fR" .br Specifies the size of the image by the coordinates .I "(x0, y0) of the upper left corner of the picture and .I "(x1, y1) of the pixel one beyond the lower right. The C interface uses .I "x0, y0, width, height to avoid confusion about whether the corner is in or out of the picture. .LP For .CW TYPE=dump and .CW TYPE=runcode , the following attribute is mandatory: .IP \fTNCHAN=\fInbytes\fR .br Specifies the number of bytes in each pixel. .CW TYPE=bitmap and .CW TYPE=ccitt-g4 may optionally take .CW NCHAN=1 , and .CW TYPE=ccir601 may optionally take .CW NCHAN=3 . .LP It is conventional but not mandatory to include: .IP "\fTCHAN=\fIformat\fR" .br Specifies the internal structure of a pixel. .I Format is a string of length equal to the value of .CW NCHAN . For example: .RS .IP \fTCHAN=rgb\fP\ \ 24-bit red-green-blue pixel. .IP \fTCHAN=rgbz...\fP\ \ 24-bit red, green and blue entries and a 32-bit depth value (floating point). .IP \fTCHAN=m\fP\ \ 1-byte monochrome or color mapped values. .RE The picfile routines specified here do not care how the user names channels. However, there are some conventions: .RS .IP \fTrgb\fP red, green, and blue channels .IP \fTyiq\fP NTSC luminance/chrominance channels .IP \fTyuv\fP IEEE or PAL luminance/chrominance channels .IP \fTa\fP alpha channel (matte) .IP \fTm\fP monochrome or mapped value .IP \fTf...\fP dots indicate a multiple-byte channel (e.g. a floating-point number) .RE .IP "\fTCOMMAND=\fIcommand line\fR" .br Store picfile history information. Multiple .CW COMMAND entries may be present in the header. The first is the command line used to make this picture, and following it are the .CW COMMAND entries (indented by one space) from all picfiles opened before this header was written. The header in Figure 1 shows a picture clipped to 400\(mu400, digitally resampled to 512\(mu512, converted to bitmap by a halftone screen, and then converted back to gray-level by Wiener-filter reconstruction. .IP "\fTRES=\fIxres yres\fR" .br Specifies the horizontal and vertical resolution in pixels per inch. This attribute is often used for images of documents. .IP \fTCMAP=\fP .br The .CW CMAP attribute has no value associated with it. It flags the presence of a color-look-up table after the header. This table is 768 bytes long and consists of 256 values of red, green, and blue. The bytes of the colormap are stored as rgbrgbrgb... .LP The colormap should be loaded into the frame buffer's colormap when the image is displayed. The mapping from pixel channels to colormap values in a full-color (e.g. .CW CHAN=rgb ) picture is usually: .P1 0 displayed red = colormap[3*r + 0] displayed green = colormap[3*g + 1] displayed blue = colormap[3*b + 2] .P2 In a monochrome picture, channel .CW m is normally mapped: .P1 0 displayed red = colormap[3*m + 0] displayed green = colormap[3*m + 1] displayed blue = colormap[3*m + 2] .P2 Applications may add other header lines. It is perfectly permissible to include .CW SHOESIZE=10 in the header, which all standard software will pass uninterpreted. .PP Following the ASCII header and the optional colormap is the binary data for the image. The routines described below assume nothing about this data except what is specified by .CW TYPE , .CW WINDOW and .CW NCHAN . .PP Pixels .I N bytes long, where .I N is the value of the .CW NCHAN attribute. .I Picread and .I picwrite , described below, do not interpret pixel values, except for conversion to a uniform format. Higher level software must assign format and meaning to pixels and specify byte ordering of short or long integers and the format of floating point data. .NH The Picfile Library .PP Picture files are referred to by a pointer to a .I PICFILE data structure, analogous to the standard I/O library's .I FILE structure. There are just a few routines for opening, reading and writing picture files one scan line at a time. To use them, a program must include the header file .CW picfile.h . On 10th edition .UX systems this file is in .CW /usr/include . On center 1125's SUNs it may for administrative reasons be found elsewhere. .P1 0 PICFILE * picopen_r(char *filename); .P2 .P1 0 PICFILE * picopen_w(char *filename, char *type, int x0, int y0, int width, int height, char * chan, char *argv[], char *cmap); .P2 .I Picopen_r opens a picture file for reading; .I picopen_w opens it for writing. For both routines, .I filename is usually a name of a .UX file. Some implementations may treat certain names specially, although this not part of the standard for now. The current implementation reserves the names .CW OUT and .CW IN to mean standard output and input. .PP For .I picopen_w , .I type is the value of the .CW TYPE attribute (e.g., .CW dump , .CW runcode , etc.) .PP .I X0 and .I y0 are the coordinates of the upper left corner of the image. .I Width and .I height are the size of the image. .I Chan is a string (e.g. .CW rgb , or .CW m , or .CW rgbaz... ) giving the value of the .CW CHAN attribute and, by implication, .CW NCHAN , which is always the string length of .I chan. .PP If nonzero, .I argv is the second argument of .I main . This passes information to the picture file routines that allow them to construct the .CW COMMAND attributes that maintain history information. It is strongly advised that users provide this pointer so proper history can be kept in picture files. .PP If non-zero, .I cmap points at a color-look-up table. .PP Once a picfile has been opened, I/O can be performed by the routines .P1 0 int picread(PICFILE *pid, char *buffer); int picwrite(PICFILE *pid, char *buffer); .P2 .I Buffer must be large enough to hold one row of the image (i.e., picture width times number of bytes per pixel). These routines read or write one row of an image, returning 1 if successful and 0 if error or end-of-file. .PP If an image has .CW TYPE=runcode , .I picread and .I picwrite will do the run-length decoding and encoding. If .CW TYPE=bitmap or .CW TYPE=ccitt-g4 , .I picread will unpack each row of the image into one byte per pixel (with values of 0 or 255), and .I picwrite will pack the pixels back into one bit each by a threshold test (1 if pixel < 128, otherwise 0). .CW TYPE=ccir601 files are unpacked and converted into .CW CHAN=rgb format, so that they can be processed by programs designed for conventional color images. .I Picread and .I picwrite do these conversions so that programs need not be greatly concerned with which image type is being used. The idea is to make all encodings look like the simplest, .CW TYPE=dump . .PP A picfile can be closed by .P1 0 void picclose(PICFILE *pid); .P2 .I Picclose closes the file descriptors and frees allocated memory associated with the picture file. .PP After calling .I picopen_w , but before the first call to .I picwrite (at which time the header is written out), users may add or change attribute values by calling .P1 0 PICFILE *picputprop(PICFILE *pid, char *name, char *value); .P2 .I Picputprop adds the attribute .I name=value to the picture file. The modified picfile descriptor is returned. .P1 0 char *picgetprop(PICFILE *pid, char *name); .P2 .I Picgetprop returns the value of the named attribute of a picfile descriptor, or a zero (\fINULL\fP) pointer if absent. .PP Attributes such as .CW COMMAND sometimes appear more than once in a header, as in the example at the start of section 2. .I Picgetprop and .I picputprop treat these as a single attribute-value pair, with newline characters delimiting the sequence of values. .PP There are macros defined in .CW picfile.h to extract commonly-used numeric attributes from picfiles. Each of the following returns an integer value: .P1 0 PIC_NCHAN(pid) /* value of NCHAN */ PIC_WIDTH(pid) /* picture width */ PIC_HEIGHT(pid) /* picture height */ .P2 Other attributes should be accessed using .I picgetprop and not by inspecting the .I PICFILE data structure, which may change in the future. .PP The call .P1 0 pid2=picopen_w(name, PIC_SAMEARGS(pid1)); .P2 will create a picture with the same arguments as a previously opened picture. The .I PIC_SAMEARGS macro includes argv in the argument list, so that variable must be defined at the point of call. .PP While not directly related to picture file I/O, the following two routines can assist some application programs which deal with complex pixel definitions. .P1 0 void picunpack(PICFILE *pid, char *pixels, char *format[, void *chan_ptr] ...); void picpack(PICFILE *pid, char *pixels, char *format[, void *chan_ptr] ...); .P2 .I Picunpack takes an array of pixels (as produced by .I picread ) and extracts channels into separate arrays of types specified by .I format . Similarly, .I picpack copies data from various channel arrays and packs them into a single array of pixels (as expected by .I picwrite ). .LP Characters in .I format can be: .IP \fTc\fP read or write a one-byte channel. The corresponding .I channel_pointer must be of type .I char (or .I "unsigned char" ). .IP \fTs\fP read or write a two-byte channel. The corresponding .I channel_pointer must be of type .I short . .IP \fTl\fP read or write a four-byte channel. The corresponding .I channel_pointer must be of type .I long . .IP \fTf\fP read or write a four-byte channel. The corresponding .I channel_pointer must be of type .I float . .IP \fTd\fP read or write an eight-byte channel. The corresponding .I channel_pointer must be of type .I double . .IP \fT_\fP underscore indicates a byte in the pixel should be skipped. .PP For example, in a picture with .CW CHAN=rgbz... , an unpacking of the green channel and the z channel would be done as follows: .P1 PICFILE *pid; char *pixels, *green; float *zdepth; picread(pid, pixels); picunpack(pid, pixels, "_c_f", green, zdepth); .P2 By using .I picpack and .I picunpack , the user also benefits from the standard machine-independent byte ordering that these routines will specify for .I short and .I long type date. Data of type .I float should also be standardized to use IEEE floating point format, but that is not being done now, so as not to inconvenience users of non-IEEE hardware. .PP Random-access routines such as .I picseek and .I pictell have not been included in order to encourage the development of .UX -style tool programs which can be combined with pipes. For example, using currently existing tools, a picture file can be resampled to 320\(mu256 as follows: .P1 resample 320 pfile1 OUT | transpose IN OUT | resample 256 IN OUT | transpose IN pfile2 .P2 .NH Example Program .PP Figure 2 shows a complete sample program. .1C .KF .P1 0 /* reflect a picture about horizontal median */ #include <picfile.h> main(int argc, char *argv[]) { PICFILE *in, *out; register char *left, *right, channel; char *buffer, *malloc(); int i; if (argc != 3) usage("reflect infile outfile"); in = picopen_r(argv[1]); if (in == 0) { perror(argv[1]); exit(1); } out = picopen_w(argv[2], PIC_SAMEARGS(in)); if (out == 0) { perror(argv[2]); exit(2); } buffer = malloc(w*n); while (picread(in, buffer)) { left = buffer; right = buffer + n*(w - 1); while (left < right) { for (i = 0; i < n; i++) { channel = *left; *left++ = *right; *right++ = channel; } right -= n + n; } picwrite(out, buffer); } exit(0); } .P2 .sp .ce Figure 2 .KE .2C .NH Acknowledgements .PP We would like to thank John Amanatides, Jon Helfman and Bob Safranek for there comments and experiences with this picture format. .PP The highly complex CCITT FAX format was implemented by Henry Baird.