Photo metadata fidelity: samples, hashes & reproducible tests
Reproduce 36 metadata transformations across nine synthetic JPEG, PNG, WebP and classic TIFF fixtures. Download samples, outputs and payload hashes.
UpdatedVersion v1 · October 30, 2026 · Public evidence downloads are free; no account or download plan required.
Download the complete evidence kit
Download verification kit ZIP · Fixture manifest & source hashes · Full results JSON · Methods & licensing README
The kit includes sources, all four outputs, an originals ZIP, writer snapshots and a verification script. Images are tiny program-generated color grids with invented author, camera and GPS fields; no real people or capture locations are included.
Per-fixture results: payloads and pixels match
Each fixture runs author/camera/GPS edits, GPS-only removal, EXIF-only removal and the all-metadata scope. The two checks compare preserved image block bytes and decoded raw pixels. Expand the final column for output downloads and before/after fields.
| Source fixture | Image payload | Decoded pixels | Evidence |
|---|---|---|---|
| jpeg3 × 2 · 8 bit · 1 page(s)/frame(s) | 4 / 4 identical | 4 / 4 identical | Outputs, tags & SHA-256Source file SHA-256 Edit author & GPSFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": "Fidelity Edited",
"make": "Fidelity Camera",
"latitude": -33.5,
"longitude": 151.20000000000002
}
}GPS onlyFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": null,
"longitude": null
}
}EXIF onlyFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": null,
"make": null,
"latitude": null,
"longitude": null
}
}All-metadata scopeFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": null,
"make": null,
"latitude": null,
"longitude": null
}
} |
| png3 × 2 · 8 bit · 1 page(s)/frame(s) | 4 / 4 identical | 4 / 4 identical | Outputs, tags & SHA-256Source file SHA-256 Edit author & GPSFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": "Fidelity Edited",
"make": "Fidelity Camera",
"latitude": -33.5,
"longitude": 151.20000000000002
}
}GPS onlyFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": null,
"longitude": null
}
}EXIF onlyFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": null,
"make": null,
"latitude": null,
"longitude": null
}
}All-metadata scopeFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": null,
"make": null,
"latitude": null,
"longitude": null
}
} |
| webp-lossless3 × 2 · 8 bit · 1 page(s)/frame(s) | 4 / 4 identical | 4 / 4 identical | Outputs, tags & SHA-256Source file SHA-256 Edit author & GPSFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": "Fidelity Edited",
"make": "Fidelity Camera",
"latitude": -33.5,
"longitude": 151.20000000000002
}
}GPS onlyFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": null,
"longitude": null
}
}EXIF onlyFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": null,
"make": null,
"latitude": null,
"longitude": null
}
}All-metadata scopeFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": null,
"make": null,
"latitude": null,
"longitude": null
}
} |
| webp-lossy3 × 2 · 8 bit · 1 page(s)/frame(s) | 4 / 4 identical | 4 / 4 identical | Outputs, tags & SHA-256Source file SHA-256 Edit author & GPSFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": "Fidelity Edited",
"make": "Fidelity Camera",
"latitude": -33.5,
"longitude": 151.20000000000002
}
}GPS onlyFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": null,
"longitude": null
}
}EXIF onlyFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": null,
"make": null,
"latitude": null,
"longitude": null
}
}All-metadata scopeFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": null,
"make": null,
"latitude": null,
"longitude": null
}
} |
| tiff-lzw3 × 2 · 8 bit · 1 page(s)/frame(s) | 4 / 4 identical | 4 / 4 identical | Outputs, tags & SHA-256Source file SHA-256 Edit author & GPSFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": "Fidelity Edited",
"make": "Fidelity Camera",
"latitude": -33.5,
"longitude": 151.20000000000002
}
}GPS onlyFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": null,
"longitude": null
}
}EXIF onlyFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": null,
"make": null,
"latitude": null,
"longitude": null
}
}All-metadata scopeFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": null,
"make": null,
"latitude": null,
"longitude": null
}
} |
| tiff-deflate3 × 2 · 8 bit · 1 page(s)/frame(s) | 4 / 4 identical | 4 / 4 identical | Outputs, tags & SHA-256Source file SHA-256 Edit author & GPSFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": "Fidelity Edited",
"make": "Fidelity Camera",
"latitude": -33.5,
"longitude": 151.20000000000002
}
}GPS onlyFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": null,
"longitude": null
}
}EXIF onlyFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": null,
"make": null,
"latitude": null,
"longitude": null
}
}All-metadata scopeFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": null,
"make": null,
"latitude": null,
"longitude": null
}
} |
| tiff-16bit3 × 2 · 16 bit · 1 page(s)/frame(s) | 4 / 4 identical | 4 / 4 identical | Outputs, tags & SHA-256Source file SHA-256 Edit author & GPSFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": "Fidelity Edited",
"make": "Fidelity Camera",
"latitude": -33.5,
"longitude": 151.20000000000002
}
}GPS onlyFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": null,
"longitude": null
}
}EXIF onlyFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": null,
"make": null,
"latitude": null,
"longitude": null
}
}All-metadata scopeFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": null,
"make": null,
"latitude": null,
"longitude": null
}
} |
| tiff-multipage3 × 4 · 8 bit · 2 page(s)/frame(s) | 4 / 4 identical | 4 / 4 identical | Outputs, tags & SHA-256Source file SHA-256 Edit author & GPSFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": "Fidelity Edited",
"make": "Fidelity Camera",
"latitude": -33.5,
"longitude": 151.20000000000002
}
}GPS onlyFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": null,
"longitude": null
}
}EXIF onlyFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": null,
"make": null,
"latitude": null,
"longitude": null
}
}All-metadata scopeFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": null,
"make": null,
"latitude": null,
"longitude": null
}
} |
| webp-animated3 × 4 · 8 bit · 2 page(s)/frame(s) | 4 / 4 identical | 4 / 4 identical | Outputs, tags & SHA-256Source file SHA-256 Edit author & GPSFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": "Fidelity Edited",
"make": "Fidelity Camera",
"latitude": -33.5,
"longitude": 151.20000000000002
}
}GPS onlyFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": null,
"longitude": null
}
}EXIF onlyFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": null,
"make": null,
"latitude": null,
"longitude": null
}
}All-metadata scopeFile SHA-256 (changes when metadata changes) Preserved image payload SHA-256 (before = after) Decoded pixel SHA-256 (before = after) Asserted fields before → after {
"before": {
"artist": "Synthetic Author",
"make": "Synthetic Camera",
"latitude": 46.5,
"longitude": 11.8
},
"after": {
"artist": null,
"make": null,
"latitude": null,
"longitude": null
}
} |
Download originals ZIP — All nine entries use STORE and extract to the source SHA-256 hashes in the manifest. Originals retain their source test metadata; edits and removal are not applied.
Reproduce locally without a download plan
- Download and extract the complete kit. Use Node.js 22.13 or newer.
- Run the following in the extracted directory. Installation downloads the sharp decoder dependency; verification only reads local kit files and does not upload photos.
npm install npm run verify
- Expect PASS for 36 transformations and nine byte-identical STORE originals. The script regenerates outputs and compares their bytes with the published files, rather than trusting the results JSON.
- You can also import a source and a published output into the viewer to inspect author and GPS fields. Workspace image downloads keep their existing plan rules; evidence files here are directly available for free.
Published checks use sharp 0.35.4 / libvips 8.18.6. The kit pins sharp and prints the actual decoder versions; investigate any pixel differences on another decoder or platform separately.
What exactly is compared?
- JPEG: compressed scan bytes from the first SOS marker to EOF. PNG: image/animation and selected color chunks. WebP: compressed image, alpha, animation and ICC chunks. Classic TIFF: image strips or tiles for all pages.
- Decode using sharp separately from the metadata writer; compare raw pixels, dimensions, bit depth, page count and frame delays. The 16-bit sample is compared as ushort, without reducing to 8 bits.
- Assert expected author, camera and GPS changes. Edited author becomes Fidelity Edited; GPS-only retains author and clears coordinates; EXIF-only and all-metadata scope clear these test fields.
- The writer snapshot and JPEG/originals-ZIP functions come directly from this site version. Snapshot hashes identify the code tested; this is not third-party certification.
Coverage and limits
These are tiny reproducible synthetic tests, not a study of every camera file. Coverage includes lossy/lossless and animated WebP, LZW/Deflate TIFF, 16-bit and multipage TIFF. BigTIFF, all vendor extensions, malformed directories and large-file stress are excluded.
Fixtures have no orientation rotation and decoding uses no auto-orientation. Removing orientation from other JPEG, PNG or WebP files may change displayed rotation despite identical compressed image bytes. The app previews the first TIFF page; exported edits apply to all pages.
GPS-only removal leaves XMP/IPTC, filenames and visual location clues. The all-metadata scope retains decoding/color data and classic TIFF layout/orientation tags. This page only asserts the listed fields and offers no forensic anonymity guarantee.
For tutorial authors: how to cite
You may cite the results and methods with the fixture coverage and the description “product-authored synthetic test.” Fixture images and transformed copies are dedicated under CC0 1.0 for reuse in tutorials. Code and third-party libraries retain their own terms; see the kit README.
EXIF Studio. Metadata fidelity verification, v1 (2026-10-30). https://exifdesk.com/fidelity-verification#results
Stable citation anchors: #results · #method · #limits. To report a mismatch, include the fixture, operation and Node/decoder versions: support@exifdesk.com.
Inspect fields in the viewer → · Understand removal scopes →