How JPEG Encodes Image Width and Height

In digital image processing, extracting dimensions from a JPEG file without decoding pixel data relies on parsing specific metadata stored in the file stream. JPEG stores its structural information in segments marked by distinct two-byte codes, where the image dimensions—specifically height and width—reside within a Start of Frame (SOF) marker segment. This article explains how to locate the SOF marker and decode the binary values that define an image's pixel dimensions.

Locating the Start of Frame (SOF) Marker

JPEG files consist of a sequence of chunks called "marker segments." Every marker begins with the byte 0xFF followed by a single byte identifying the marker type.

Dimensions are contained within the Start of Frame (SOFn) header. Depending on the encoding process used (such as baseline, progressive, or lossless), the SOF marker byte varies between 0xC0 and 0xCF (excluding 0xC4, 0xC8, and 0xCC, which are used for table definitions). The two most common markers are:

A parser scans past the Start of Image (SOI) marker (0xFF 0xD8) and skips preceding markers (such as APPn or DQT segments by reading their length fields) until it encounters an SOFn marker.

Byte Layout of the SOF Segment

Once the SOF marker is identified, the frame header follows a strict byte-level structure:

  1. Marker Code (2 bytes): 0xFF followed by the SOF identifier (e.g., 0xC0).
  2. Frame Header Length (2 bytes): The total length of the SOF segment (excluding the initial 0xFF 0xXX marker itself).
  3. Data Precision (1 byte): Bits per sample (commonly 8 for standard JPEG images, sometimes 12).
  4. Image Height (2 bytes): The number of lines in the image.
  5. Image Width (2 bytes): The number of samples per line.
  6. Number of Components (1 byte): Color channels (e.g., 1 for grayscale, 3 for YCbCr, 4 for CMYK).
  7. Component Specification Parameters (3 bytes per component): Component IDs and sampling factors.

Decoding the Height and Width Values

Both the height and width are stored as 16-bit unsigned integers in big-endian (network byte order) format, occupying four consecutive bytes immediately following the 1-byte data precision field:

For example, consider the following raw hex sequence representing an SOF0 segment:

FF C0 00 11 08 04 38 07 80 03 ...

Edge Cases: The DNL Marker

Standard JPEG specifications require the width to be greater than zero. If the height field is encoded as 0x00 0x00, the actual height was unknown at the start of frame generation. In this rare scenario, the height is defined later in the stream by a Define Number of Lines (DNL) marker (0xFF 0xDC), which appears immediately after the first scan data. Modern JPEG files almost universally populate the height directly inside the SOF header.