Binary Engineering•10 min read

Deep-Dive into the PNG Specification: IHDR, IDAT, tEXt Chunks, and Lossless Optimization

Understand the low-level binary layout of PNG files, 8-byte magic signatures, critical vs ancillary chunks, CRC-32 checksum calculation, and lossless byte-trimming techniques.

Kenji Takahashi
Binary & Compression Systems Specialist
Every digital engineer has opened, saved, or uploaded a PNG image, but few have inspected its internal binary architecture. A PNG file is not a monolithic blob; it is a meticulously structured sequence of typed binary packets called 'chunks'. Each chunk performs a dedicated duty: defining dimensions, mapping indexed palettes, housing DEFLATE-compressed pixel scanlines, or storing textual metadata. Mastering this binary anatomy is essential for web performance optimization, QA test generation, and building high-performance client-side image processing tools.

The 8-Byte Magic Signature & 4-Byte Chunk Framing Architecture

Every valid PNG datastream begins with an immutable 8-byte magic signature in hexadecimal: 89 50 4E 47 0D 0A 1A 0A. In ASCII, bytes 2 through 4 spell 'PNG'. The other bytes intentionally test for common transmission corruptions, such as 7-bit stripping, carriage-return/line-feed conversions, and file truncation.

Following the signature, all PNG data is packaged into discrete chunks. Every chunk follows an unyielding 4-part structure: a 4-byte Length field (big-endian 32-bit unsigned integer), a 4-byte Chunk Type code (ASCII letters), the Chunk Data payload, and a 4-byte CRC-32 checksum calculated across the type and payload.

Chunk capitalization is semantically meaningful: if the first letter is uppercase, the chunk is 'Critical' (the decoder must abort if unrecognized); if lowercase, it is 'Ancillary' (safe to ignore).

Field NameByte OffsetSizeTypeDescription
Length0 to 34 bytesUint32 (Big-Endian)Number of bytes in Data field (excluding Type, Length, CRC)
Chunk Type4 to 74 bytesASCII (4 chars)Chunk identifier (e.g. 'IHDR', 'IDAT', 'tEXt', 'IEND')
Chunk Data8 to N+7N bytesBinary payloadPayload bytes conforming to the specific chunk definition
CRC-32N+8 to N+114 bytesUint32 (Big-Endian)Cyclic Redundancy Checksum over Type and Data fields

Critical Chunks: IHDR, PLTE, IDAT, and IEND Byte Layout

A valid PNG requires at least three critical chunks in strict sequential order: IHDR, IDAT, and IEND (plus PLTE for indexed color modes).

IHDR (Image Header) must appear first immediately following the 8-byte signature. It contains exactly 13 bytes: 4 bytes for Width, 4 bytes for Height, 1 byte Bit Depth, 1 byte Color Type (0=Grayscale, 2=Truecolor RGB, 3=Indexed, 6=Truecolor with Alpha RGBA), 1 byte Compression method (0=Deflate), 1 byte Filter method (0=Adaptive), and 1 byte Interlace method (0=None, 1=Adam7).

IDAT contains the compressed image data stream. Multiple IDAT chunks can appear consecutively; the decoder concatenates their payloads into a single continuous zlib stream.

IEND marks the end of the image datastream. It has a length of 0 bytes, type 'IEND', and a constant CRC of 0xAE426082.

Ancillary Metadata Chunks: tEXt, zTXt, and Stripping Overhead

Ancillary chunks store non-essential data: color space profiles (sRGB, iCCP, cHRM), gamma correction (gAMA), physical pixel dimensions (pHYs), and uncompressed text strings (tEXt).

Popular graphics software (Photoshop, Figma, Illustrator) often injects extensive ancillary chunks: application build versions, XML metadata (XMP), embedded thumbnails, and ICC color profiles that frequently exceed 20 KB in weight.

For a 1 KB icon, 20 KB of ancillary metadata represents a 2,000% payload penalty. Lossless PNG optimization engines (such as Oxipng or OptiPNG) strip all non-essential ancillary chunks, preserving only the critical rendering stream.

