Skip to content

Keep all values of repeatable IPTC datasets on insert - #9484

Open
jadhavgaurav wants to merge 1 commit into
Exiv2:mainfrom
jadhavgaurav:fix-iptc-repeatable-insert
Open

Keep all values of repeatable IPTC datasets on insert#9484
jadhavgaurav wants to merge 1 commit into
Exiv2:mainfrom
jadhavgaurav:fix-iptc-repeatable-insert

Conversation

@jadhavgaurav

Copy link
Copy Markdown
Contributor

Fixes #3334.

Problem

Exporting IPTC to an .exv sidecar and inserting it again loses all but one value of a repeatable IPTC dataset:

$ exiv2 -M"add Iptc.Application2.Keywords one"   e.jpg
$ exiv2 -M"add Iptc.Application2.Keywords two"   e.jpg
$ exiv2 -M"add Iptc.Application2.Keywords three" e.jpg
$ exiv2 -ea e.jpg
$ exiv2 -ia e.jpg
$ exiv2 -PI -g Keywords e.jpg
Iptc.Application2.Keywords                   String      5  three
Iptc.Application2.Keywords                   String      3  two
Iptc.Application2.Keywords                   String      5  three

The .exv itself is fine; the values are lost on insert.

Cause

metacopy() copies IPTC in preserve mode (the mode used by the insert action) with:

targetImage->iptcData()[iptc.key()] = iptc.value();

IptcData::operator[] looks up the first entry with that key. Datasets like Iptc.Application2.Keywords, Iptc.Application2.Byline and Iptc.Application2.SuppCategory are repeatable, so every source value is written onto the same first target entry and only the last one survives. Exif and XMP are unaffected: their keys are unique.

Fix

Remove the target's entries for the datasets the source provides, then append all source entries in their original order. Non-repeatable datasets behave exactly as before: the source value replaces the target value, and target-only datasets are still preserved.

Tests

New system test tests/bugfixes/github/test_issue_3334.py reproduces the report: it adds three keywords, exports with -ea, re-inserts with -ia and checks that all three come back in order. It fails before the change and passes after.

Two existing reference outputs change, both because keywords that used to be dropped are now kept:

  • conversions.out: step 9 ("And back to IPTC") now returns all three keywords (Sex, Drugs, Rock'n'roll) instead of only the last one.
  • stdin-test.out: piping exiv2 -ea- from Reagan.jpg into exiv2 -ia- now carries all 10 keywords and all 3 SuppCategory values, so the APP13 segment grows from 784 to 952 bytes and the following segment offsets shift.

Ran locally on macOS (arm64, Ninja, Release):

  • unit_tests: 370/370 pass
  • tests/runner.py bugfixes: 325 pass, 10 skipped
  • tests/runner.py regression_tests: 329 pass
  • tests/runner.py bash_tests: 66/67 pass; io_test fails both with and without this change because this build has webready/network support disabled
  • tests/runner.py tiff_test: 1 pass

clang-format was not available on this machine, so the new code was matched to the surrounding style by hand rather than verified with the tool.

metacopy() copied IPTC in preserve mode with
`targetImage->iptcData()[iptc.key()] = iptc.value()`. IptcData::operator[]
returns the first entry matching the key, so for a repeatable dataset such as
Iptc.Application2.Keywords every source value was written onto the target's
first matching entry and all but the last one were lost.

Drop the target's entries for the datasets the source provides, then append all
source entries in their original order. Non-repeatable datasets keep the same
behaviour: the source value replaces the target value.

The reference output of conversions_test and stdin_test changes accordingly:
both round-trip files whose keywords were previously dropped.

Fixes Exiv2#3334
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

If several values for Iptc.Application2.Keywords are entered in an .exv-file, only one of them will be inserted

1 participant