Photo Forensics, Explained

After reading this you will know how four classic forensic tests work, what a positive result actually means, and why an original camera JPEG tells you far more than a screenshot ever will.

What these tests look for

A digital photo carries a history. The camera sensor recorded light, the camera firmware compressed it into a JPEG, and every later edit re-encoded some or all of the pixels. Each of those steps leaves a statistical trace. Photo forensics reads those traces to answer one question: does the whole image share a single, consistent history, or does one region behave differently from its surroundings?

Here is the hook. Suppose someone pastes a face from photo B into photo A and saves the result as a new JPEG. Both faces now look equally sharp to your eye. But the pasted face went through JPEG compression twice with different settings, while the background went through it once (plus the final save). That mismatch does not show on screen, yet it is measurable. The four tools on this page are four different ways to measure it.

ELA (Error Level Analysis)
Re-save the image at a known quality, then subtract. Regions that compress differently from their neighbors stand out.
JPEG ghost
Re-save at many qualities and measure the error at each. Dips reveal the quality the file was previously saved at.
Clone detection
Search for blocks that are near-duplicates of other blocks in the same image, the fingerprint of copy-paste retouching.
Quantization tables
The compression settings stored in the file header, which often identify the last software that wrote it.

When to use it, and when not to

These tests work on the compression history, so they need that history intact. An original JPEG straight off a camera or phone is the ideal input. A file that has been screenshotted, exported through Photoshop's "Save for Web", or run through a social network is much weaker evidence, because the last re-encode overwrites the earlier traces you wanted to see.

Concretely: a Facebook upload re-compresses at roughly quality 71 to 85 and strips most metadata. After that pass, an object pasted in at quality 90 no longer differs from the background at quality 90, because both were flattened to the same final quality. The signal you were hunting is gone.

None of these four tests produces a verdict. They produce leads. A clean ELA does not prove an image is authentic, and a bright ELA region does not prove tampering. Treat every result as a reason to look closer, not as an answer.

The math behind ELA and JPEG ghosts

JPEG compression works in 8 \times 8 pixel blocks. Each block is transformed and its coefficients are divided by a quantization step, then rounded. Rounding throws away detail, and that lost detail is the compression error. The key fact: once a block has been quantized at quality q, re-compressing it at that same quality changes it very little, because it is already snapped to the grid.

ELA saves the image again at a fixed quality (often 90 or 95) and computes the absolute difference per pixel:

E(x, y) = \left| I(x, y) - I_q(x, y) \right|

Here I is the current image, I_q is the same image re-saved at quality q, and E is the error map, usually brightened for viewing. A region already at quality q gives small E. A region that has never been at that quality gives larger, patchier E.

The JPEG ghost test generalizes this. Instead of one re-save quality, it sweeps many. For each candidate quality q it re-saves and measures the mean squared error against the current pixels:

D(q) = \frac{1}{N} \sum_{i=1}^{N} \left( I_i - I_{q,i} \right)^2

N is the pixel count, I_i is pixel i of the current image, and I_{q,i} is that pixel after re-saving at quality q. Plot D(q) against q and you get a curve with a local minimum at the quality the file was actually stored at, because re-saving at the original quality disturbs the pixels least. That dip is the "ghost".

A worked example with the demo image

The demo button loads the default sample: a JPEG that was saved once at quality 85, then had a small patch re-pasted at quality 70. Run the JPEG ghost sweep from quality 40 to 100 in steps of 5 and you get two features in the curve.

Reading the ghost curve

  1. The error D(q) is large at very low qualities (heavy re-compression damages the pixels) and falls as q rises.
  2. A clear local dip appears near q = 85, where D drops to about 18 in squared-error units. That is the background's storage quality.
  3. A second, shallower dip sits near q = 70 with D \approx 41. That is the pasted patch showing its earlier compression.
  4. Two dips at different qualities mean two compression histories in one file. That is your lead.
Two dips: the deep one at q = 85 is the whole image's save quality, the shallow one at q = 70 marks the pasted patch.

The numbers here are illustrative but internally consistent: the deepest point of the curve (18 at q = 85) is lower than the secondary dip (41 at q = 70), which is what you expect when most of the frame shares one history and only a small region carries a second one.

Try the effect of a second save

The ghost dip is easy to state and hard to picture until you move it yourself. The widget below lets you set an original save quality and watch the error curve form a dip exactly there.

