BookNotesSlidesP-sets Syllabusdraft · v0.2.49.1
◀▲⌂▶
💬Comments welcome. To leave a note, select any text and click the note / highlight button that pops up — or open the panel with the tab at the top-right (‹). Notes are visible only inside our private review group.
💡 In a hurry? Jump to this chapter’s 2 big lessons ↓

8.11 File formats and compression⧉

An image file stores pixel values together with enough structure to decode them, and often metadata about color and capture. At this boundary, check orientation, channel order, bit depth, color interpretation, and compression. A correctly decoded array can still be misinterpreted or carry artifacts from earlier processing.

Compression exploits predictable data, and lossy photographic compression also exploits visual tolerance. JPEG makes these choices concrete: separate luma and chroma, transform local structure into coefficients, quantize, then encode the remaining symbols. The savings and the visible errors depend on image content and viewing conditions.

JPEG is useful here because it makes perceptual design concrete. Separate controls for chroma resolution and spatial-frequency quantization turn observations about vision into adjustable numerical choices. They can be tested against file size and visible error. Perception does not determine one universally correct table, but it supplies engineering constraints that can be measured and compared.

8.11.1 The big picture: none, lossless, lossy⧉

Storing an image costs bits, and there are exactly three philosophies about how to spend them.

The first is to write the pixels directly, one number after another, and read them back the same way. This is uncompressed storage: a plain dump of the array. It is simple, exact, and fast, but it is large: a 12-megapixel photo at 8 bits per channel is roughly 36 megabytes, and a folder of them fills a disk in a hurry. This is what a memory-resident image, or a no-frills format, amounts to.

The second philosophy is lossless compression: shrink the file, but promise that what comes back out is bit-for-bit identical to what went in. This is possible because real images are not random noise. Neighboring pixels tend to be similar, large regions are nearly constant, edges repeat, and that statistical redundancy can be squeezed out and then perfectly restored, the way a ZIP archive shrinks text without losing a character. PNG and (usually) TIFF live here. Lossless is the right call when every pixel is sacred: a mask, a depth map, scientific data, or an image you will edit and re-save many times.

Lossy compression permits decoded samples to differ from the input in exchange for a smaller file. JPEG commonly uses this approach. HEIF, WebP, AVIF, and JPEG XL support different codecs or modes, including lossless options; the extension alone does not establish whether information was discarded. Keep a suitable master when later editing or measurement matters.

Lossless compression preserves the samples presented to the codec. It cannot undo an earlier conversion to a palette, a lower bit depth, or another color space. Lossy compression can trade exact reconstruction for rate, using visual quality or another task-specific objective.

8.11.2 Data versus metadata: EXIF⧉

Image metadata describes dimensions, sample types, orientation, and color interpretation. Filesystem properties such as path and modification time are separate and can change when a file is copied. Capture metadata records how and when the image was made; it is not part of the pixel array.

Cameras write a far richer layer of capture metadata into a standardized block, the exchangeable image file format (EXIF), a set of tagged fields stored alongside the pixels. This is where you find the ISO, shutter speed, aperture, and focal length the photo was taken at, along with the lens model, whether the flash fired, a timestamp, and often a Global Positioning System (GPS) location. For a computational photographer it is the physical record of the shot, and later chapters on exposure and noise read these fields directly; for a photo library it is what sorts by date, plots shots on a map, or auto-rotates a sideways frame. GPS is the double edge: handy for organizing a library, and a real privacy concern when you post a file without thinking. Sorted by capture time, years of phone photographs become a detailed diary: you can watch children grow frame by frame, or find exactly where you stood and which lens you used on a trip a decade ago. The same fields can pinpoint your home in a file posted straight from the camera; exiftool reads and strips them.

The quickest way to see what that block actually holds is to open one of your own files and look (Figure 8.11.1).

fig-exif-explorer
Figure 8.11.1. What your photo says about you (interactive). Drop in a JPEG, TIFF or raw file and read the EXIF block it carries: the camera and lens, the exposure the camera chose, the moment it was taken to the second, the orientation flag, sometimes the firmware version and a serial number unique to your body, and, if the camera had a position fix, a latitude and longitude good to a few meters, which the figure pins on a world map. The file is read and parsed in the page, so nothing is uploaded anywhere, which is worth knowing given what the block contains. The whole format is on show: a JPEG is a chain of segments, EXIF rides in APP1 and is itself a small TIFF file, whose directories are listed here separately, IFD0 for the image, the Exif sub-IFD for how it was shot, the GPS IFD for where. It is also the argument of this section made concrete: the same metadata that sorts a library by date and rotates a sideways frame is the metadata that tells a stranger where you live. (Coastline: Natural Earth 1:110m, public domain, simplified.)
EXIF is frustrating in practice

Treat EXIF as a hint, not a measurement: two things go wrong. First, coverage is incomplete and inconsistent, not every camera writes every field, and the exact set and formatting differ from maker to maker, so any code that reads EXIF has to tolerate missing and oddly-encoded values. Second, and more dangerous, some numbers are only approximate. The recorded ISO and shutter speed in particular are routinely rounded to tidy nominal labels and are not radiometrically correct: they will not let you reconstruct the true exposure, or compare two frames' light, to the precision the digits imply. Do not treat EXIF capture values as calibrated measurements.

Orientation can include mirroring as well as rotation. Determine whether the decoder already applied it; apply it once, and update or remove the tag when saving transformed pixels. Color interpretation is separate: ICC profiles are not simply EXIF fields and can describe more than primaries plus a gamma. A color-managed conversion uses the source and destination profiles; embedding a profile alone does not ensure identical appearance on every display.

