How to tell if an image was edited or AI-generated

What a JPEG, PNG, WebP or HEIC records about its own history, where to read it, and what each finding does and does not prove.

Proofs of address arrive as phone photos. Payslips arrive as screenshots. An image file is not just pixels. It is a container that records what captured it, what encoded it, when, and often what touched it afterwards. Most of that survives editing, because most tools do not bother to clean it up, and some generators and editors write their names into the file on purpose. This page walks the checks by hand, then shows the automated version.

One caveat governs everything below: a match is strong, an absence is nothing. Image metadata is trivially removable, and the most common remover is not a forger. It is WhatsApp. A file that says Adobe Photoshop was in Photoshop; a file that says nothing has merely said nothing. Tamperlens reports risk signals, not verdicts, and so should you.

Every rung below the first survives metadata stripping, and the last one is the only rung that ever settles the document itself.
THE ORDER TO READ AN IMAGE IN 1 Read what the file says about itself EXIF capture block · Software · XMP · C2PA 2 Test that claim against the bytes encoding · quantisation tables · the four timestamps 3 Read the container's shape chunk CRCs · IEND · FFD9 · trailing bytes 4 Ask the sender for the original file straight from the camera roll, not through a chat app 5 Go to the issuer the only step that settles the document rather than the file A match at step 1 is strong evidence. An absence at step 1 is nothing at all, which is exactly why steps 2 and 3 exist.

1. Read the EXIF block

The cheapest check. A direct capture from a phone or camera carries an EXIF block naming the device (Make, Model), the exposure (shutter, aperture, ISO), the capture time, and often the lens and GPS position. On a Mac, Preview → Tools → Show Inspector; anywhere else, ExifTool reads every field:

Dump everything the file says about itself

exiftool -a -G photo.jpg

For a document photograph: a utility bill on a kitchen table. A coherent capture block is what the file's own story predicts. The checks below are all comparisons against that story: a file claiming to be a phone photo should be encoded like one, timed like one, and shaped like one.

2. Look for editor fingerprints

Editors announce themselves in the Software tag, in the XMP CreatorTool, or, for Photoshop specifically, in a dedicated APP13/Photoshop IRB segment that survives even some metadata strippers. Strings like Adobe Photoshop 26.0, GIMP, Pixelmator, Canva or Snapseed mean the file passed through that tool.

"Passed through" is the honest claim, and the strongest claim available. A crop for size, a rotation for orientation and a forged salary figure all leave this same trace. The editor fingerprint tells you the file's rendered content is not necessarily what left the camera; it cannot tell you which pixels changed or why. Treat it as a fact worth explaining, exactly like a consumer editor in a PDF's Producer field.

3. Look for AI-generator traces

Generated images frequently say so, in three places worth checking by hand:

  • PNG text chunks. Stable Diffusion front-ends write their entire prompt and sampler settings into the file, Automatic1111 under a parameters key, ComfyUI as a workflow JSON. exiftool shows these as ordinary tags.
  • Software and XMP fields. Midjourney, DALL·E, Adobe Firefly and others name themselves the way an editor would.
  • C2PA / Content Credentials. A cryptographically signed provenance manifest, increasingly attached by both generators and cameras. Verify one at contentcredentials.org. A valid C2PA manifest is the closest an image gets to a PDF's digital signature: a checkable statement of where the file came from.
All three of these find files that announced their own generation. None of them can certify that an image was not generated.
THREE PLACES A GENERATED IMAGE NAMES ITSELF PNG text chunks the whole prompt and the sampler settings, written by the front-end that made it Software and XMP fields the generator naming itself exactly the way an ordinary editor names itself A C2PA manifest the only one that is signed, and so the only one whose claim can be checked ONE ACTION REMOVES ALL THREE Screenshot the image, or re-save it through any tool that strips metadata, and every box above is empty. The presence of a trace is a finding. The absence of all three is the ordinary state of any file that travelled.

The asymmetry from the callout applies with full force. These traces find files that announced their generation; a screenshot of a generated image, or a re-save through any stripping tool, removes all three. No metadata check can certify that an image is not AI-generated. Anyone claiming otherwise is selling something.

4. Compare the four timestamps