If the original save quality is set to 85, the re-save error curve reaches its lowest value at quality 85 and rises on both sides. Lowering the original quality to 60 moves the single dip to quality 60. Adding a pasted region at a different quality introduces a second, shallower dip at that region's quality.

Clone detection and quantization tables

Clone detection tackles a different edit: removing an object by painting over it with a copy of nearby pixels. The tool divides the image into small overlapping blocks, computes a compact descriptor for each (for example the low-frequency transform coefficients), and looks for pairs of blocks whose descriptors are nearly identical but whose positions differ by more than a few pixels. When many such pairs share the same offset vector, that whole shifted region was almost certainly copied.

The trap is natural repetition. A clear blue sky has thousands of near-identical blocks, and so does a brick wall or a lawn. Those innocent matches scatter in all directions. A real clone shows up as a cluster of matches all pointing the same way, drawn as long parallel arrows between the source and the copy.

Quantization tables are simpler and often the fastest tell. The JPEG header stores the exact 64-value tables used to quantize the image. Cameras, phones and editors each use recognizable tables. If the file claims to be an untouched camera original but its tables match Photoshop's quality-8 preset, the file was last written by Photoshop. Reading the tables does not tell you what changed, only who saved it last. Combine that with the metadata from the EXIF Viewer & Remover and the picture gets clearer.

Reading results without fooling yourself

Every one of these tests has a characteristic false positive, and knowing them keeps you honest.

Signals versus their innocent look-alikes
TestReal tampering looks likeInnocent cause of the same look
ELASharp, object-shaped bright region on a quiet fieldHigh-contrast edges and text glow everywhere, naturally
JPEG ghostA second dip at a different qualityUniform single dip after a normal re-save
Clone detectionCluster of matches sharing one offsetSky, water and repeating textures match randomly
Quant tablesEditor signature on a claimed originalAny honest export through that same editor

Notice that ELA brightens edges by design. A busy image with lots of fine detail lights up all over, and that is normal, not evidence. The interesting signal is a bright patch shaped like a real object sitting against a calm background. For a strict pixel-by-pixel comparison of two versions of an image, the Image Diff tool is the right instrument instead.

Corroborate before you conclude. One suspicious ELA patch is weak. The same patch showing a second JPEG ghost dip, plus a clone cluster nearby, plus a quant table that names an editor, is a strong and consistent story.

Common mistakes

The most common error is running these tests on the wrong kind of file. A PNG has no JPEG quantization at all, so ghost analysis and quant tables tell you nothing. A screenshot is a fresh single-quality encode of whatever was on screen, which erases the layered history you needed. Before you spend effort, confirm you are holding an original JPEG.

The second mistake is over-reading ELA brightness. People see any bright area and call it a forgery. Brightness in ELA tracks local contrast and edge density as much as it tracks editing. Compare a suspect region to a region of similar texture elsewhere in the same photo, not to a flat area.

The third is ignoring scale in clone detection. If you set the block size too small, ordinary texture produces endless matches. Too large and you miss small patched spots. Reserve judgment for match clusters that share a single offset and span a meaningful area.

Related tools on this site

Forensics rarely rests on one measurement. These pages help you gather the surrounding facts:

Frequently asked questions

Can ELA prove a photo was edited?

No. ELA highlights regions whose compression error differs from their neighbors, which is a lead, not proof. Edges, text and textured areas glow innocently. Use ELA to decide where to look, then confirm with the ghost curve, clone detection and metadata.

Why do these tests fail on screenshots and social media images?

Both apply a fresh JPEG encode at a single quality over the entire frame. That last pass flattens the earlier, region-specific history the tests depend on. After a Facebook re-encode at roughly quality 71 to 85, a patch that was once distinct now matches the background.

What does a second dip in the JPEG ghost curve mean?

It means part of the image carries a different compression history from the rest. In the demo, the deep dip at quality 85 is the whole file, and the shallow dip at quality 70 is a region that was compressed at 70 before being pasted in.

Is my image uploaded anywhere?

No. All four tests run locally in your browser. The image bytes never leave your device.

Can clone detection be fooled?

Yes, in both directions. Flat sky and repeating textures create innocent matches, and an editor who blurs or rotates a cloned patch can defeat exact-block matching. Trust clusters of matches that share one offset vector and span a real object.