Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Xmp.dc.subject is not saved as Array type #6

Open
Raven24 opened this issue Jan 9, 2013 · 5 comments
Open

Xmp.dc.subject is not saved as Array type #6

Raven24 opened this issue Jan 9, 2013 · 5 comments

Comments

@Raven24
Copy link

Raven24 commented Jan 9, 2013

According to the exiv2 documentation, the Xmp.dc.subject field seems to be the "new" place to store keywords (apart from Iptc.Application2.Keywords)

Unfortunately, if multiple values get assigned to that field like so

image.xmp_data.add("Xmp.dc.subject", "kw1")
image.xmp_data.add("Xmp.dc.subject", "kw2")
image.write_metadata

only the value assigned last makes it into the actual file headers, the rest is lost.

@jgraichen
Copy link
Contributor

There is a difference between Iptc.Application2.Keywords and Xmp.dc.subject. The first one is a tag that holds a string value, but can appear more than one time. So two keywords can be assigned by adding two key-value pairs:

image.iptc_data.add("Iptc.Application2.Keywords", "kw1")
image.iptc_data.add("Iptc.Application2.Keywords", "kw2")

But Xmp.dc.subject is a multi-value property, that can only be added once but contains multiple string values (XmpBag). Your code example first sets a Xmp.dc.subject with the value "kw1". The second creates a new key-value pair with the new value and tries to add this pair. But only on property Xmp.dc.subject is allowed so the first pair will be overridden.

Currently the only way to assign specific non string values to any kind of property is by providing it in an exiv2 type specific format as a string. For example: exif stores GPS coordinates as an array of rationals. Those values are returned as a string "4/1 22/1 1/3" and can also be written in such a format.

Some quick test told me that the string returned for a multi value XmpBag is a comma separated list, so you can try to just set a comma separated list :

image.iptc_data["Xmp.dc.subject"] = "kw1, kw2"

But I do not know if exiv2 parses and stores such a string as a multi value property or a plain string.

Reading and writing values in there appropriate ruby equivalents (arrays, longs, rationals, ...) isn't easy, due to corner cases and different tags and tag types. I'm working on that at https://github.com/jgraichen/exiv2 if you're interested. Current development build should be able to write multi-value xmp properties as well as reading most values as native ruby objects. Writing native ruby types isn't yet complete. You can take a look in the test cases how native ruby objects are returned.

@Raven24
Copy link
Author

Raven24 commented Jan 10, 2013

Thank you for responding and working on this so quickly!
I had a look at your branch and tested it a little, but it still doesn't seem to cope with multiple values when they are written to the file.

Or, to say it in rspec: (this is what I'd expect)

before do
  # create a fresh test file
  img = Pathname.new("spec/files/test.jpg").to_s
  @test_img = Pathname.new("spec/files/keyword_test.jpg").to_s
  FileUtils.cp(img, @test_img)
end

after do
  # remove test file after test
  FileUtils.rm(@test_img)
end

describe "keywords in 'Xmp.dc.subject'" do 
  it "should accept an array" do
    img = Exiv2::ImageFactory.open(@test_img)
    img.read_metadata
    img.xmp_data["Xmp.dc.subject"] = ["aaaa", "bbbb"]
    img.write_metadata

    img = Exiv2::ImageFactory.open(@test_img)
    img.read_metadata
    img.xmp_data["Xmp.dc.subject"].should =~ ["aaaa", "bbbb"]
  end

  it "should behave like Iptc keywords" do
    img = Exiv2::ImageFactory.open(@test_img)
    img.read_metadata
    img.xmp_data.add("Xmp.dc.subject", "aaaa")
    img.xmp_data.add("Xmp.dc.subject", "bbbb")
    img.write_metadata

    img = Exiv2::ImageFactory.open(@test_img)
    img.read_metadata
    img.xmp_data["Xmp.dc.subject"].should =~ ["aaaa", "bbbb"]
  end
end

I hope this is at all possible.

Btw, adding keywords as img.xmp_data["Xmp.dc.subject"] = "aaaa,bbbb" adds the string without any splitting or other processing by exiv2 :(

@jgraichen
Copy link
Contributor

In my opinion the semantic of add is to explicit try to add a new property. Changing that behavior only for Xmp.dc.subject does not look right for me. If your intention is to set multiple keywords the same way you can use the array setter also for Iptc keywords:

    it "should set multiply IPTC data values" do
      @iptc_data["Iptc.Application2.Keywords"] = ["abc", "cde"]
      @iptc_data.to_hash["Iptc.Application2.Keywords"].should == ["abc", "cde"]
    end

The spec name is a little bit old. It will actually set multiple Iptc.Application2.Keywords properties with one keyword each.

If you only want to add a new keyword the following should be possible too:

@iptc_data["Iptc.Application2.Keywords"] += ["efg"]
@iptc_data["Iptc.Application2.Keywords"] << "efg"

Unfortunately that only works if you have at least two keywords previously set (... = ["abc", "cde"]) otherwise not an array but nil or a string will be returned by @iptc_data["Iptc.Application2.Keywords"] which may result in an exception or unwanted behavior.

I'll try to extend the Iptc reading behavior so that an array will be returned for all repeatable Iptc properties even if that property is not set or has only one value but that will need some rewrites.

@Raven24
Copy link
Author

Raven24 commented Jan 11, 2013

In my opinion the semantic of add is to explicit try to add a new property. Changing that behavior only for Xmp.dc.subject does not look right for me.

Ok now I see what you mean by that.

Keep me updated on your progress, I am happy to do some testing for you.

@mrkamel
Copy link

mrkamel commented Oct 8, 2013

Hi, is there any progress?
I'm also running into issues because of this.
Thx.

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

No branches or pull requests

3 participants