An image can record time in four independent places: when the shutter fired (DateTimeOriginal), when the frame was digitised (DateTimeDigitized (equal to the first on any direct capture), when the file was last written (ModifyDate), and the GPS receiver's UTC timestamp), which comes from satellites, not from the device clock, and cannot be set in a settings menu.

Three of the four come from a clock the device owner can set. The GPS timestamp comes from satellites, which is why it is the one worth comparing the others against.
FIELD WHAT SETS IT SETTABLE BY THE HOLDER? DateTimeOriginal the device clock, when the shutter fired yes DateTimeDigitized the same clock: equal to the above on a direct capture yes ModifyDate whatever machine last wrote the file yes GPSDateStamp / GPSTimeStamp the satellite signal, in UTC no So the strong comparison is capture time against satellite time. The weaker ones still matter: an impossible ordering means at least one stamp was written by something other than the camera pipeline.

The GPS block is present only when location was recorded, and it is stripped along with everything else by any tool that cleans metadata. Its strength is that it cannot be quietly adjusted, not that it is usually there.

  • ModifyDate later than DateTimeOriginal means the file was written again after capture: an edit or a re-encode, of unknown content.
  • DateTimeOriginal disagreeing with the GPS timestamp by more than clock drift is the strong version: the satellite time is the one a device owner cannot quietly adjust before "capturing" a backdated document.
  • Capture time after file time, or dates in the future . Impossible orderings mean at least one timestamp was set by something other than the camera pipeline.

5. Check the encoding against the claimed origin

The pixels' wrapper betrays re-encoding even when every metadata field has been cleaned. Three checks need no decoder:

Each row is a claim the file makes about where it came from, contradicted by the wrapper the pixels actually arrived in.
WHAT THE FILE CLAIMS WHAT THE WRAPPER SAYS WHAT THAT ESTABLISHES a direct camera capture cameras emit baseline JPEG progressive JPEG a software encoding written by an export or optimiser step, not a camera a named camera maker in the EXIF Make tag libjpeg quant tables a different encoder family re-encoded after it left the camera a phone photo no phone hands you one a WebP container a delivery format passed through a site, a CDN or a messaging app None needs a decoder. Each tests the file's story against the bytes carrying it, and a re-encode is not itself an edit.
  • Progressive JPEG claiming to be a camera capture. Cameras emit baseline JPEG; progressive encoding comes from software : web export pipelines, editors, optimisers.
  • Quantisation tables that don't match the claimed maker. A JPEG's quality tables identify the encoder family. A file whose EXIF says Canon but whose tables are textbook libjpeg was re-encoded after it left the camera.
  • The format itself. No camera or phone hands the user a WebP. A WebP arriving as evidence has been through a conversion step (a website, a CDN, a messaging app), and that conversion is itself the finding: the bytes you hold are not the bytes that were captured.

6. Check the container's structure

Everything above reads metadata. Claims the file makes about itself, which a competent forger simply deletes. The container's shape is different: a forger has to get it right by accident. A PNG ends at its IEND chunk; anything after it was appended by something. Chunk lengths and CRCs must agree; a JPEG must close with its FFD9 end-of-image marker. On the command line:

A PNG ends at its IEND chunk. Anything after it was put there by something that was not the encoder.
A PNG, AS A RUN OF BYTES signature IHDR IDAT · IDAT · IDAT IEND trailing bytes the format's declared end everything past here is extra WHY THIS ONE SURVIVES STRIPPING Shape is not a claim the file makes, so there is nothing to delete. Chunk lengths and CRCs have to agree, and a JPEG has to close with FFD9.

Bytes after the declared end of a PNG

$ python3 -c "d=open('doc.png','rb').read(); i=d.rfind(b'IEND')+8; print(len(d)-i, 'trailing bytes')"
2048 trailing bytes

Trailing payloads, broken checksums and truncated containers each mean the file was assembled or damaged by something other than a normal encoder. Worth explaining before the document is trusted.

7. What missing metadata means

Less than you want it to. Every major messaging platform strips EXIF on upload as a privacy measure; social networks, CDNs and screenshot tools do the same. A bare file is therefore the normal condition for anything that travelled through WhatsApp, which, for documents submitted by customers in much of the world, is most files. Absence moves the question ("why does a fresh camera capture carry nothing at all?"), it never answers it. The useful posture: metadata present is evidence to read; metadata absent is a reason to rely on the structural and encoding checks above, which survive stripping.

Automating it

Tamperlens runs exactly these checks on every JPEG, PNG, WebP, HEIC and AVIF, the same engine, endpoint and report as for PDFs. Nine image signal families cover generator metadata, editor fingerprints, dimension and encoding mismatches, recompression traces, date anomalies, missing metadata, container structure, C2PA provenance and capture context, each with a severity, a plain-English detail and the raw evidence behind it.

The engine reads structures the encoder wrote; it deliberately decodes no pixels, executes nothing, and calls no third-party service. Deterministic: the same bytes produce the same report. Files are parsed in memory and never written to disk.

Read step 1 on a real photograph

Open the sample photo: an ordinary phone capture with its EXIF block, its timestamps and its encoding laid out field by field, which is what the first rung of the ladder above looks like when there is nothing wrong. No account, no upload, no quota. Your own photo or screenshot goes into the same page: it is sent over HTTPS, parsed in memory and never written to disk. When you want it in your pipeline, an API key with 50 documents a month is free: see the API quickstart.

Tamperlens reports risk signals, not authenticity verdicts. Signals can have benign causes; combine them with your own decision logic.

Related reading