💡 What metadata should travel with an image

A recurring wish in this book: beyond the basics above, a sane image representation would carry exactly the things a bare array can never imply on its own:

Metadata support varies: DNG, for example, can carry a noise profile. Such metadata must be updated when processing changes the values and their uncertainty. Yet the algorithms that come later silently need this provenance: white balance and HDR want the encoding and color space, denoising wants the noise parameters (see edge-preserving filtering), deblurring wants the PSF. The plain view, then, is that an image is its pixels plus this provenance, and a representation that drops it forces every later stage to guess.

8.11.3 PNG: the format we read from⧉

PNG is convenient for exercises because its compression preserves the stored samples exactly. It supports grayscale, palette, and RGB images, optional transparency, and integer sample depths up to 16 bits. Saving a floating-point array as an 8-bit PNG still requires a potentially lossy conversion before compression.

PNG filters scanlines to form predictable residual bytes, then compresses them with DEFLATE. Inspect the decoded shape and dtype: a library may expand palette indices, add alpha, or return grayscale. If transparency is unwanted, decide whether to discard alpha or composite against a chosen background; those operations produce different RGB images.

8.11.4 JPEG: compression by perception⧉

The common baseline JPEG path Wallace 1991 combines lossy quantization with lossless entropy coding. Color conversion and optional subsampling commonly precede the block codec. JPEG also specifies modes beyond this baseline; the following description concerns the usual 8-bit photographic workflow.

fig-jpeg-pipeline
Figure 8.11.2. The JPEG encoding pipeline, left to right. (1) Color transform: RGB → opponent YCbCr, separating luma Y from two chroma channels Cb, Cr. (2) Chroma subsampling: shrink Cb and Cr to half resolution (4:2:0), exploiting the eye's low color acuity. (3) Block DCT: split each channel into 8×8 blocks and transform each to spatial-frequency coefficients. (4) Quantization: divide the coefficients by a quality-dependent table that crushes high frequencies hardest; this is the only lossy step. (5) Entropy coding: losslessly pack the (mostly zero) quantized coefficients in a smart order. Decoding runs the same chain in reverse.

The starting observation, lifted straight from Chapter 3.4, Spatial and temporal vision, is that human vision is not uniform. The contrast sensitivity function (CSF) tells us our sensitivity to detail falls off at high spatial frequencies: we simply cannot resolve fine texture as well as coarse structure. And our sensitivity to color detail is far lower still than our sensitivity to brightness detail: the eye has sharp acuity for luminance and surprisingly coarse acuity for hue. JPEG's entire strategy is to match the number of bits to what the eye can actually use: many bits for the brightness structure we see keenly, few for the color detail and the high frequencies we barely register. The five stages below implement that allocation.

Stage 1: opponent color⧉

A common color JPEG converts encoded RGB to $Y'CbCr$. The weighted sum $Y'$ is luma, while $Cb$ and $Cr$ represent scaled blue-minus-luma and red-minus-luma differences. This provides separate controls over brightness-like and chromatic information. It is not the retina's exact opponent transform. The ideal affine transform is invertible; finite-precision conversion and clipping can introduce small losses.

The transformed RGB gamut occupies only part of the nominal $Y'CbCr$ box. Values outside that region are outside the original RGB gamut, not necessarily physically impossible colors. Code-range occupancy depends on the transform and range convention, so a universal percentage is misleading.

We follow one 32×32 image through all five stages of Figure 8.11.3, starting with this conversion (stage color).

fig-jpeg-stages
Figure 8.11.3, stage 1. Stage 1 of a baseline JPEG encoder on a 32×32 image. Top: the input R′G′B′ and its three planes, luma Y′ and the chroma differences Cb and Cr, each drawn in gray, where 128 means no chroma. Below: the selected 8×8 region of each plane as numbers, and the selected pixel's conversion with the JFIF coefficients before and after rounding to 8 bits. Click any plane or any cell to move the pixel; the menu picks the input, four crops of photographs from this chapter and two synthetic images. The red hibiscus is bright in Cr and nearly flat in Cb; the red disk on teal is drawn at almost the same luma as its background, so its edge nearly vanishes from Y′. Rounding the planes to 8 bits already costs a little: R′G′B′ rebuilt from them measures about 53 dB PSNR. Photographs: Frédo Durand.

Stage 2: chroma subsampling⧉

With color now isolated in Cb and Cr, JPEG makes its first lossy reduction, with little perceptual cost. Because our acuity for color detail is so low, JPEG simply throws away half or three-quarters of the color resolution: it shrinks the two chroma channels while keeping luma at full resolution. This is chroma subsampling, written in a J:a:b notation that counts how many chroma samples survive in a $4\times2$ block of pixels (Figure 8.11.4). 4:4:4 keeps full color resolution (no subsampling at all). 4:2:2 halves the horizontal color resolution. 4:2:0, the usual JPEG choice, halves it in both directions (one color sample for every $2\times2$ block of luma, a 75% cut in color data) and visibility depends on the image and viewing scale.

Lower chromatic acuity often makes chroma subsampling acceptable for photographs. It can be conspicuous on colored text, saturated edges, and fine color patterns. Low-pass filter before decimation and specify chroma sample positions; simply dropping samples aliases, and inconsistent siting shifts color boundaries.

