Binary Image Format

How BMP, PNG, and JPEG Store Pixel Data at the Binary Level

Every Image File Starts With a Magic Number

In my years working with image processing and file recovery, the first thing I look at when analyzing a binary image file is its magic number. Every image file format begins with a specific sequence of bytes that identifies the format. For JPEG, the magic number is FF D8 FF. For PNG, it is 89 50 4E 47 0D 0A 1A 0A (which includes "PNG" in ASCII). For BMP, it is 42 4D ("BM" in ASCII, short for "BitMap"). These signatures are critical for file type identification when extensions are misleading or missing. I've used them countless times to recover images from corrupted drives.

Try this: Take any image file and open it in a hex editor. Look at the first 8 bytes — you will see the magic number of the format. For PNG, you can literally read "PNG" in the binary data.

BMP File Structure: Magic Number and Header

The BMP format, short for Windows Bitmap, is the simplest binary image format to understand. A BMP file begins with the magic number 42 4D (hexadecimal for "BM", the ASCII characters "B" and "M"). This two-byte signature is immediately followed by a 14-byte BITMAPFILEHEADER containing the file size, reserved fields, and the offset where pixel data starts. The signature 0x424D in binary is 01000010 01001101. In my experience working with low-level image data, BMP is the best teaching format because every byte in the file directly maps to something meaningful. There's no compression, no complex encoding — just headers and raw pixel data.

BMP DIB Header and Pixel Array

After the 14-byte file header comes the DIB (Device Independent Bitmap) header. The most common version is BITMAPINFOHEADER, which is exactly 40 bytes. It contains the image width (4 bytes), height (4 bytes), color planes (2 bytes, always 1), bits per pixel (2 bytes), compression method (4 bytes), and several other fields. For a BMP with 24 bits per pixel, the pixel data starts right after the headers at byte offset 54. The pixel array is stored bottom-up — the first row of pixel data in the file is the bottom row of the image. Each pixel occupies 3 bytes in BGR order (Blue, Green, Red), not RGB. I've debugged many BMP reading issues caused by forgetting that BGR byte order.

PNG: 8-Byte Signature and Chunk Structure

PNG (Portable Network Graphics) uses a much more sophisticated binary structure than BMP. The file starts with an 8-byte signature: 89 50 4E 47 0D 0A 1A 0A. The byte 89 (binary 10001001) sets the high bit to ensure the file is treated as binary, not text. The next three bytes are the ASCII characters "PNG". The remaining bytes detect common file transfer problems. After the signature, the file is a sequence of chunks. Each chunk has a 4-byte length field, a 4-byte chunk type (ASCII, like "IHDR", "IDAT", "IEND"), the chunk data itself, and a 4-byte CRC32 checksum. I've worked extensively with PNG at the binary level, and the chunk-based architecture makes it highly extensible — readers can safely skip unknown chunk types.

PNG Key Chunks: IHDR, IDAT, and IEND

The three essential PNG chunks are IHDR (image header), IDAT (image data), and IEND (image end). The IHDR chunk is always first and contains the image width (4 bytes), height (4 bytes), bit depth (1 byte), color type (1 byte), compression method (1 byte), filter method (1 byte), and interlace method (1 byte). The IDAT chunk contains the compressed pixel data, which has been filtered (using Sub, Up, Average, or Paeth filters) and then compressed with DEFLATE. Multiple IDAT chunks can appear in sequence and must be concatenated. The IEND chunk is always last and has no data (length = 0). In binary, the IEND chunk literally reads 00 00 00 00 49 45 4E 44 AE 42 60 82 — zero length, the type "IEND", and the CRC32 checksum.

Key insight: PNG achieves lossless compression by applying a filter to each scanline that subtracts predicted pixel values, reducing data entropy. The filtered data is then compressed with DEFLATE, the same algorithm used by ZIP files.

JPEG Markers: FF D8 Start and FF D9 End

JPEG uses a marker-based binary structure entirely different from BMP and PNG. Every marker starts with byte FF followed by a marker type byte. The file begins with SOI (Start of Image): FF D8. Then comes a sequence of marker segments: APP0 (FF E0) contains the JFIF header with version, density, and thumbnail; DQT (FF DB) contains quantization tables; SOF0 (FF C0) contains the image dimensions and number of components; DHT (FF C4) contains Huffman tables; SOS (FF DA) marks the start of the compressed scan data. The file ends with EOI (End of Image): FF D9. In my experience debugging corrupt JPEG files, these markers are lifesavers — you can find where data starts and ends even if parts are damaged.

JPEG Quantization and Compressed Data

The JPEG compression magic happens after the SOS marker. The image is divided into 8 × 8 pixel blocks, and each block is transformed using the Discrete Cosine Transform (DCT). The resulting frequency coefficients are divided by values from the quantization table (stored in the DQT marker segment) and rounded to integers. High-frequency coefficients (fine detail) get divided by larger numbers, often becoming zero. The quantized coefficients are then run-length encoded and Huffman coded using the tables from the DHT marker segment. At quality setting 75, many coefficients become zero, and the bitstream efficiently stores runs of zeros. The JPEG binary stream is a continuous sequence of Huffman-coded bits with no byte alignment until the EOI marker. This is why JPEG is not a format where you can easily inspect pixel values in a hex editor — the data is highly transformed and compressed.

Binary Format Comparison: Same Image, Three Formats

Here's how a 1920 × 1080 image differs at the binary level across formats:

  • BMP (24-bit): 14-byte file header + 40-byte DIB header + 6,220,800 bytes of raw BGR pixel data. Total: about 6.22 MB. Every pixel can be read directly from the file. No compression, no magic, no ambiguity.
  • PNG: 8-byte signature + IHDR chunk (25 bytes) + one or more IDAT chunks (compressed filtered scanlines) + IEND chunk (12 bytes). Total: typically 0.5 to 3 MB depending on image complexity. Lossless — the binary decompresses to exactly the original pixel values.
  • JPEG: SOI marker + segment markers with tables + SOS marker + Huffman-coded DCT coefficient bitstream + EOI marker. Total: typically 100 KB to 1 MB. Lossy — the binary represents quantized frequency data, not pixel values.

I've used this comparison in presentations many times. Understanding the binary structure helps me choose the right format for every project. BMP for teaching and direct pixel access, PNG for lossless web graphics and screenshots, JPEG for photographs where file size matters more than pixel-perfect accuracy.

Reading Image Format Signatures in Practice

When I encounter an unknown file, these are the binary signatures I check first:

  • FF D8 FF at offset 0 = JPEG
  • 89 50 4E 47 at offset 0 = PNG
  • 42 4D at offset 0 = BMP ("BM")
  • 49 49 2A 00 or 4D 4D 00 2A = TIFF (little-endian or big-endian)
  • 47 49 46 38 at offset 0 = GIF ("GIF8")

Knowing these first 2-4 bytes of the most common image formats is enough to identify almost any image file you encounter. The binary signatures work regardless of file extension, making them essential for digital forensics, data recovery, and file validation.

Try It Yourself

Open the Binary Code Decoder in a new tab and enter some binary patterns to see the results instantly. All conversions happen in your browser — no data is sent to any server.