← Blog

CCITT G4 — fax compression for bitonal scans

G4 codes runs of black/white pixels using offsets from the previous row Bitonal scan, 2550 × 3300 (Letter, 300 DPI) raw 1-bit ~1.05 MB deflate ~150 KB CCITT G3 1D ~85 KB CCITT G3 2D ~62 KB CCITT G4 (T.6) ~45 KB JBIG2 (lossless) ~30 KB G4 is the office-scanner default G4 algorithm summary For each transition (black↔white) on this row, find the matching transition on the previous row. Encode horizontal distance to that transition in a Huffman-like variable-length code. Long runs of identical rows compress to almost nothing — whitespace areas of a printed page take ~1 bit each.

If you've ever wondered why a scanned 30-page contract is 200 KB while a single phone photo of the same content is 2 MB, the answer is CCITT compression. G3 and G4 — algorithms originally designed for fax machines — exploit a property unique to bitonal scans: pixels are either black or white, with very long runs of the same color. Office scanners use these algorithms to produce remarkably compact bitonal documents.

What "bitonal" means

Bitonal = 1 bit per pixel. Black or white, no gray. Typical for:

A 2550 × 3300 (Letter at 300 DPI) bitonal image is 8,415,000 pixels. At 1 bit per pixel, the raw data is 1.05 MB before any compression. Deflate (zlib) reduces that to ~150 KB. CCITT G4 reduces it to ~45 KB.

How G4 works

G4 (officially ITU-T Recommendation T.6) is a 2-dimensional run-length encoding tuned for printed-page scans. The key insight: most rows of pixels are very similar to the row above. A character's left edge appears in roughly the same column from one row to the next as long as you're inside that character.

For each row, G4 encodes the positions of black-to-white and white-to-black transitions relative to the corresponding transitions on the previous row. If the transitions match exactly (very common in long horizontal strokes), the encoding is one symbol that means "vertical, same position". If they differ by ±3 pixels or less, the encoding is one of seven short codes. Larger differences fall back to absolute run-length coding.

The resulting bitstream is Huffman-encoded with code tables from the spec. The whole algorithm is small (a few hundred lines of C), fast, and produces typically 3–5× better compression than zlib on bitonal scan content.

G3 vs G4 — and why G3 still appears

G3 (T.4) was the original fax compression standard. It has two flavors: 1D (each row encoded independently as run lengths) and 2D-K (every K-th row independent, intervening rows encoded relative). G3 1D is least efficient but most error-resistant, important for noisy phone-line fax transmissions; G4 (which is essentially G3 2D with K=∞) is most efficient but a single bit error corrupts the rest of the image.

For TIFF files stored on disk, G4 is universal. G3 occasionally appears in legacy archives or in TIFFs received directly from old fax modems.

How PDF handles CCITT

PDF supports both G3 and G4 natively via the /CCITTFaxDecode filter, with parameters describing exactly which variant:

/Filter /CCITTFaxDecode
/DecodeParms <<
  /K -1                 % -1 = pure G4; 0 = G3 1D; positive = G3 2D-K
  /Columns 2550
  /Rows 3300
  /BlackIs1 false       % true if 1 bits represent black (TIFF convention varies)
  /EndOfLine false      % T.6 G4 doesn't have EOL markers
>>

The PDF reader decodes the bitstream and produces a 1-bit-per-pixel image. Color space is usually /DeviceGray with bit depth 1.

CCITT input through TIFF2PDF

The ideal converter would extract the compressed CCITT bitstream from a G4 TIFF's strips, concatenate them, and embed the result as a PDF Image XObject with /Filter /CCITTFaxDecode. No re-decode, byte-for-byte preservation, output size matching input.

Specialist archival software can do this true pass-through. The general-purpose conversion pipeline behind TIFF2PDF instead decodes the bitonal pixels and re-embeds them with a PDF-native filter, typically Flate-compressed grayscale — the trade-off is broader compatibility with unusual TIFF variants. The output is correct visually but typically 2–3× larger than a true pass-through would produce: a 1.5 MB G4 TIFF becomes a 3–5 MB PDF.

If you need maximum size efficiency for archival, look for software that explicitly mentions "CCITT pass-through" or "TIFF G4 preserved in PDF" — common in document-management and records-archival products. The result preserves CCITT G4 inside the PDF and matches input size within a few percent.

The "BlackIs1" subtlety

TIFF can store bitonal data in either polarity:

Old fax-derived TIFFs use WhiteIsZero; most modern bitonal TIFFs use BlackIsZero. Any converter that emits PDFs with /CCITTFaxDecode needs to know which polarity the source uses and set /BlackIs1 accordingly — get it wrong and every page comes out inverted (black text becomes white on black background). With a decode-and-re-embed approach, the polarity is handled inside the decode step and isn't a concern downstream.

When CCITT is the wrong choice

CCITT G3/G4 is bitonal only — there is no concept of color or grayscale. If your input TIFF is grayscale or color (even if mostly black-and-white text), it can't use CCITT. The compression is then deflate or LZW.

For grayscale-but-mostly-bitonal scans (signed contracts where the signature is grayscale, the text is bitonal-look-alike), the right pre-processing step is to threshold to bitonal first, accepting the loss of grayscale signature anti-aliasing. Or use JBIG2, a more sophisticated bitonal codec that's about 30% smaller than G4. PDF supports JBIG2 via /Filter /JBIG2Decode; producing JBIG2 output requires a dedicated encoder run as part of an OCR pipeline.