fig-chroma-subsampling
Figure 8.11.4. Chroma subsampling notation, on a 4×2 block of pixels. 4:4:4: every pixel keeps its own Cb and Cr (full color resolution). 4:2:2: chroma sampled every other column (half the horizontal color resolution). 4:2:0 (JPEG's usual choice): one chroma sample per 2×2 block, color resolution halved in both directions, a 75% reduction. Luma (Y) is always kept at full resolution. Because the eye's color acuity is low, even 4:2:0 is nearly invisible; try the same on luma and edges smear.

Figure 8.11.5 compares luma and chroma coarsening on a photograph. Inspect saturated boundaries as well as ordinary texture. Full-resolution luma cannot preserve an isoluminant color edge whose structure lies entirely in chroma.

fig-chroma-subsampling-photo
Figure 8.11.5. Chroma subsampling on a real photo (a saturated red hibiscus against green leaves). Left, the original. Center, the image reconstructed after subsampling: choose 4:2:2 (half the chroma) or 4:2:0 (a quarter) and the red petals bleed only a hair across the sharp edge, because the full-resolution luma Y′ holds every contour. Right, the Y′, Cb, and Cr planes, so you can watch which one is coarsened. Now flip coarsen to luma: the same block-averaging applied to Y′ instead smears every edge and the image falls apart. The perceptual bet behind chroma subsampling, made visible: resolution belongs in luma, never chroma.

On the small image of Figure 8.11.3, stage subsample, the same step removes three quarters of the chroma samples. It is also the only loss left at the top of the quality scale: at quality 100, on every input of the figure, the decoded image is exactly as far from the original as 4:2:0 subsampling alone makes it.

fig-jpeg-stages
Figure 8.11.3, stage 2. Stage 2, 4:2:0 subsampling. The Cb and Cr planes in the strip are now 16×16: each sample is the average of a 2×2 cell of the full-resolution plane, shown below as numbers for the selected 8×8 region, with the arithmetic for the selected cell. Top right, the image rebuilt from full-resolution Y′ and the 4:2:0 chroma upsampled with libjpeg's triangle filter. The image keeps 1,536 of its 3,072 samples. On crops this small, each pixel stands for many pixels of the photograph, so the loss is larger than on a full-size image: the rebuilt hibiscus measures 26.3 dB PSNR, the egret 31.8 dB, and the red disk on teal 19.9 dB, because its edge and its one-pixel line live only in chroma and spread over their neighbors.

Stage 3: the 8×8 DCT⧉

Now JPEG turns to the high-frequency half of the CSF story, and to do that it must work in terms of spatial frequency rather than raw pixels. It splits each channel into small $8\times8$ pixel blocks and transforms each block with the discrete cosine transform (DCT). The DCT is a close relative of the Fourier transform we study in Chapter 6.3, Fourier: it re-expresses the 64 pixel values of a block as 64 coefficients, each the weight of a particular 2-D cosine basis pattern, from a flat constant (the block's constant component, the "DC" term), through gentle ramps, up to fine checkerboards at the highest frequencies (Figure 8.11.6). No information is lost yet; the DCT is just a change of representation, perfectly invertible, like rewriting the same number in a different base.

For a level-shifted block $b_{xy}$ (subtract 128 for 8-bit input), an orthonormal convention is

$$C_{uv}=\alpha_u\alpha_v\sum_{x,y=0}^{7}b_{xy}\cos\frac{(2x+1)u\pi}{16}\cos\frac{(2y+1)v\pi}{16},$$

with $\alpha_0=1/\sqrt8$ and $\alpha_k=1/2$ for $k>0$. Then $C_{00}=8\,\operatorname{mean}(b)$, not the mean itself. For positive table entries $Q_{uv}$,

$$q_{uv}=\operatorname{round}(C_{uv}/Q_{uv}),\qquad \hat C_{uv}=Q_{uv}q_{uv}.$$

The ideal coefficient error is bounded by $Q_{uv}/2$, subject to the rounding convention. Integer DCT implementations can add numerical differences.

Why bother? Because frequency is exactly the axis the CSF is organized along. Once a block is expressed as frequency coefficients, JPEG can treat low and high frequencies differently: keep the coarse structure the eye sees keenly, crush the fine detail it barely registers. And there is a statistical bonus: on real photographs, most of a block's energy piles into the low-frequency coefficients (smooth regions dominate), so the high-frequency coefficients are usually small to begin with. The DCT thus concentrates the signal into a few coefficients, which is what makes the next two stages so devastatingly effective. (Why $8\times8$ and not the whole image? A small block keeps the transform cheap and lets the encoder adapt to local content, but it is also the source of JPEG's signature artifacts, as we will see.)

fig-dct-basis
Figure 8.11.6. The 64 basis patterns of the 8×8 DCT, arranged in an 8×8 grid. Top-left is the constant (DC) pattern, the block's average. Moving right increases horizontal frequency; moving down increases vertical frequency; the bottom-right corner is the finest checkerboard. Any 8×8 image block is a weighted sum of these 64 patterns, and the DCT computes those 64 weights. Photographs put most of their energy in the top-left (low-frequency) patterns, which is exactly what makes the following quantization step so effective.

Figure 8.11.3, stage dct, applies the transform to one block of the small image. On a block of a petal, the six lowest-frequency coefficients hold 77% of the block's energy; on a smooth ramp, more than 99%.

fig-jpeg-stages
Figure 8.11.3, stage 3. Stage 3, the 8×8 DCT of one block. Left, the block's samples after the level shift, $b_{xy}$ = sample − 128; center, its 64 coefficients $C_{uv}$, red positive and blue negative, rounded for display, each beside a thumbnail of the basis function it weights (gray is zero), with $u$ increasing to the right and $v$ downward as in the formula above; right, the share of the block's energy held by the first k coefficients in zig-zag order. The readout checks that $C_{00}$ is 8 times the block's mean. Click a block of Y′ in the strip, or of the 16×16 Cb or Cr plane, to transform that one instead. On the hibiscus petal block selected at first, the six lowest coefficients hold 77% of the energy; on the smooth ramp, more than 99%.

Stage 4: quantization, the lossy step⧉

This is another stage where JPEG throws information away, and where its quality knob lives. Each of the 64 DCT coefficients is divided by a corresponding entry in a quantization table and rounded to the nearest integer. The rounding is the lossy act: once you have rounded 7.4 to 7, you cannot recover the original: that fractional detail is gone forever. The quantization table decides which coefficients to round coarsely and which to keep fine.

Quantization tables usually assign larger steps to high-frequency and chroma coefficients. Perceptual sensitivity motivates that allocation, but a table is not a direct universal measurement of the CSF. Image statistics, display size, viewing distance, and encoder design also matter.

An encoder's quality setting commonly scales quantization tables, and may also change subsampling or other decisions. Quality numbers are not standardized across encoders. The decoder reads the actual tables from the file; it multiplies quantized integers by those entries before the inverse transform.

An orthonormal DCT preserves total squared error. If pixel rounding errors were independent with equal variance, their coefficient errors would have equal variance too. A single quantized basis pattern does not satisfy that statistical assumption in general: deterministic rounding, clipping, basis normalization, and amplitude affect the result. Thus an 8-bit block does not guarantee eight useful bits in every individual coefficient.

fig-dct-8bit-roundtrip
Figure 8.11.7. The systematic round-trip: a single 8×8 DCT basis coefficient is rendered into pixels, those pixels are quantized to 8 bits, and the coefficient is read back out. For a low-, mid-, and high-frequency basis, the recovered coefficient is plotted against the intended one, a fine staircase that preserves roughly eight bits, independent of frequency. Because the DCT is an orthonormal rotation, the pixels' rounding noise lands equally on every coefficient, so there is no per-frequency precision penalty from 8-bit storage itself, a useful contrast with the quantization table, which keeps high frequencies coarse for perceptual reasons, not storage ones.

The DCT rounding experiment separates two reasons a high-frequency coefficient may be small or imprecise. Pixel quantization limits the input measurements; JPEG’s coefficient quantization makes a further, deliberate allocation of error. Under an independent equal-variance rounding-noise model, an orthonormal transform does not inherently make its high-frequency coordinates noisier than its low-frequency ones. Coarser high-frequency quantization is therefore a coding choice motivated by statistics and visibility, not a requirement that a pixel array can only represent low frequencies.

Figure 8.11.3, stage quantize, quantizes that block at a quality we choose.

fig-jpeg-stages
Figure 8.11.3, stage 4. Stage 4, quantization. For the selected block: its coefficients $C_{uv}$; the table $Q_{uv}$ at the chosen quality, the luminance or chrominance table of Annex K scaled by the IJG rule (at quality 50 it is the Annex K table itself); the integers $q_{uv}=\operatorname{round}(C_{uv}/Q_{uv})$ that the file stores, zeros shaded green; and the error of the decoded block, in gray levels. Top right, the whole decoded image. Drag the quality slider. At 50, 43 of the 64 integers of the hibiscus petal block are zero and the decoded image measures 21.9 dB PSNR. At 100 every table entry is 1, each coefficient survives to within half a unit, and the PSNR, 26.3 dB, is what the subsampling of stage 2 left.

Stage 5: entropy coding⧉

In baseline JPEG, the DC coefficient is coded as a difference from the preceding block's DC in that component. AC coefficients are scanned in zig-zag order; run lengths describe zeros before a nonzero value, and an end-of-block symbol omits trailing zeros. Huffman codes pack these symbols, with additional bits for coefficient amplitudes. This stage is lossless with respect to the quantized integers. Decoding reconstructs those integers, dequantizes, applies the inverse DCT, and performs the necessary color upsampling and conversion.

The transform and scan order prepare the data for lossless coding. After quantization, many high-frequency AC coefficients are zero. Scanning roughly from lower to higher frequencies tends to move long zero runs toward the end of the sequence, where an end-of-block symbol can replace them. Neighboring blocks also often have similar averages, which makes differences between DC coefficients economical to encode. The entropy coder benefits from this predictable structure. It cannot restore information already removed by quantization, but it need not lose anything more.

Figure 8.11.3, stage entropy, counts the bits of the small image symbol by symbol. At this size the coded scan is only a small part of a real file: at quality 50 the hibiscus crop takes 843 bytes, 626 of them headers and tables, so the file is about 3.6 times smaller than the raw pixels while the scan alone is 14 times smaller. Compression ratios quoted for JPEG assume images large enough for that fixed overhead not to matter.

fig-jpeg-stages
Figure 8.11.3, stage 5. Stage 5, entropy coding. The quantized block is read in zig-zag order (the gray path), and the zeros that end it (shaded) become a single end-of-block symbol, EOB, where the outlined cell begins. The DC coefficient is coded as its difference from the previous block's DC, DC Δ, and each nonzero AC coefficient as a pair (zeros before it, its value). Every symbol carries its cost in bits: its Huffman code from the typical tables of Annex K plus the amplitude bits. Below, the totals for the block and for the image, in bits per pixel and as a ratio against 24 bits per pixel. They count the entropy-coded data only, and on the photographs they agree with libjpeg's to about 1%. At quality 50 the hibiscus takes 1,730 bits, 1.69 bits per pixel, 14:1; a real 32×32 file adds about 620 bytes of headers and tables, more than the data itself.
💡 Big lesson

JPEG combines optional chroma subsampling and coefficient quantization with lossless coding. Perception helps allocate the loss, while signal statistics help encode what remains. Neither the transform nor entropy coding alone produces the large lossy savings.

Limitations and artifacts⧉

Baseline JPEG stores 8-bit component samples and can visibly block or ring at strong compression. Neither the file extension nor a high quality setting supplies the precision and scene-referred latitude of a suitable raw or floating-point master.

The two familiar artifacts come from different aspects of the representation. Each 8×8 block has its own quantized coefficients. Neighboring blocks can reconstruct different values at their shared boundary, revealing the block grid. Within a block, a sharp edge needs several spatial-frequency components; changing those components can create ripples near the edge. Sharpening the decoded image can amplify both the block discontinuities and the ripples.

fig-jpeg-artifacts
Figure 8.11.8. JPEG artifacts at low quality. Left: the original. Center: a high-quality JPEG, visually indistinguishable. Right: a low-quality JPEG showing the two signature artifacts: blocking (the 8×8 grid surfacing as a quilt of seams in smooth regions, because each block is quantized independently) and ringing (spurious ripples hugging sharp edges and text, from discarding the high frequencies an edge needs). Insets zoom a flat gradient and a hard edge to make each artifact obvious.

The clean test edge of Figure 8.11.8 isolates the two artifacts; Figure 8.11.9 shows them where you actually meet them: on a real photographic edge. Save a photo with a hard, high-contrast boundary (a white egret against dark foliage) at low quality, zoom in, and overlay the encoder's $8\times8$ grid: the grid surfaces as flat seams across the smooth bright region (blocking), and faint ripples cling to the high-contrast edge (ringing). These are exactly the fingerprints a careless sharpening filter will then magnify.

fig-jpeg-artifacts-photo
Figure 8.11.9. JPEG blocking and ringing on a real photographic edge. Left: the whole photo saved at quality 10 (with its tiny file size), the crop region boxed. Center: a zoom of the original, a clean curved edge where the bright bird meets dark foliage. Right: the same crop from the q=10 file, with the 8×8 block grid overlaid; blocking shows as flat patches and seams across the smooth bright area, and ringing as bright/dark ripples hugging the edge. The same artifacts as the synthetic test, on real content.

The trade-off is clearest as a sweep (Figure 8.11.10): save the same photo across a range of quality settings and watch the file size and the damage move together. The file shrinks several-fold, and the degradation marches in step: near-invisible at high quality, a softening of fine detail through the middle, then unmistakable blocking and color bleed at the bottom. This is the tradeoff behind the quality slider: the same knob trades measurable bits against just-noticeable damage.

fig-jpeg-quality-levels
Figure 8.11.10. JPEG quality versus degradation. The same photograph saved at a sweep of quality settings (here 85 → 40 → 20 → 10 → 5), each panel a zoomed crop with the whole image's file size beneath it. As the quality knob, and the file, shrink, the artifacts grow: fine detail softens, the 8×8 blocking grid surfaces in smooth regions, and color bleed creeps along edges. The first panel is near-indistinguishable from the original at a fraction of the size; the last is tiny but visibly broken.

Repeated decoding and encoding can change an image, but the error need not grow at a fixed rate or monotonically. Some unchanged settings and codecs settle quickly; other combinations drift or cycle. Color conversion, subsampling, rounding, edits, and block-grid shifts all affect the loop. Keeping a master and exporting from it avoids relying on such stability.

fig-jpeg-generation-loss
Figure 8.11.11. JPEG generation loss: open, save, repeat. The image is JPEG-encoded and decoded back to 8-bit pixels $N$ times (the browser's real codec; nothing written to disk), at a quality you choose. Each round-trip re-quantizes the block-DCT coefficients. At a fixed quality most of the damage (blocking, edge ringing, color drift) happens in the first few generations, and then it tends to settle, because re-quantizing coefficients that are already quantized changes little; changing the quality, cropping or editing between saves starts the loss again. Near quality 100 a re-save is almost idempotent. The lesson: keep a lossless master, export to JPEG once.

Editing between saves changes the samples being quantized. Darkening and brightening through an 8-bit JPEG adds both sample rounding and coefficient quantization. Compare the final result with an edit performed at higher precision followed by one export.

fig-exposure-jpeg-roundtrip
Figure 8.11.12. Iterated exposure edits through a JPEG: the repeated-quantization experiment of Chapter 8.1, Image representation plus generation loss. From an 8-bit image, darken to the chosen exposure in N steps and brighten back in N more; every step scales the exposure in float, re-quantizes to 8 bits, and applies a JPEG-like model: an 8×8 block DCT, quantization at the chosen quality and the inverse DCT, run on R, G and B separately. It is not a full codec: there is no conversion to YCbCr and no chroma subsampling. Input | middle (darkened) | final (back to full). Both kinds of damage can compound: 8-bit banding in the smooth regions, blocking and ringing on the 8×8 grid. Lower the quality or add EV to make them worse; more round-trips do not always mean more error. Hover a panel for a pixel-level closeup; a smooth image (sky, sunset) shows the two artifacts interacting most clearly.

A fixed coefficient quantizer is idempotent on its own reconstruction levels. A full decode/edit/encode pipeline includes other operations, so that property does not prove that the whole loop converges. Even a deterministic finite-state loop can enter a cycle.

The cited re-save experiment Krawetz, "How I Met Your Mother Through Photoshop" illustrates application-dependent drift. It does not by itself identify which processing step caused the drift; that requires the software version, settings, and decoder behavior.

Video 8.11.1. Video: An application-specific JPEG re-save experiment (discussed in Krawetz, "How I Met Your Mother Through Photoshop").

Use these demonstrations to inspect a particular codec loop, rather than as proof that all JPEG round-trips converge or that all drift comes from deblocking.

Video 8.11.2. Video: Repeated JPEG save/open with a codec and settings that stabilize in this example.

The format therefore affects how a later filter should be evaluated. A denoiser or sharpener applied to a camera JPEG is processing existing compression artifacts along with scene detail and sensor noise. Keep a lossless intermediate while developing a chain of edits so additional lossy encoding does not obscure which stage introduced an artifact.

Removing the artifacts: JPEG deblocking⧉

A decoder that only inverts the DCT shows the blocks and the ringing. Deblocking, or compression-artifact reduction, estimates a cleaner image from the same file. It has more to work with than an ordinary denoiser, because it knows exactly how the image was damaged. The file stores the quantization table, so for every block we know each integer coefficient $q_{uv}$ and its step $Q_{uv}$. The original coefficient was rounded to $\hat C_{uv}=Q_{uv}\,q_{uv}$, so it lay somewhere in the interval

$$C_{uv}\in\big[\,Q_{uv}(q_{uv}-\tfrac12),\;Q_{uv}(q_{uv}+\tfrac12)\,\big].$$

Every image whose block DCTs fall inside these intervals would have produced the same file. The standard decoder picks the center of every interval, which is the one choice that ignores what images look like. Deblocking picks, among all the images consistent with the file, one that looks more like a photograph. The intervals form a convex set, the quantization constraint set, and the methods differ in the image model they use to choose inside it.

Filtering the block boundaries. The simplest methods smooth across the 8×8 grid only. A step between two blocks is suspicious when it is small compared with the quantization step, because quantization can create a step of that size from nothing; a large step is more likely a real edge and is left alone. Video codecs build this decision into the decoder: H.264 filters each block edge with a strength set by the quantization parameter and by thresholds on the steps across it List et al. 2003 (H.264 deblocking). There the filter is in the loop, since filtered frames serve as references for predicting the next ones (Chapter 30.2, Video compression and motion compensation). For a JPEG it is a choice of the viewer or of a later processing step.

Projecting back onto the file. Zakhor alternated two steps Zakhor 1992 (deblocking, POCS): a low-pass filter that removes the block edges, then a projection back onto the constraint set, which takes the DCT of every block and clamps each coefficient into its interval. Clamping undoes whatever part of the smoothing the file rules out, so the result keeps every edge the file can prove and loses the block edges it cannot. Yang, Galatsanos and Katsaggelos cast the same idea as regularized reconstruction, a smoothness penalty minimized under the constraint Yang, Galatsanos & Katsaggelos 1993. Consistency with the file is not closeness to the original, though. On a smooth image the projection gains several decibels; on a textured photograph it removes the block edges but lowers PSNR slightly after its first iteration, because the low-pass pushes the coefficients that carry texture all the way to the end of their interval nearer zero, further than the original values usually were (Figure 8.11.13).

Algorithm 8.11.1
deblock(decoded, q, Q, iterations):
    x = decoded
    repeat iterations times:
        x = smooth(x)                                   # the image model
        for each 8x8 block b of x:
            C = dct8(b)
            C = clamp(C, Q * (q - 0.5), Q * (q + 0.5))   # back into the file's intervals
            b = idct8(C)
    return x

The projection is exact only for the luma channel at full resolution. Chroma was also subsampled before its DCT, and the decoded pixels were rounded and clipped to 8 bits, so a real implementation projects the chroma at its own resolution and accepts that the constraint is approximate.

Treating the error as noise. If each coefficient's error is spread evenly over its interval, its variance is $Q_{uv}^2/12$, and since the DCT is orthonormal, the average error variance per pixel is

$$\sigma_q^2=\frac1{64}\sum_{u,v}\frac{Q_{uv}^2}{12}.$$

For the standard luminance table, $\sigma_q$ is about 19 gray levels at quality 50, 10 at quality 75 and 4 at quality 90. A denoiser told this noise level can then remove the artifacts. This is an overestimate, because most high-frequency coefficients were close to zero before quantization and their errors are smaller than the uniform model says. On the photograph of Figure 8.11.13 the actual error is six to nine times smaller than $\sigma_q$, and a denoiser does best when told 0.3 to 0.5 $\sigma_q$; told $\sigma_q$, it smears detail. The error is also not like sensor noise: it is correlated within each block and aligned with the grid. Methods that adapt the shape of their support to the image, such as the shape-adaptive DCT of Foi, Katkovnik and Egiazarian, smooth inside regions without crossing edges and remove blocking and ringing together Foi, Katkovnik & Egiazarian 2007 (SA-DCT).

Learned deblocking. Training pairs are easy to make: compress clean photographs at chosen qualities and train a network to undo it. AR-CNN was an early network for this Dong et al. 2015 (AR-CNN), and DnCNN handled Gaussian denoising and JPEG deblocking with one model Zhang et al. 2017 (DnCNN). Since the file carries its quantization table, the network does not have to guess how strong the compression was. FBCNN estimates a quality factor and lets the user change it, trading artifact removal against detail Jiang, Zhang & Timofte 2021 (FBCNN). A strong network can remove real texture along with the artifacts, and one trained with a perceptual or adversarial loss can invent detail that the file does not support. Projecting the output back onto the constraint set checks the second problem: whatever remains is at least consistent with the file.

Deblocking produces an estimate, not the original. The information the quantizer removed is gone, and a deblocked JPEG is the original only in the sense that it would compress to the same file. For measurements or forensic work we keep the decoded image and the file, and state which deblocking, if any, was applied.

Figure 8.11.13 runs the first three methods side by side on one photograph and checks each against the file's intervals.

fig-jpeg-deblocking
Figure 8.11.13. Deblocking a JPEG three ways, on a gray crop of an egret photograph coded in the browser. The codec is JPEG's luminance path for one plane at full resolution, with no color and no chroma subsampling, so the projection is exact: the orthonormal 8×8 DCT, the Annex K luminance table $T_{uv}$ scaled by the IJG rule ($S=\lfloor 5000/\text{quality}\rfloor$ below quality 50, $S=200-2\,\text{quality}$ from 50 up, $Q_{uv}=\lfloor (T_{uv}S+50)/100\rfloor$ kept between 1 and 255), rounding to $q_{uv}$, then $\hat C_{uv}=Q_{uv}q_{uv}$, the inverse DCT, and rounding and clipping to 8 bits. The boundary filter is H.264's strong filter for intra block edges List et al. 2003 (H.264 deblocking), with its thresholds taken from the table instead of H.264's: $\alpha=\sigma_q$ and $\beta=\sigma_q/2$ gray levels. The projection alternates a 3×3 binomial low-pass with the clamp of every block's coefficients into their intervals Zakhor 1992 (deblocking, POCS). The denoiser is non-local means (3×3 patches, 11×11 search) told the noise level $s\,\sigma_q$. PSNR is measured over the whole image against the original. Click a block in the overview or in a crop to probe it, and turn on the grid to see where the blocks fall. The lower panel plots the probe block's 64 coefficients in zig-zag order as $(C_{uv}-\hat C_{uv})/Q_{uv}$, so every interval is the same band from $-\tfrac12$ to $\tfrac12$ around the decoded value; click a column to read its numbers. At quality 20 the decoded error is 5.2 gray levels RMS where the uniform model gives $\sigma_q=47$, and the denoiser scores best near $s=0.4$; at $s=1$ it smears the eye. The projection's coefficients stay inside their intervals by construction, the boundary filter's nearly always, and about 2% of the denoiser's leave them. On this photograph the projection removes the block edges in the smooth regions, but it gains PSNR only after a single iteration at low quality and loses it with more: each pass of the low-pass pulls the coefficients that carry texture to the end of their interval nearer zero, which the file allows and the original rarely used. Photograph: Frédo Durand.

Making JPEG differentiable⧉

Rounding has zero derivative almost everywhere and is discontinuous at its thresholds. To optimize through JPEG, one can use a smooth approximation or a straight-through gradient estimate Shin & Song 2017 (DiffJPEG). A straight-through estimator changes the backward calculation, not the true derivative of rounding. Tensor implementations must also model value ranges, subsampling, and rounding conventions; validate the trained result with the actual deployment codec.

Differentiating through compression matters when training an upstream operation to survive it. Examples include a watermark that must remain detectable after JPEG, an enhancement that should not create fragile high-frequency detail, or a reconstruction network trained on compressed inputs. A surrogate backward pass can provide a useful optimization signal even though it is not the derivative of actual rounding. Evaluate the result through the real codec afterward; optimizing the surrogate alone can exploit discrepancies in the approximation.

8.11.5 RAW files: before the cooking⧉

Raw storage retains data from an earlier stage of the camera pipeline, leaving more reconstruction and rendering choices to the developer. The file may contain a CFA mosaic, demosaicked channels, or partly processed measurements. Raw capture offers latitude, but does not guarantee unmodified or losslessly stored sensor data.

To obtain scene-linear working values, decode the stored representation, apply any linearization table, subtract calibrated black levels, and use the metadata-defined scale. A linear DNG can already contain reconstructed channels. Check processing tags and profiles rather than assuming the extension establishes the numerical domain.

Here is the subtlety, stated plainly: "RAW" is not always purely raw. The name suggests an untouched sensor dump, but in practice most cameras pre-cook the data to some degree: subtracting the sensor's black level, correcting defective and hot pixels, sometimes applying lens-shading or vignetting correction or even mild denoising. Some "RAW" formats are themselves lossy-compressed or non-linearly encoded to save space. So RAW is best thought of as a spectrum of how cooked the data is, from a near-literal readout to something already partly processed, not a single guarantee of pristineness.

There is also a practical headache: RAW is largely proprietary. Nearly every manufacturer ships its own format and extension: Canon's (CR3 files), Nikon's (NEF files), Sony's (ARW files), and so on, each subtly different. That creates software and archival problems, since a format only one company supports may not be readable in thirty years. Adobe's Digital Negative (DNG) format is an open, documented, standardized RAW container meant to fix exactly this (its specification Adobe DNG specification is the reference here); many photographers convert their proprietary RAWs to DNG for safekeeping, and some cameras shoot DNG directly.

fig-xkcd-1683
Figure 8.11.14. xkcd #1683 "Digital Data," Randall Munroe, xkcd.com/1683 (CC BY-NC 2.5).

8.11.6 HDR formats: more than 8 bits⧉

HDR storage requires an encoding that covers the intended range at adequate precision. Floating point is useful for scene-linear processing, but not required for HDR display delivery: nonlinear integer encodings such as PQ or HLG can represent HDR signals. Conversely, additional integer bits do not automatically provide values above a chosen normalized white.

OpenEXR supports half and full floating-point channels, arbitrary additional channels, and both lossless and lossy compression. Radiance RGBE uses a shared exponent per pixel; it supports nonnegative high-range RGB but loses relative precision in a small channel beside a large one. TIFF can store integer or floating-point samples, subject to reader support. Choose both the sample representation and compression mode explicitly.

A gain-map file pairs a base rendering with metadata and an auxiliary image for adapting it to another display range. An SDR JPEG base remains viewable by older software, while compatible software can reconstruct an HDR rendering. Android Ultra HDR and ISO 21496-1 have distinct metadata conventions that can coexist; compatibility depends on the writer and reader, not just the .jpg extension.

8.11.7 Modern formats⧉

JPEG 2000 replaces the block DCT with wavelet coding, supporting reversible and irreversible paths and scalable access. It avoids baseline JPEG's fixed 8×8 blocking pattern but can still blur or ring at strong compression. Its use in specialized imaging does not imply universal application support. It found its homes where lossless modes, very large images and region-of-interest access matter more than browser support: it is the image codec of the Digital Cinema Package delivered to theaters, and common in medical (DICOM), archival, and satellite and geospatial imaging. On the web, patent uncertainty, encoder complexity and scant browser support kept it from displacing JPEG.

Modern formats add compression tools and capabilities such as alpha, animation, higher precision, or HDR. Compare the features of the chosen codec and profile with those supported by the receiving application.

Several formats reuse still-frame tools from video coding; others are designed specifically for images. Their compression is not interchangeable, and equal quality-slider values are not a meaningful comparison.

Modern codecs can use spatial prediction, adaptive transforms, and context-dependent entropy coding. JPEG already predicts DC coefficients, so it is inaccurate to say it has no prediction at all. A meaningful comparison fixes image dimensions, color interpretation, and output precision, then measures size, quality, encode/decode cost, and compatibility. Rankings can change with content, metric, and encoder settings.

fig-format-comparison
Figure 8.11.15. Modern image formats, measured. Every encode is our own, made with open-source encoders on our own test photographs (the interactive version lets you switch among four with different demands: the iguana's scales, the Prudential tower's fine window grid, a saturated hibiscus, and a child on the beach). Left: a detailed crop encoded at three matched file sizes (~28, ~48, ~80 KB in the columns) in each format (the rows), beside the lossless original. Each crop is labeled with its quality, measured as SSIM against the original, where 1.00 is identical and higher is better. Read down a column: the files are the same size, so only the format differs; read across a row: the same format gets a larger budget. JPEG breaks into 8×8 blocks and loses the scales; JPEG 2000 blurs instead of blocking; WebP is smoother but soft; the video-derived codecs (HEIC on HEVC, AVIF on AV1) and JPEG XL hold the texture and edges. The gap is widest at the smallest size (at ~28 KB, SSIM runs from 0.71 for JPEG to 0.91 for AVIF) and narrows as the budget grows. Right: the rate-distortion curves, quality (SSIM, higher is better) versus file size across quality settings, where up and to the left is better. The modern codecs reach a given quality at a fraction of JPEG's size, which is the whole reason they exist. (Quality is measured by SSIM, a standard if imperfect perceptual proxy; a different metric or test image shifts the exact numbers but not the ranking.) Interactive: pick one of four test images, then click any crop in the grid (rows are file size, columns are format) to open it full-size beside the lossless original, see a per-pixel SSIM-loss map, and light up its point on the rate-distortion plot.
fig-xkcd-2254
Figure 8.11.16. xkcd #2254 "JPEG2000," Randall Munroe, xkcd.com/2254 (CC BY-NC 2.5).

Learned compression replaces a fixed analysis transform with a network that maps pixels to latent coefficients. Quantize and entropy-code those coefficients, then reconstruct with a synthesis network. Training balances estimated rate and distortion, $\mathcal L=R+\lambda D$. The probability model must match the coded symbols; both sides need compatible model definitions and numerical behavior. A perceptual loss can favor plausible texture over pixel accuracy. JPEG AI has a published core coding standard, ISO/IEC 6048-1:2025; standardization does not imply universal decoder availability.

Intra prediction estimates a block from already reconstructed neighbors and codes the residual. A smooth continuation can then require few residual bits. Adaptive transform sizes change the tradeoff between compactly describing broad structure and following local boundaries. Context-dependent entropy coding assigns code lengths using nearby symbols or other available information. These tools improve the statistical description of the image; perceptual quantization decides which errors to permit. In-loop filtering, where a codec specifies it, also changes the reconstructed reference seen by subsequent predictions, so encoder and decoder must agree on it.

8.11.8 Other formats: TIFF and GIF⧉

TIFF is a flexible container whose compression may be lossless or lossy. It can store integer and floating-point samples and multiple images; application-specific Photoshop layers are not equivalent to universally supported TIFF pages. Test interchange with the destination software.

GIF losslessly compresses indexed pixels, with at most 256 entries in each color table and a transparent index rather than continuous alpha. Converting a photograph to that palette can lose substantial color information before compression. Animation can use different tables in different frames.

For processing, keep the original raw and use an intermediate format with sufficient precision and range. For delivery, choose a supported format, inspect the actual export, and retain its color metadata. When reporting compression results, name the encoder, version, settings, and metric.

💡 Big lesson

Match compression to the task. A visual metric can guide photographic delivery, but masks, measurements, and intermediate images may require exact samples. Lossless refers to the codec input, not to every conversion that preceded it.


Recap: big lessons of this chapter

💡 Big lesson

JPEG combines optional chroma subsampling and coefficient quantization with lossless coding. Perception helps allocate the loss, while signal statistics help encode what remains. Neither the transform nor entropy coding alone produces the large lossy savings.

💡 Big lesson

Match compression to the task. A visual metric can guide photographic delivery, but masks, measurements, and intermediate images may require exact samples. Lossless refers to the codec input, not to every conversion that preceded it.