Skip to content

Commit c94be51

Browse files
chore: add memory index and corpus gap analysis documentation
1 parent df199a3 commit c94be51

5 files changed

Lines changed: 305 additions & 0 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Memory Index
2+
3+
- [Test corpus sources](reference_test_corpus.md) — 12 public repos/sources; confirmed file lists, download URLs, and edge-case coverage per source
4+
- [Corpus gap analysis](project_corpus_gaps.md) — Identified gaps resolved in download.sh: progressive JPEG, XMP sidecar, multi-page TIFF, BigTIFF endianness, exotic RAW formats, MakerNote variants, XMP-only
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
---
2+
name: Corpus gap analysis
3+
description: Gaps identified in testdata/corpus as of 2026-04-03 audit, and how each was resolved in download.sh
4+
type: project
5+
---
6+
7+
# Test Corpus Gap Analysis (2026-04-03)
8+
9+
## Corpus state before this audit
10+
1,726 files across jpeg/tiff/png/heif/webp/raw. No xmp/ directory.
11+
12+
## Gaps identified and resolutions
13+
14+
### 1. Progressive JPEG — RESOLVED
15+
**Gap**: No progressive JPEG test files in corpus.
16+
**Resolution**: SOURCE 9 (sindresorhus/is-progressive) added. Provides both progressive and baseline variants with MIT license.
17+
**Files**: kitten-progressive.jpg, progressive.jpg, baseline.jpg, kitten.jpg, curious-exif.jpg
18+
**Destination**: corpus/jpeg/progressive/
19+
20+
### 2. XMP-only JPEG — RESOLVED
21+
**Gap**: No JPEG with XMP but no EXIF was in corpus (needed to test XMP-first parsing path).
22+
**Resolution**: SOURCE 8 (exiftool) XMP.jpg (XMP-only, 10KB). SOURCE 1 (ianare) jpg/xmp/no_exif.jpg.
23+
**Files**: corpus/jpeg/exiftool/XMP.jpg, corpus/jpeg/exif-samples/no_exif.jpg
24+
25+
### 3. EXIF+IPTC+XMP combined — RESOLVED
26+
**Gap**: No single image confirmed to carry all three metadata standards simultaneously.
27+
**Resolution**: SOURCE 8 (exiftool) ExifTool.jpg (confirmed EXIF+IPTC+XMP, 26KB). MWG.jpg also confirmed.
28+
**Files**: corpus/jpeg/exiftool/ExifTool.jpg, corpus/jpeg/exiftool/MWG.jpg
29+
30+
### 4. No-metadata JPEG — RESOLVED
31+
**Gap**: Unknown.jpg from ExifTool test suite was not in corpus.
32+
**Resolution**: SOURCE 8 now includes Unknown.jpg (7.2 KB, no recognized metadata).
33+
**Files**: corpus/jpeg/exiftool/Unknown.jpg
34+
35+
### 5. Extended/multi-packet XMP — RESOLVED
36+
**Gap**: No file testing the case where XMP is split across multiple APP1 segments.
37+
**Resolution**: SOURCE 8 ExtendedXMP.jpg (1.4KB, multi-packet XMP).
38+
**Files**: corpus/jpeg/exiftool/ExtendedXMP.jpg
39+
40+
### 6. BigTIFF big-endian (Motorola byte order) — CONFIRMED PRESENT
41+
**Status**: BigTIFFMotorola.tif and BigTIFFMotorolaLongStrips.tif already in corpus via SOURCE 2.
42+
**Files**: corpus/tiff/metadata-extractor/BigTIFFMotorola.tif
43+
44+
### 7. Multi-page TIFF — CONFIRMED PRESENT
45+
**Status**: multipage.tif already in corpus via SOURCE 2.
46+
**Files**: corpus/tiff/metadata-extractor/multipage.tif
47+
48+
### 8. Fuji RAF — RESOLVED
49+
**Gap**: No RAF files in corpus (copy_ext in old download.sh did not include raf extension).
50+
**Resolution**: SOURCE 2 now copies raf extension; SOURCE 8 includes FujiFilm.raf.
51+
**Files**: corpus/raw/metadata-extractor/*.raf, corpus/raw/exiftool/FujiFilm.raf
52+
53+
### 9. Pentax PEF — RESOLVED
54+
**Gap**: PEF format not collected.
55+
**Resolution**: SOURCE 2 now copies pef extension.
56+
**Files**: corpus/raw/metadata-extractor/Pentax K-1 Mark II.pef
57+
58+
### 10. Sigma X3F — RESOLVED
59+
**Gap**: X3F format not collected.
60+
**Resolution**: SOURCE 2 now copies x3f extension. SOURCE 8 includes Sigma.x3f.
61+
**Files**: corpus/raw/metadata-extractor/*.x3f, corpus/raw/exiftool/Sigma.x3f
62+
63+
### 11. Minolta MRW — RESOLVED
64+
**Gap**: MRW format not collected.
65+
**Resolution**: SOURCE 8 includes Minolta.mrw.
66+
**Files**: corpus/raw/exiftool/Minolta.mrw
67+
68+
### 12. Canon CRW (legacy) — RESOLVED
69+
**Gap**: CRW (pre-CR2 Canon format) not collected.
70+
**Resolution**: SOURCE 2 now copies crw extension. SOURCE 8 includes CanonRaw.crw.
71+
**Files**: corpus/raw/exiftool/CanonRaw.crw
72+
73+
### 13. Phase One IIQ — RESOLVED
74+
**Gap**: No medium-format RAW coverage.
75+
**Resolution**: SOURCE 8 includes PhaseOne.iiq.
76+
**Files**: corpus/raw/exiftool/PhaseOne.iiq
77+
78+
### 14. XMP sidecar files — RESOLVED
79+
**Gap**: No .xmp sidecar files were collected (only embedded XMP).
80+
**Resolution**: xmp/ corpus directory created. SOURCE 2 collects xmp/ directory. SOURCE 6 collects BlueSquare.xmp, StaffPhotographer-Example.xmp. SOURCE 8 collects PLUS.xmp.
81+
**Files**: corpus/xmp/
82+
83+
### 15. PNG with EXIF / PNG with no metadata / PNG with tEXt — RESOLVED
84+
**Gap**: No explicit minimal PNG test cases.
85+
**Resolution**: SOURCE 6 (Exiv2) adds 1343_exif.png, 1343_comment.png, 1343_empty.png.
86+
**Files**: corpus/png/exiv2/*.png
87+
88+
### 16. MakerNote variants (Olympus 5 variants, Pentax 3 variants) — RESOLVED
89+
**Gap**: MakerNote variant testing was limited.
90+
**Resolution**: SOURCE 4 (libexif/libexif test/testdata) adds 9 explicit MakerNote variant JPEGs.
91+
**Files**: corpus/jpeg/libexif-makernotes/
92+
93+
### 17. IPTC backward compatibility (older standard versions) — RESOLVED
94+
**Gap**: Only Std2024.1 and Std2021.1 were downloaded; Core1.3 failed (404).
95+
**Resolution**: Download now attempts Std2023.2, Std2019.1, Std2017.1, Std2016, Std2014 in addition to Core1.3.
96+
**Note**: Core1.3 URL may still 404 — verify manually.
97+
98+
### 18. TIFF structural variants (planar, tiled, multi-page, compressed) — RESOLVED
99+
**Gap**: Existing TIFF corpus was mostly camera-metadata focused, not TIFF-structure focused.
100+
**Resolution**: SOURCE 10 (tlnagy/exampletiffs) adds mri.tif (multi-page), compression variants, planar, tiled.
101+
**Files**: corpus/tiff/exampletiffs/
102+
103+
## Remaining confirmed gaps
104+
- **Hasselblad 3FR/FFF**: No source found with freely licensed files
105+
- **Phase One RAW beyond IIQ**: Limited to ExifTool's single sample
106+
- **Unicode in JPEG metadata body**: 46_UnicodeEncodeError.jpg from ianare exists but tests encoder error, not embedded UTF-8 characters in field values — a hand-crafted test file would be more precise
107+
- **Images with very large metadata blocks (>64KB XMP)**: Not confirmed present in any source; would need synthetic generation
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
---
2+
name: Test corpus sources
3+
description: 12 public repos/sources for image metadata test images; confirmed file lists, download URLs, and edge-case coverage per source as of 2026-04-03
4+
type: reference
5+
---
6+
7+
# Image Metadata Test Corpus Sources
8+
9+
All sources are incorporated in testdata/download.sh.
10+
11+
## SOURCE 1: ianare/exif-samples
12+
**URL**: https://github.com/ianare/exif-samples
13+
**License**: Not explicitly stated (public test images)
14+
**Key content**:
15+
- jpg/tests/: 13 edge-case JPEGs (type errors, GPS IFD, Unicode errors, zero-length strings, memory errors, IndexError)
16+
- jpg/invalid/: 7 malformed JPEG files (image00971.jpg through image02206.jpg)
17+
- jpg/gps/: 9 Nikon DSCN GPS-tagged JPEGs
18+
- jpg/orientation/: 16 orientation-tagged JPEGs (landscape_1-8, portrait_1-8)
19+
- jpg/xmp/: no_exif.jpg (XMP-only, no EXIF), BlueSquare.jpg
20+
- tiff/: 8 TIFF files including Crémieux11.tiff (Unicode filename test)
21+
- heic/, heic/mobile/: iPhone 13 Pro Max, Nokia 8.3 5G HEIC/HEIF
22+
23+
## SOURCE 2: drewnoakes/metadata-extractor-images
24+
**URL**: https://github.com/drewnoakes/metadata-extractor-images
25+
**License**: Varies per file (community contributed)
26+
**Key content** (CONFIRMED via API):
27+
- tif/BigTIFF/BigTIFF.tif: BigTIFF Intel/LE
28+
- tif/BigTIFF/BigTIFFMotorola.tif: BigTIFF Motorola/BE (explicit big-endian test)
29+
- tif/BigTIFF/BigTIFFSubIFD4.tif, BigTIFFSubIFD8.tif: SubIFD traversal tests
30+
- tif/multipage.tif: multi-page TIFF (1.5 MB)
31+
- tif/ImageTestSuite/: ~45 hash-named TIFF edge cases
32+
- png/PngSuite/: ~175 official PNG test suite files
33+
- png/photoshop-8x12-rgb24-all-metadata.png: EXIF+IPTC+XMP in PNG
34+
- png/sampleWithExifData.png: EXIF in PNG
35+
- png/photoshop-8x12-rgb24-interlaced.png, rgba32-interlaced.png: interlaced PNG
36+
- png/invalid-iCCP-missing-adler32-checksum.png: corrupt PNG chunk
37+
- webp/: 15 WebP files covering VP8, VP8L, VP8X, lossless, lossy, animated
38+
- raf/: FujiFilm EX-2, FinePix S5500, X-E1
39+
- x3f/: Sigma DP1 Quattro, DP2 Quattro
40+
- pef/: Pentax K-1 Mark II
41+
- xmp/: 4 sidecar XMP files (digiKam, jPhotoTagger, ExifTool 9.74, APhotoManager)
42+
43+
## SOURCE 3: libexif/libexif-testsuite
44+
**URL**: https://github.com/libexif/libexif-testsuite
45+
**Images/**: 4 files: canon-eos-m6mark2.jpg, canon-powershot-g2.jpg, nikon-z6.jpg, samsung-s9.jpg
46+
47+
## SOURCE 4: libexif/libexif test/testdata
48+
**URL**: https://github.com/libexif/libexif (test/testdata path)
49+
**Key content**: 9 MakerNote variant JPEGs with .parsed golden files
50+
- canon_makernote_variant_1.jpg
51+
- fuji_makernote_variant_1.jpg
52+
- olympus_makernote_variant_2.jpg through _5.jpg (4 variants)
53+
- pentax_makernote_variant_2.jpg through _4.jpg (3 variants)
54+
**Download pattern**: https://raw.githubusercontent.com/libexif/libexif/master/test/testdata/{filename}
55+
56+
## SOURCE 5: IPTC reference images (iptc.org)
57+
**URL**: https://iptc.org/standards/photo-metadata/reference-images/
58+
**License**: Official IPTC standard reference images (freely distributable for testing)
59+
**Available versions** (CONFIRMED via web):
60+
- Std2024.1: https://iptc.org/std/photometadata/examples/IPTC-PhotometadataRef-Std2024.1.jpg
61+
- Std2023.2: https://iptc.org/std/photometadata/examples/IPTC-PhotometadataRef-Std2023.2.jpg
62+
- Std2021.1: https://www.iptc.org/std/photometadata/examples/IPTC-PhotometadataRef-Std2021.1.jpg
63+
- Std2019.1: https://www.iptc.org/std/photometadata/examples/IPTC-PhotometadataRef-Std2019.1.jpg
64+
- Std2017.1: https://www.iptc.org/std/photometadata/examples/IPTC-PhotometadataRef-Std2017.1.jpg
65+
- Core1.3: https://www.iptc.org/std/photometadata/examples/IPTC-PhotometadataRef-Core1.3.jpg
66+
- Std2016: https://iptc.org/std/photometadata/examples/IPTC-PhotometadataRef-Std2016_large.jpg
67+
- Std2014: https://iptc.org/std/photometadata/examples/IPTC-PhotometadataRef-Std2014_large.jpg
68+
**Note**: Core1.3 failed to download in prior runs (404 possible). Each image has every field populated with its own field name as value.
69+
70+
## SOURCE 6: Exiv2/exiv2 test/data
71+
**URL**: https://github.com/Exiv2/exiv2 (test/data path)
72+
**Key content** (CONFIRMED via API):
73+
- HEIC: Stonehenge.heic, IMG_3578.heic, 2021-02-13-1929.heic
74+
- PNG: 1343_comment.png (tEXt chunk), 1343_exif.png (EXIF in PNG), 1343_empty.png (no metadata)
75+
- XMP sidecars: BlueSquare.xmp, StaffPhotographer-Example.xmp
76+
- TIFF: Reagan.tiff, ReaganLargeTiff.tiff
77+
- Multiple *_poc files: fuzzing/security inputs
78+
- exiv2-fujifilm-finepix-s2pro.jpg: Fuji MakerNote
79+
- exiv2-sigma-d10.jpg: Sigma MakerNote
80+
- Canon-R6-pruned.CR3: Canon CR3
81+
82+
## SOURCE 7: adobe/XMP-Toolkit-SDK (samples/testfiles)
83+
**URL**: https://github.com/adobe/XMP-Toolkit-SDK
84+
**Key content**: XMP-heavy JPEGs and TIFFs from Adobe's reference XMP implementation
85+
**Note**: Only 6 JPEGs and 2 TIFFs at time of audit — small but authoritative
86+
87+
## SOURCE 8: exiftool/exiftool (t/images)
88+
**URL**: https://github.com/exiftool/exiftool (t/images path)
89+
**License**: Artistic License (Perl standard)
90+
**Key files** (all CONFIRMED via API, sizes in bytes):
91+
- ExifTool.jpg (26,106): EXIF + IPTC + XMP combined
92+
- MWG.jpg (2,255): Metadata Working Group compliance
93+
- GPS.jpg (2,133): GPS IFD with coordinates
94+
- IPTC.jpg (9,851): IPTC-focused JPEG
95+
- XMP.jpg (10,314): XMP-only JPEG (key gap filler — no EXIF)
96+
- ExtendedXMP.jpg (1,380): multi-packet extended XMP
97+
- Unknown.jpg (7,199): JPEG with no recognized metadata
98+
- ExifTool.tif (4,864): TIFF with EXIF+IPTC+XMP
99+
- GeoTiff.tif (2,660): GeoTIFF with projection metadata
100+
- BigTIFF.btf (384): BigTIFF format (minimal)
101+
- FujiFilm.raf (38,452): Fuji RAF raw
102+
- PhaseOne.iiq (3,364): Phase One IIQ medium format
103+
- CanonRaw.crw (not sized): Canon CRW legacy format
104+
- Minolta.mrw (2,596): Minolta MRW raw
105+
- Sigma.x3f (1,464): Sigma X3F raw
106+
- PLUS.xmp (4,763): PLUS licensing XMP sidecar
107+
108+
## SOURCE 9: sindresorhus/is-progressive
109+
**URL**: https://github.com/sindresorhus/is-progressive
110+
**License**: MIT (confirmed — license file present in repo)
111+
**Key files** (CONFIRMED via API):
112+
- kitten-progressive.jpg: progressive JPEG encoding
113+
- progressive.jpg: progressive JPEG encoding
114+
- baseline.jpg: baseline JPEG encoding
115+
- kitten.jpg: baseline JPEG encoding
116+
- curious-exif.jpg: EXIF data in baseline JPEG
117+
**Download base**: https://raw.githubusercontent.com/sindresorhus/is-progressive/main/fixture/
118+
119+
## SOURCE 10: tlnagy/exampletiffs
120+
**URL**: https://github.com/tlnagy/exampletiffs
121+
**Key files** (CONFIRMED via API, sizes):
122+
- mri.tif (230,578): multi-page TIFF (MRI slices)
123+
- shapes_tiled_multi.tif (37,604): tiled multi-page TIFF
124+
- shapes_lzw.tif (11,530): LZW compressed TIFF
125+
- shapes_deflate.tif: deflate compressed TIFF
126+
- shapes_uncompressed.tif: uncompressed TIFF
127+
- shapes_lzw_planar.tif: planar storage TIFF
128+
- shapes_lzw_palette.tif: palette TIFF
129+
- 4D-series.ome.tif: OME-TIFF with XML in ImageDescription
130+
**Download base**: https://raw.githubusercontent.com/tlnagy/exampletiffs/master/
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Memory Index
2+
3+
- [XMP/IPTC Spec Audit — 2026-04-03](project_xmp_iptc_audit.md) — XMP 7/10, IPTC 7.5/10; specific gaps identified in struct serialization, array-of-structs parsing, IRB write, charset handling
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
---
2+
name: XMP/IPTC Spec Audit — 2026-04-03
3+
description: Detailed spec compliance audit of xmp/ and iptc/ packages; scores and specific defects documented
4+
type: project
5+
---
6+
7+
Audit conducted against XMP ISO 16684-1 and IPTC IIM 4.2.
8+
9+
## XMP Score: 7/10
10+
11+
### Confirmed correct
12+
- Packet scanning: `<?xpacket begin=` + `<?xpacket end=` markers; no premature `?>` termination
13+
- BOM embedded as attribute value in `begin=` field
14+
- `id="W5M0MpCehiHzreSzNTczkc9d"` magic ID present
15+
- `rdf:Alt/Seq/Bag` with `rdf:li` accumulation
16+
- `xml:lang` on `rdf:li` stored as `lang|value`; x-default stored without prefix
17+
- `rdf:parseType="Resource"` → struct handling
18+
- `rdf:resource` shorthand attribute
19+
- Inline attribute shorthand on `rdf:Description`
20+
- All core namespaces correct (xmp, xmpRights, xmpMM, dc, photoshop, exif, tiff, aux, Iptc4xmpCore, Iptc4xmpExt)
21+
- `xml.EscapeText` used for all character data in write
22+
- 2 KB whitespace padding + `<?xpacket end="w"?>`
23+
- Deterministic output via sort
24+
25+
### Defects / Gaps
26+
1. **No UTF-16 packet support** — XMP §7.2 allows UTF-16/UTF-32; `bytes.Index` on UTF-8 literals fails
27+
2. **`begin=` attribute value not validated** — accepts malformed PIs
28+
3. **Array-of-structs not parsed**`rdf:li` containing nested `rdf:Description` (e.g., xmpMM:History) silently dropped
29+
4. **`xml:lang` not namespace-qualified** in rdf:li scanning (minor)
30+
5. **Struct fields cross-namespace key attribution** — stored under field NS not parent NS
31+
6. **Struct properties not serialized correctly**`propLocal.fieldLocal` emitted as dotted XML element name (invalid)
32+
7. **`collectionType` incomplete** — xmpMM:History/Ingredients should be Seq, not Bag
33+
8. **Missing type-support namespaces**: stEvt, stRef, stDim, stVer, xmpBJ, xmpTPg, xmpDM, xmpG, xmpGImg
34+
9. **`rdf:about` not validated** — spec requires consistent subject URI across all rdf:Description blocks
35+
36+
## IPTC Score: 7.5/10
37+
38+
### Confirmed correct
39+
- Tag marker 0x1C scanning
40+
- 5-byte header: marker + record + dataset + 2-byte size
41+
- Standard 2-byte length (big-endian)
42+
- Extended length: `0x80 | nBytes` in high byte; subsequent nBytes carry actual length
43+
- IRB: 8BIM marker, resource ID, Pascal string name + even-padding, 4-byte size, data even-padding
44+
- Resource ID 0x0404 for IPTC-NAA
45+
- UTF-8 declaration: ESC % G (0x1B 0x25 0x47) in 1:90
46+
- ISO-8859-1 fallback via golang.org/x/text charmap
47+
- UTF-8 declaration re-emitted on encode when originally present
48+
- Dataset registry: good coverage of photographic datasets (5, 25, 55, 60, 80, 105, 116, 120, etc.)
49+
50+
### Defects / Gaps
51+
1. **Destructive IRB write** — buildIRB emits only 0x0404; all other resource blocks (ICC, thumbnail, XMP, etc.) discarded
52+
2. **Multi-segment APP13 not supported** — large IPTC can span multiple APP13 segments; only first parsed
53+
3. **No auto UTF-8 declaration on write** — SetCaption/SetCopyright with non-ASCII values written without 1:90 dataset injection
54+
4. **`isUTF8Declaration` len==3 too strict** — some tools append NUL padding; HasPrefix would be more robust
55+
5. **No ISO 2022 charset diversity** — non-UTF-8, non-Latin-1 declared charsets (e.g., Shift-JIS) produce garbled output
56+
6. **Malformed data silently truncates** — break on integrity failure drops all subsequent datasets without error
57+
7. **Missing IIM datasets**: 2:22, 2:26-2:31, 2:35-2:38, 2:42, 2:45-2:47, 2:75 (agency workflow fields)
58+
8. **Missing convenience accessors**: ObjectName (2:05), DateCreated (2:55), Headline (2:105), City/ProvinceState/CountryName
59+
60+
**Why:** Research-only audit for library gap assessment.
61+
**How to apply:** Use these findings to prioritize remediation work; P0 is struct serialization (XMP) and destructive IRB write (IPTC).

0 commit comments

Comments
 (0)