James is the maintainer of the Graphics File Formats FAQ on comp.graphics.misc and coauthor of Encyclopedia of Graphics File Formats, second edition, (O'Reilly & Associates, 1996) on which this article is based. He can be contacted at jm@ora.com.
Still picture interchange file format (SPIFF) is a generic bitmap file format defined by the International Telecommunications Union (ITU) and International Standards Organization/International Electrotechnical Commission (ISO/ IEC) for the storage, compression, and interchange of color or grayscale continuous-tone and bitonal image data.
SPIFF is capable of storing bitmap data containing pixels 1 to 32 bits in depth with a maximum image size of 4Gx4G pixels (64Kx64K pixels for nontiled baseline JPEG images). Along with JBIG and JPEG, SPIFF supports Modified Huffman, Modified READ, Modified Modified READ, and uncompressed data. A SPIFF file may only contain one image (not including thumbnail images) and SPIFF data is always read and written using the Big-endian (Motorola) byte order.
SPIFF has been described as the "official" JPEG file format. When the Joint Photographic Experts Group (ISO/IEC JTC1/ SC29/WG1) established the JPEG compression standard in 1990, they didn't create a corresponding standard file format for the storage and interchange of JPEG data. Some five years later, SPIFF is in draft status and pending ratification by the JPEG committee to fill this void.
The original JPEG committee did not create an official JPEG file format because, at the time, numerous other standards groups were defining file formats for various application environments, such as SC18 for the Office Document Architecture (ODA) and SC24 for image processing applications. Each of these groups was planning on storing JPEG-compressed data within file formats of their own design.
Reasoning that a single file format covering the needs of all applications could not be adequately defined, the Group concluded that the other standards bodies should be left to create their own formats to encapsulate JPEG data. It also was a possibility that any file format work undertaken by the JPEG committee could be perceived as infringing upon the scope of work of other standards bodies.
Regardless of the reasons for its omission, a file format for JPEG data needed to be created.
The format that emerged was the JPEG File Interchange Format (JFIF), created in 1992 by Eric Hamilton of C-Cube Microsystems and other developers. JFIF is the format typically used when software reads and writes what is commonly referred to as a JPEG (.JPG) file. Although JFIF is a very simple format-containing little more than a header followed by a JPEG data stream-it is very portable across all operating systems, and it quickly became the de facto standard file format for storing JPEG image data.
When Eric Hamilton took over as WG1 Convener (JPEG and JBIG committees), he started to work on a completely defined file format for JPEG and JBIG data. The majority of users need something simple that allows image interchange. Because compressed picture interchange definitely falls within the scope of the JPEG and JBIG projects, SPIFF was created as a standard interchange format. Eric stepped down as the WG1 Convener in December 1994 when work on extensions to the JPEG standard was completed.
The SPIFF specification is found in the Digital Compression and Coding of Continuous-tone Still Images: Extensions standards document (published by the ITU as ITU-T Recommendation T.84 and by the ISO as ISO/IEC International Standard 10918-3). This document also may be described as part 3 of the JPEG specification and can be purchased directly from the ITU (http://www.itu.ch) and ISO (http:// www.iso.ch).
Since JFIF is small, simple, and widespread (and practically every JPEG image-display program reads it), why would you want to use SPIFF rather than JFIF to store your JPEG image data?
One reason is that SPIFF is much more carefully designed, specified, and thought-out than JFIF. SPIFF is part of the JPEG standard and is, therefore, well-defined in format, application, and compliance testing. It is an official standard, rather than an ad hoc one, and it has been reviewed more thoroughly.
SPIFF also is more flexible than JFIF. Extended features include support for more color spaces and a provision for specifying image gamma. JFIF took a shortcut by requiring that all JFIF images have a gamma of 1.0. That requirement has been widely ignored because many preexisting images have other gamma values, and, as it turns out, a gamma of around 0.4 to 0.5 is technically superior. Always assigning a gamma of 1.0 means that JFIF images frequently come out too dark or too light, depending on their origin and the viewing system.
The SPIFF specification does not define a standard file extension or type indicator for SPIFF files. IJG recommends that the ".JPG" extension and the "JPEG" type indicator be used for SPIFF files containing lossy (DCT), JPEG-compressed data, and that ".SPF" be used for all other variants of SPIFF. (Of course, the JBIG community might prefer a ".JBG" extension for SPIFF-JBIG files.)
The .JPG extension is already commonly used for JFIF-format JPEG files. However, properly written JFIF-compatible software should read SPIFF-JPEG files without difficulty. The SPIFF format has been carefully designed to make this possible by defining the magic numbers and length fields to make the SPIFF header look like a series of JPEG APPn markers, which old JPEG decoders will just ignore.
SPIFF also will be supported in the future by the Independent JPEG Group's (IJG) JPEG library (available at ftp:// ftp.uu.net/graphics/jpeg/jpegsrc.v6.tar.gz). This means you can integrate SPIFF support into your image and graphics applications using a well-known, well-written, widely distributed, and freely available source-code library that hundreds of applications already use.
You can expect that SPIFF-JPEG software will read JFIF files for backward compatibility. Because JFIF and SPIFF-JPEG are interoperable, there is no need to confuse the average user by introducing a new file extension for SPIFF files containing JPEG data.
The non-JPEG variants of SPIFF, however, are not interoperable with any existing software, and will confuse JFIF-only software considerably, so those variants need a different extension. Using the extensions ".JPG" and ".SPF" also offers the advantage of maintaining a clear distinction between lossy and lossless SPIFF image formats, which should minimize user confusion and unintentional degradation of data.
As Figure 1 illustrates, SPIFF files are composed of four major sections: the header, the information directory, the image data, and an optional section containing indirect data (that is, information too large to fit in the information directory).
The header is typical of most bitmap file headers and contains information necessary to properly decode the image data. The directory may be thought of as a secondary header that contains optional fields of information called "directory entries." The image data is stored immediately after the directory and is followed by any directory data that was too large to fit in a single directory entry.
The SPIFF header is 36 bytes in length; see Figure 2. MagicNumber is the identification value for SPIFF files. This 4-byte field always contains the value FFD8FFE8h.
HeaderLength contains the length of the header excluding the MagicNumber field. In version 1.0 of SPIFF, this value is always 32.
Identifier contains additional identification values. These values are 53h, 50h, 49h, 46h, 46h, and 00h (the NULL-terminated string "SPIFF").
Version contains the major and minor revision of SPIFF to which the file conforms. The most significant byte contains the value 01h and the least significant byte contains the value 00h. These values correspond to version 1.0.
Differing minor version numbers represent backward-compatible changes in the SPIFF format. Differing major version numbers represent backward-incompatible changes in SPIFF. File readers should attempt to read SPIFF files even if the minor revision number is not recognized, but should give up if the major version is not recognized.
ProfileId specifies the features that the file reader must support to read the file. There are four possible values for this field: 0 (no profile specified), 1 (continuous-tone base profile), 2 (continuous-tone progressive profile), 3 (bilevel facsimile profile), and 4 (continuous-tone facsimile profile).
NumberComponents indicates the number of color components (channels) in the primary image. This value is 1 for a typical grayscale image, and 3 for an RGB or CMY image.
ImageHeight and ImageWidth store the size of the image. ImageHeight is the number of scan lines in the primary image. ImageWidth is the number of samples per line.
ColorSpace specifies the color-space coordinate system used to define the samples. Table 1 lists the allowed values for this field.
BitsPerSample specifies the number of bits per sample.
CompressionType indicates the type of compression algorithm used to encode the image data. The possible values for this field are given in Table 2.
ResolutionUnits indicates the type of units used to express the resolution of the image. Possible values for this field are 0 (aspect ratio defined by VerticalResolution and HorizontalResolution), 1 (dots or samples per inch), or 2 (dots or samples per centimeter).
VerticalResolution and HorizontalResolution contain the resolution of the image. If ResolutionUnits is 0, the values of these fields contain the numerator and denominator, respectively, of the samples' aspect ratio. Otherwise, these fields contain the image resolution as fixed-point numbers.
Following the header is a directory of references to information stored within the SPIFF file. The directory will contain at least one directory entry-the End of Directory (EOD) entry is mandatory-all other entries are optional. Data associated with the directory entry may be stored directly, within the directory entry, or indirectly, outside of the directory and following the image data. The maximum size of a block of data that may be stored within a directory entry is 65,527 bytes.
As Figure 3 illustrates, the header of each directory entry is 8 bytes in length. EntryMagic identifies the start of each directory entry. This value is always FFE8h.
EntryLength is the length of the entry, not including the EntryMagic field. The value of this field may range from 6 to 65,534.
EntryTag is a bit field identifying the format and type of data stored or referenced by the directory entry. Each directory entry will always have a unique EntryTag value and a specific format of entry data. The eight most-significant bits (31:24) of EntryTag are always 0. The value of the next three bits (23:21) define the originating standards body to which the file data conforms. Table 3 presents the possible values.
The remaining bits (20:0) are defined by the standards organization defining the particular tag. The SPIFF specification defines the possible values of these remaining 20 bits when the three identifier bits are set to 0.
Each directory entry must be a multiple of 4 bytes in length. An entry with no associated data is 8 bytes in length. An entry containing an offset to indirect data is 12 bytes in length. And an entry containing direct data must have its data padded to end on the nearest 4-byte boundary. Figure 4 shows the layout of a directory entry.
Directory entries are not linked together by offset values in the way that TIFF image file directories are. Instead, entries occur in contiguous order after the header and before the image data. Figure 5 illustrates the position of directory entries within a SPIFF file.
The last entry in a directory is the EOD. In an EOD entry, EntryMagic is FFE8h, EntryLength is always 8, and EntryTag is always 1.
Note that the EntryLength value of the EOD entry is two bytes larger than it seems it should be. This is because the length of the EntryMagic field is also added into this value, but only for the EOD entry. The EntryMagic, EntryLength, and EntryTag fields are defined to appear as a JPEG SOI marker followed by a series of JPEG APP8 markers, so the SPIFF header and directory entries are ignored by JFIF readers. The EOD EntryLength value is two greater than it should be so that old JFIF decoders will skip over the SOI marker at the beginning of the SPIFF data area. Otherwise, older decoders would see two SOI markers and complain.
SPIFF 1.0 defines the format of 15 directory entries and EntryTag values. All of these entries (except for the EOD entry) are optional, and many may appear only once in a SPIFF file. The exact format of each entry is documented in the SPIFF specification; see Table 4.
Indirect storage is allowed for the Thumbnail Image, Scan Index, Tile Index, and textual-directory entries (Image Name, Image Description, and so forth). Each of these entries contains a field specifying the offset of the data from the beginning of the file. If this value is 0, then the data is stored directly within the entry. It is recommended that direct storage be used whenever possible (that is, when the entry data is less than 64 KB in size).
SPIFF requires that the Scan Index and Tile Index entries be stored as indirect data. These indexes are only useful to decoders that can perform random access on a file and are likely to be built on the fly by encoders, so requiring them to be stored at the end of a SPIFF file is a reasonable thing to do.
The SPIFF format also provides for application-specific directory entries that would store any information not supported by the standard directory entries defined in the SPIFF specification. These directory entries are identified by setting the bits 23:21 in the EntryTag to all 1s.
There currently is no process for registering or reserving application-specific directory tags, so it is recommended that additional identifying information be present in the entry data. This will help prevent data interpretation problems caused by duplicate application-specific directory tags defined by different organizations. SPIFF readers should, of course, ignore any directory entries with an unrecognized tag value.
Although thought of as a file format for JPEG data, SPIFF is capable of supporting data compressed using the Huffman 1D, MR, MMR, and JBIG data-compression methods as well. And uncompressed-data storage also is supported, as you might expect.
The data area of each variation of SPIFF contains the complete data stream defined by the underlying compression standards. For example, SPIFF-JPEG files contain a complete JPEG interchange data stream as defined by ITU-T T.81, SPIFF-JBIG files contain a complete JBIG bi-level image entity as defined by ITU-T T.82, and so on.
An application profile is a predefined set of features that a SPIFF file reader must support in order to interpret the contents of a SPIFF file. The ProfileId field of the header contains a value that specifies the profile required by the data stored in the SPIFF file. This field makes it possible for a file reader to determine the contents of the file without reading the entire directory.
The profiles currently defined apply to baseline JPEG data, progressive-mode JPEG data (for low-speed communications applications), bi-level image data, and continuous-tone, color or grayscale facsimile images. The currently defined profile values are listed in Table 5. The profile value should be 0 (no profile) if the file uses features that do not fall into any of the other profiles.
When you first read through the SPIFF specification, you may conclude that it is easy to convert a JFIF file to a SPIFF-JPEG file: Just fill in the SPIFF header fields from information found in the JFIF file, write out the header and an EOD entry, then append the entire JFIF file itself to the SPIFF-JPEG file.
This technique for JFIF-to-SPIFF-JPEG conversion has the advantage of being a simple and quick conversion that also preserves the JFIF markers, allowing older decoders to read the resolution and thumbnail data present in the JFIF data stream. It also allows a SPIFF-JPEG-to-JFIF conversion program to recover the original JFIF data from the SPIFF file without performing any type of data conversions.
This technique, however, has the disadvantage of violating the JFIF specification by including a JFIF APP0 marker that does not immediately follow the SOI marker. While many JFIF encoders may not care about this violation, it is possible that some JFIF decoders will.
JFIF uses APP0 markers to embed ancillary information directly within a raw JPEG data stream. A primary purpose of SPIFF-JPEG is to replace the function of JFIF's APP0 markers with SPIFF's header and directory information. While it is valid to store JPEG data in a SPIFF file that contains APP0 markers, it does not follow the spirit of the SPIFF format and design.
The goal is to convert all ancillary information in the JFIF file to the equivalent SPIFF information structures and store only a raw JPEG data stream in the SPIFF-JPEG file. The following guidelines are offered:
1. Convert all APPn data to the equivalent SPIFF header information. Table 6 lists the JFIF and JPEG information that must be used to initialize the fields of the SPIFF header.
Note that the value of ColorSpace will be 3, if the JPEG number of color components value is 3; or 8, if the same JPEG marker data is 1. These ColorSpace values correspond to the two color spaces allowed by the JFIF spec. Non-JFIF, raw JPEG data files may convert to other SPIFF color-space codes; for example, Adobe Photoshop can emit CMYK JPEG files.
2. Convert any thumbnail data stored in the JFIF APP0 marker segment or extension marker segment to SPIFF thumbnail directory entries.
3. Convert JPEG comment blocks (COM markers) to SPIFF text entries. Here, we run into the black art of JFIF-to-SPIFF-JPEG conversion. The JPEG standard does not define the type of information stored in a JPEG comment block. It can be anything from your name to the Gettysburg Address to a field of NULL values; it's up to the user and/or application creating the JPEG data stream. The storage of generic blocks of unspecified or miscellaneous text is not directly supported by the SPIFF format. The content of a SPIFF directory entry is somewhat rigidly defined to be the name of the SPIFF file creator, image title, image description, copyright information, and so on. A converter may choose to store any JPEG comment block information it finds in the SPIFF image-description directory entry, but this may not always be the proper place for it. Another possible solution is to store miscellaneous text in application-specific directory entries, as provided by the SPIFF specification. This, however, will effectively hide the comment block information from every SPIFF reader that doesn't recognize your application-specific directory tag (which is probably most of them). Your last-and possibly best-solution is to simply leave the comment block in the JPEG data stream. At least this will make it possible for programs that read JPEG comment blocks to retrieve the information.
4. Do not write out any indirect directory entries. Indirect data requires random access of the SPIFF file. Many JPEG decoders read the data file strictly serially and cannot conveniently handle indirect data. You should expect that a significant percentage of SPIFF readers will simply ignore any indirect directory entries.
Note that storing indirect data is not harmful. All JFIF readers should stop at the End of Image (EOI) JPEG marker at the end of the compressed data and should never reach the indirect data. The recommendation against indirect data is made just to accommodate simple-minded SPIFF decoders that don't handle indirect entries.
Will SPIFF eventually replace JFIF? Only if the majority of people storing JPEG-compressed images find SPIFF's additional features useful. Organizations interested in using standardized, international data formats will adopt SPIFF. And SPIFF certainly offers a standard format in which to store JBIG images and offers an alternative to CCITT Group 3, Group 4, and CALS for storing MR and MMR facsimile data. And thanks to the IJG, free SPIFF-JPEG code will be available.
Digital Compression and Coding of Continuous-tone Still Images: Extensions, ITU-T T.84|ISO/IEC 10918-3, Draft International Standard, 18 April 1995.
Hamilton, Eric. JPEG File Interchange Format. Milpitas, CA: C-Cube Microsystems, 1992.
Murray, James D. and William vanRyper. Encyclopedia of Graphics File Formats, second edition. Sebastopol, CA: O'Reilly & Associates, 1994.
Value Color Space of Image
0 Bilevel
1 YCbCr, ITU-R BT 709, video
2 No color space specified
3 YCbCr, ITU-R BT 601-1, RGB
4 YCbCr, ITU-R BT 601-1, video
5 Reserved
6 Reserved
7 Reserved
8 Grayscale
9 PhotoYCC
10 RGB
11 CMY
12 CMYK
13 YCCK
14 CIELab
Figure 2: SPIFF header.
typedef struct _SpiffHeader
{
DWORD MagicNumber; /* Primary identification value (FFD8FFE8h) */
WORD HeaderLength; /* Header length (not including MagicNumber)*/
CHAR Identifier[6]; /* Secondary ID value ("SPIFF\0") */
WORD Version; /* SPIFF version */
BYTE ProfileId; /* Application profile */
BYTE NumberComponents; /* Number of color components */
DWORD ImageHeight /* Number of lines in image */
DWORD ImageWidth; /* Number of samples per line */
BYTE ColorSpace; /* Color space used by image data */
BYTE BitsPerSample; /* Number of bits per sample */
BYTE CompressionType; /* Type of data compression used */
BYTE ResolutionUnits; /* Type of resolution units */
DWORD VerticalResolution; /* Vertical resolution */
DWORD HorizontalResolution; /* Horizontal resolution */
} SPIFFHEADER;
.
Table 2: Values of CompressionType header field.
Value Compression Method of Image Data
0 Uncompressed, interleaved, 8 bits per sample
1 Modified Huffman
2 Modified READ
3 Modified Modified READ
4 JBIG
5 JPEG
Table 3: EntryTag bit values.
Value Standards Organization
0 SPIFF specification definition.
1-3 ISO/IEC and common text generic standards.
4 ISO application standards.
5 ITU-T recommendations.
6 National standards bodies.
7 Application specific.
Figure 3: SPIFF directory entry.
typedef struct _SpiffDirectoryEntry
{
WORD EntryMagic; /* Directory entry magic number (FFE8h) */
WORD EntryLength; /* Length of entry */
DWORD EntryTag; /* Identification value of the entry */
} SPIFFDIRECTORYENTRY;
Table 4: Standard SPIFF directory entries.
Name Use EntryTag Multiple Entries
End Of Directory End of directory marker 1 No
Transfer Characteristics Gamma Correction 2 No
Component Registration Location of components 3 No
Image Orientation Rotated, flipped 4 No
Thumbnail Image Thumbnail header 5 Yes
Image Title Text 6 Yes
Image Description Text 7 Yes
Time Stamp ISO 8601 standard time 8 No
and date stamp
Version Number Image version number 9 Yes
Creator Identification Text 10 Yes
Protection Indicator Level of authenticity 11 No
Copyright Information Text 12 Yes
Contact Information Text 13 Yes
Tile Index Pointer to tiles 14 No
Scan Index Pointers to scans 15 No
Set Reference Relationship to other files 16 Yes
Table 5: SPIFF application profiles.
Value Application Profile
0 No profile
1 Continuous-tone base profile
Compression is 5 (JPEG)
ColorSpace is 3 (YCbCr RGB) or 8 (grayscale)
No Image Orientation directory entry
No indirect directory data allowed
Image data is encoded with baseline JPEG as a single scan with
interleaved components
2 Continuous-tone progressive profile
Continuous-tone base profile
Support for DCT progressive mode JPEG with spectral selection and
full progressive
3 Bilevel facsimile profile
Support per ITU-T T.4 (Modified Huffman and Modified READ),
ITU-T T.6 (Modified Modified READ), or
ITU-T T.82|ISO/IEC 11544 (JBIG)
4 Continuous-tone facsimile profile
8 bits per sample (12 bits optional)
2:1 Chrominance subsampling in each direction (no subsampling optional)
CIE Standard Illuminant D50 (custom illuminant optional)
Default gamut range (custom gamut range optional)
Table 6: Equivalent SPIFF header fields and JPEG/JFIF information
Description SPIFF Header Field JFIF or JPEG Marker Code
Number of color components NumberComponents SOF0 (components)
Number of bits per sample BitsPerSample SOF0 (sample precision)
Number of lines in image ImageHeight SOF0 (height)
Number of samples per line ImageWidth SOF0 (width)
Color space ColorSpace SOF0 (components)
Type of resolution units ResolutionUnits APP0 (units)
Vertical resolution VerticalResolution APP0 (Ydensity)
Horizontal resolution HorizontalResolution APP0 (Xdensity)
.