2D Scanline Filtering: None, Sub, Up, Average, and Paeth Prediction

Before raw pixel rows are passed into the DEFLATE compressor, PNG applies a 2D filter to each scanline. This filter replaces absolute pixel values with difference (delta) values relative to neighboring pixels.

Each scanline is prepended with a 1-byte Filter Type: 0 (None), 1 (Sub - difference from left pixel), 2 (Up - difference from above pixel), 3 (Average of left and above), and 4 (Paeth - linear predictor choosing between left, above, and top-left).

Filtering dramatically flattens entropy. In a solid color image or horizontal gradient, Sub filtering turns every pixel in the row into [0, 0, 0, 0], which the LZ77 compressor can encode into a tiny run-length token.

Programmatic Chunk Assembly with JavaScript TypedArrays

Modern browsers can manipulate and assemble binary PNG streams directly in memory using JavaScript ArrayBuffer, DataView, and Uint8Array.

The code below demonstrates how to compute a CRC-32 checksum and construct an ancillary tEXt chunk in memory, enabling dynamic byte-padding or metadata injection without third-party libraries.

TYPESCRIPTExample Snippet
// CRC-32 table generator conforming to ISO 3309 / PNG specification
const CRC_TABLE = new Uint32Array(256);
for (let n = 0; n < 256; n++) {
  let c = n;
  for (let k = 0; k < 8; k++) {
    c = (c & 1) ? (0xedb88320 ^ (c >>> 1)) : (c >>> 1);
  }
  CRC_TABLE[n] = c >>> 0;
}

export function calculateCRC32(data: Uint8Array): number {
  let crc = 0xffffffff;
  for (let i = 0; i < data.length; i++) {
    crc = CRC_TABLE[(crc ^ data[i]) & 0xff] ^ (crc >>> 8);
  }
  return (crc ^ 0xffffffff) >>> 0;
}

export function buildPNGChunk(typeStr: string, payload: Uint8Array): Uint8Array {
  const typeBytes = new TextEncoder().encode(typeStr);
  const length = payload.length;
  const chunk = new Uint8Array(12 + length);
  const view = new DataView(chunk.buffer);

  // 1. Length (4 bytes, Big-Endian)
  view.setUint32(0, length, false);

  // 2. Chunk Type (4 bytes)
  chunk.set(typeBytes, 4);

  // 3. Chunk Payload (N bytes)
  chunk.set(payload, 8);

  // 4. Calculate CRC32 over Type + Payload
  const crcTarget = new Uint8Array(4 + length);
  crcTarget.set(typeBytes, 0);
  crcTarget.set(payload, 4);
  const crc = calculateCRC32(crcTarget);

  // 5. Append CRC (4 bytes, Big-Endian)
  view.setUint32(8 + length, crc, false);

  return chunk;
}

Summary & Key Takeaways

The PNG format's chunk-based binary architecture decouples critical pixel decoding from ancillary metadata. By understanding chunk framing, scanline delta filtering, and programmatic ArrayBuffer manipulation, developers can optimize assets for minimal latency and engineer robust client-side image pipelines.

Live Studio Tool

Exact File Size QA Generator

Generate byte-accurate test files from 1 KB to 50 MB using verified PNG chunk injection.

Open File Size Studio

Häufig gestellte Fragen

What happens if a PNG decoder encounters an unknown chunk?

If the chunk's first letter is lowercase (ancillary), the decoder safely ignores it and continues rendering. If the first letter is uppercase (critical), conforming decoders must abort and report an error.

Why does a 1x1 transparent PNG take 67 bytes rather than 4 bytes?

A 1x1 RGBA PNG requires the 8-byte PNG signature, 25-byte IHDR chunk, 22-byte IDAT chunk (housing zlib headers, scanline filter byte, and compressed pixels), and 12-byte IEND chunk, totaling 67 bytes.

Does removing color profiles (iCCP chunks) change how an image looks?

Yes. If an image was authored in Display P3 or Adobe RGB and the iCCP chunk is stripped without converting pixels to sRGB, standard browsers will display the image with dull, washed-out colors.

Neueste Leitfäden

View All Guides →