JPEG
hier lekt het meestEen JPEG-bestand bewaart zijn metadata in APPn-segmenten, tussen de header van het bestand en de beeldgegevens. Dit is wat er waar zit, en wat PicScrub met elk stuk doet.
Wat er weggaat
- EXIF GPS-coördinaten, merk en model van de camera, datum en tijd, belichtingsinstellingen
- XMP bewerkingsgeschiedenis, gebruikte software, beoordelingen
- IPTC / Photoshop bijschriften, credits, trefwoorden
- Comments en ingesloten thumbnails een piepklein kopietje van het origineel dat je uitsnedes en bewerkingen kan overleven
Wat je kunt houden
- Beeldgegevens altijd onaangeroerd, nooit opnieuw gecodeerd
- ICC-kleurprofiel optioneel, zodat de kleuren blijven kloppen
- Oriëntatie optioneel, zodat portretten rechtop blijven staan
- Copyrightvermelding optioneel, voor fotografen die credits willen zonder coördinaten
De structuur in vogelvlucht
Als je ooit een JPEG in een hex-editor hebt geopend, is het je opgevallen dat hij bestaat uit segmenten die door markers worden gescheiden. Elke marker begint met 0xFF, gevolgd door een byte die vertelt wat voor segment het is. Door dat ontwerp zijn JPEG's relatief eenvoudig te parsen: je zoekt gewoon naar FF-bytes en kijkt wat erachter komt.
Wat privacy betreft is het interessante dat alle metadata (EXIF, GPS, datum en tijd) in die segmenten zit, volledig los van de echte beeldgegevens. Daarom kunnen we de metadata verwijderen zonder de pixels aan te raken of iets opnieuw te comprimeren.
Structuur van een JPEG-bestand
Voorbeeld van een JPEG-header
| Offset | Hex | ASCII | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0000 | FFD8FFE000104A464946000101000048 | ......JFIF.....H | |||||||||||||||
| 0010 | 00480000FFE112344578696600000000 | .H.....4Exif.. | |||||||||||||||
Opbouw van een marker
FF xx:Marker (xx geeft het type aan)LL LL:Lengte (2 bytes, big-endian, inclusief zichzelf)Data...:Gegevens van het segment (lengte - 2 bytes)
Volledig overzicht van JPEG-markers
| Marker | Naam | Beschrijving |
|---|---|---|
| FF D8 | SOI | Begin van de afbeelding |
| FF D9 | EOI | Einde van de afbeelding |
| FF C0 | SOF0 | Begin van het frame (baseline DCT) |
| FF C2 | SOF2 | Begin van het frame (progressieve DCT) |
| FF C4 | DHT | Huffman-tabel definiëren |
| FF DB | DQT | Kwantisatietabel definiëren |
| FF DD | DRI | Restart-interval definiëren |
| FF DA | SOS | Begin van de scan (hierna komen de beeldgegevens) |
| FF FE | COM | Comment (metadata) |
| FF E0 | APP0 | JFIF-marker |
| FF E1 | APP1 | EXIF- / XMP-marker |
| FF E2 | APP2 | ICC-profiel / MPF |
| FF ED | APP13 | IPTC / Photoshop |
| FF EE | APP14 | Kleurtransformatie van Adobe |
Goud = metadata (wordt verwijderd), zonder kleur = structuur die blijft
JFIF tegenover EXIF
Iets wat veel mensen in de war brengt: JPEG-bestanden bevatten vaak twee verschillende metadatastandaarden tegelijk. JFIF was er eerst en regelt de basis, zoals de resolutie. Daarna gingen camera's EXIF-gegevens toevoegen, met alle details over de opname. De meeste moderne JPEG's hebben allebei, en daarom zie je vooraan in het bestand zowel een APP0- als een APP1-marker.
APP0:JFIF
JPEG File Interchange Format. Basisinformatie over de afbeelding.
- • Versienummer
- • Pixeldichtheid (DPI)
- • Beeldverhouding
- • Optionele thumbnail
APP1:EXIF
Exchangeable Image File Format. Metadata van de camera.
- • Merk en model van de camera
- • GPS-coördinaten
- • Datum en tijd
- • Belichtingsinstellingen
APP-markers van dichtbij
De JPEG-specificatie reserveerde 16 "application"-markers (APP0 tot en met APP15) die leveranciers naar eigen inzicht mochten gebruiken. In de loop der jaren claimden verschillende organisaties verschillende markers voor hun metadataformaten. Het resultaat is een beetje een rommeltje, maar dan wel een goed gedocumenteerd rommeltje.
Lastig is vooral dat dezelfde marker iets anders kan betekenen, afhankelijk van de inhoud. APP1 kan bijvoorbeeld zowel EXIF- als XMP-gegevens bevatten, dus je moet naar de identifier binnenin kijken om te weten waar je mee te maken hebt.
APP0 (0xFFE0):JFIF
Identifier: JFIF\0. Bevat de versie, de eenheid van de dichtheid, de X/Y-dichtheid en een optionele ingesloten thumbnail. Over het algemeen veilig om te bewaren.
APP1 (0xFFE1):EXIF
Identifier: Exif\0\0. Bevat een complete TIFF-structuur met IFD-entries voor camera-info, GPS-gegevens, datum en tijd, thumbnails en maker notes. Het grootste privacyrisico.
APP1 (0xFFE1):XMP
Identifier: http://ns.adobe.com/xap/1.0/\0. Metadatastandaard van Adobe op basis van XML. Kan bewerkingsgeschiedenis, softwaregegevens en uitgebreide EXIF-gegevens bevatten.
XMP-namespaces
xmp: http://ns.adobe.com/xap/1.0/xmpMM: http://ns.adobe.com/xap/1.0/mm/dc: http://purl.org/dc/elements/1.1/photoshop: http://ns.adobe.com/photoshop/1.0/tiff: http://ns.adobe.com/tiff/1.0/exif: http://ns.adobe.com/exif/1.0/APP1 (0xFFE1):Extended XMP
Identifier: http://ns.adobe.com/xmp/extension/\0. Voor XMP-gegevens groter dan 65KB, verdeeld over meerdere APP1-segmenten.
APP2 (0xFFE2):MPF
Identifier: MPF\0. Multi-Picture Format, voor stereoscopische beelden en panorama's.
APP2 (0xFFE2):ICC-profiel
Identifier: ICC_PROFILE\0. Gegevens voor kleurbeheer. Kan in stukken over meerdere APP2-markers verdeeld zijn. Meestal veilig om te bewaren.
APP13 (0xFFED):IPTC/Photoshop
Identifier: Photoshop 3.0\0. Bevat IPTC-IIM-gegevens met bijschriften, trefwoorden, copyright en gegevens over de maker. Kan informatie over de auteur bevatten.
APP14 (0xFFEE):Adobe
Identifier: Adobe\0. Bevat vlaggen voor de kleurtransformatie (RGB/CMYK). Belangrijk om de kleuren goed weer te geven.
De EXIF-structuur
Hier wordt het interessant (en een beetje vreemd). EXIF-gegevens zijn in feite een piepklein TIFF-bestand dat in je JPEG zit. Ja, echt. Het heeft een eigen header, een eigen byte-volgorde en gebruikt de IFD-structuur (Image File Directory) van TIFF om tags op te slaan.
Het eerste wat je na de identifier "Exif" ziet, is een TIFF-header die aangeeft of de gegevens little-endian zijn (Intel, "II") of big-endian (Motorola, "MM"). Zit je daar naast, dan is elk getal onzin, dus dat is het eerste wat elke parser controleert.
TIFF-header (8 bytes)
| Offset | Hex | ASCII | |||||||
|---|---|---|---|---|---|---|---|---|---|
| 0000 | 49492A0008000000 | II*..... | |||||||
II = Intel (little-endian), MM = Motorola (big-endian)
Opbouw van een IFD-entry (12 bytes)
Belangrijke IFD-entries
0x010F:Make0x0110:Model0x0132:DateTime0x8769:ExifIFDPointer0x8825:GPSInfoIFDPointer0x927C:MakerNoteHoe PicScrub JPEG verwerkt
De aanpak is vrij rechttoe rechtaan: we lopen het bestand marker voor marker door, houden de markers die nodig zijn om de afbeelding te tonen en slaan de markers met metadata over. Omdat we de gecomprimeerde beeldgegevens nooit aanraken, is er geen enkel kwaliteitsverlies.
De kern is dat de markerstructuur van JPEG dit makkelijk maakt. We hoeven niets te begrijpen van DCT-coëfficiënten of Huffman-tabellen. We hoeven alleen te herkennen welke segmenten metadata zijn en welke niet.
De header controleren
Nagaan of de SOI-marker (FF D8) aan het begin van het bestand staat
De markers parsen
Elke marker op volgorde lezen en het type en de lengte eruit halen
De metadata herkennen
De identifiers in de APP-segmenten nalopen (EXIF, XMP, IPTC en zo verder)
Selectief kopiëren
Segmenten zonder metadata naar het resultaat kopiëren, de rest overslaan
Wat er blijft
- • SOI/EOI-markers (verplicht)
- • DQT (kwantisatietabellen)
- • SOF (frameheader)
- • DHT (Huffman-tabellen)
- • SOS en scangegevens (de echte afbeelding)
- • Optioneel: het ICC-kleurprofiel (in te stellen)
Wat er weggaat
- • APP1 EXIF (camera, GPS, datum en tijd)
- • APP1 XMP (metadata van bewerkingen)
- • APP13 IPTC (bijschriften, auteur)
- • COM-markers (comments)
- • EXIF-thumbnails
Overzicht van EXIF-tags
Niet elke EXIF-tag is even gevoelig. Sommige, zoals de belichtingsinstellingen, zijn tamelijk onschuldig. Andere, zoals serienummers en namen van eigenaren, wijzen rechtstreeks naar jou of naar je apparatuur. Dit zijn de tags die wij als risicovol beschouwen:
| Tag-ID | Naam | Privacyrisico |
|---|---|---|
| 0x9003 | DateTimeOriginal | Hoog |
| 0x9004 | DateTimeDigitized | Hoog |
| 0x9010 | OffsetTime | Gemiddeld |
| 0x9286 | UserComment | Hoog |
| 0x927C | MakerNote | Hoog |
| 0xA420 | ImageUniqueID | Hoog |
| 0xA430 | CameraOwnerName | Hoog |
| 0xA431 | BodySerialNumber | Hoog |
| 0xA434 | LensModel | Gemiddeld |
| 0xA435 | LensSerialNumber | Hoog |
| 0xFDE8 | OwnerName | Hoog |
| 0xFDE9 | SerialNumber | Hoog |
Bekijk alle tags met camera-instellingen (niet herleidbaar)
0x829A ExposureTime0x829D FNumber0x8822 ExposureProgram0x8827 ISOSpeedRatings0x9201 ShutterSpeedValue0x9202 ApertureValue0x9203 BrightnessValue0x9204 ExposureBiasValue0x9207 MeteringMode0x9208 LightSource0x9209 Flash0x920A FocalLength0xA001 ColorSpace0xA002 PixelXDimension0xA003 PixelYDimension0xA402 ExposureMode0xA403 WhiteBalance0xA405 FocalLengthIn35mmFilm0xA406 SceneCaptureTypeOverzicht van GPS-tags
GPS-gegevens staan in een eigen sub-IFD, waar tag 0x8825 in de hoofd-IFD naar verwijst. Bestaat die pointer, dan zit er locatiedata in je afbeelding. Moderne smartphones zijn hier bijzonder fanatiek in, vaak met genoeg precisie om aan te wijzen waar je precies stond.
| Tag-ID | Naam | Beschrijving |
|---|---|---|
| 0x0000 | GPSVersionID | Versie van de GPS-tags |
| 0x0001 | GPSLatitudeRef | N of S |
| 0x0002 | GPSLatitude | Graden, minuten, seconden |
| 0x0003 | GPSLongitudeRef | E of W |
| 0x0004 | GPSLongitude | Graden, minuten, seconden |
| 0x0005 | GPSAltitudeRef | Boven of onder zeeniveau |
| 0x0006 | GPSAltitude | Meters |
| 0x0007 | GPSTimeStamp | Tijd in UTC |
| 0x001D | GPSDateStamp | Datum in UTC |
| 0x0012 | GPSMapDatum | Gebruikt geodetisch datum |
| 0x001B | GPSProcessingMethod | GPS/CELLID/WLAN/MANUAL |
| 0x001C | GPSAreaInformation | Naam van de locatie |
Overzicht van IPTC-tags
IPTC is bedacht zodat persbureaus bijschriften, credits en copyrightgegevens in een foto konden zetten. Het staat in APP13, met de identifier "Photoshop 3.0" (ja, Adobe nam het over). Heb je ooit copyrightgegevens of trefwoorden toegevoegd in Lightroom of Photoshop, dan belanden die hier.
0x0250 By-line (auteur)0x0255 By-line Title (functie van de auteur)0x025A City (stad)0x025C Sub-location (plek binnen de stad)0x025F Province/State (provincie of staat)0x0265 Country Name (land)0x0274 Copyright Notice (copyrightvermelding)0x0276 Contact (contactgegevens)0x0237 Date Created (aanmaakdatum)0x023C Time Created (aanmaaktijd)0x0278 Caption/Abstract (bijschrift)0x0219 Keywords (trefwoorden)