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

Expose IPTC and XMP in metadata if available #1079

Merged
merged 1 commit into from
Jan 10, 2018

Conversation

oaleynik
Copy link
Contributor

Closes #904

@oaleynik
Copy link
Contributor Author

@lovell I didn't see references to the WIP branch like mentioned in Contribution guide, so I've created PR targeting master branch. Feel free to change target branch.

@coveralls
Copy link

coveralls commented Dec 28, 2017

Coverage Status

Coverage remained the same at 99.226% when pulling 61f7590 on oaleynik:feat__iptc-xmp into 358b8fe on lovell:master.

@coveralls
Copy link

coveralls commented Dec 28, 2017

Coverage Status

Coverage remained the same at 99.226% when pulling 7a66294 on oaleynik:feat__iptc-xmp into 358b8fe on lovell:master.

@oaleynik oaleynik changed the title [WIP] Expose IPTC and XMP in metadata if available Expose IPTC and XMP in metadata if available Dec 28, 2017
@coveralls
Copy link

coveralls commented Dec 28, 2017

Coverage Status

Coverage decreased (-77.2%) to 21.981% when pulling d82dbc0 on oaleynik:feat__iptc-xmp into 358b8fe on lovell:master.

@oaleynik
Copy link
Contributor Author

Oops, that was my bad with coverage - forgot to remove .only from test.

@oaleynik
Copy link
Contributor Author

Rebased and squashed.

@coveralls
Copy link

coveralls commented Dec 28, 2017

Coverage Status

Coverage remained the same at 99.226% when pulling 65f3c94 on oaleynik:feat__iptc-xmp into 358b8fe on lovell:master.

@lovell
Copy link
Owner

lovell commented Dec 31, 2017

Hello, this looks great, thank you. Do you think it's worth adding an assertion that inspects the first byte/word of each Buffer to ensure their contents are as-expected too?

Update: I'm happy for devDependencies to be added that can parse the metadata for use in the tests.

@@ -81,6 +81,22 @@ class MetadataWorker : public Nan::AsyncWorker {
memcpy(baton->icc, icc, iccLength);
baton->iccLength = iccLength;
}
// IPTC
if (image.get_typeof(VIPS_META_IPCT_NAME) == VIPS_TYPE_BLOB) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jcupitt Was the use of IPCT (vs IPTC) in the VIPS_META_IPCT_NAME naming intentional/historical?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh dear, no, just acronymical dyslexia, sorry. I'll fix it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 8.6 with jcupitt/libvips@77287a9

There's a #define so the wrong name will still work.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jcupitt Thanks John, fast work as always.

@oaleynik This PR can use the current IPCT spelling for now. The forthcoming version of sharp will depend on libvips v8.6.1+ so I'll update to use the IPTC naming before release.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rodger! Thanks for the quick fix @jcupitt ;)

@@ -57,6 +57,7 @@ module.exports = {

inputJpg: getPath('2569067123_aca715a2ee_o.jpg'), // http://www.flickr.com/photos/grizdave/2569067123/
inputJpgWithExif: getPath('Landscape_8.jpg'), // https://github.com/recurser/exif-orientation-examples/blob/master/Landscape_8.jpg
inputJpgWithIptcAndXmp: getPath('Landscape_9.jpg'), // https://unsplash.com/photos/RWAIyGmgHTQ
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a smaller test image we could use? (Perhaps resize this one but maintain metadata?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, sorry. I will definitely resize it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@oaleynik
Copy link
Contributor Author

Hello, this looks great, thank you. Do you think it's worth adding an assertion that inspects the first byte/word of each Buffer to ensure their contents are as-expected too?
Update: I'm happy for devDependencies to be added that can parse the metadata for use in the tests.

@lovell I wanted to add some kind of IPTC parser, but I didn't find good implementation for nodejs, which is at least maintained. For use in my main job project I've ended up implementing the custom one (I need to be able to use streams). Not sure if I will be releasing that as independent npm package, but I will definitely think about adding here something like this https://github.com/devongovett/exif-reader/blob/master/index.js#L4

@coveralls
Copy link

coveralls commented Dec 31, 2017

Coverage Status

Coverage remained the same at 99.226% when pulling 333765c on oaleynik:feat__iptc-xmp into 358b8fe on lovell:master.

// IPTC
assert.strictEqual('object', typeof metadata.iptc);
assert.strictEqual(true, metadata.iptc instanceof Buffer);
// XMP
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given there's no well-maintained IPTC parser, perhaps we could add an assertion on the Buffer length?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can work for now. Thanks for the suggestion @lovell! I will add it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like we also can test it by checking that buffer starts with Photoshop word.

⌘  exiv2 -pS test/fixtures/Landscape_9.jpg
STRUCTURE OF JPEG FILE: test/fixtures/Landscape_9.jpg
 address | marker       |  length | data
       0 | 0xffd8 SOI
       2 | 0xffe0 APP0  |      16 | JFIF............
      20 | 0xffe1 APP1  |   18835 | Exif..II*...............z......
   18857 | 0xffe1 APP1  |   12497 | http://ns.adobe.com/xap/1.0/.<?x
   31356 | 0xffed APP13 |   18252 | Photoshop 3.0.8BIM..............
   49610 | 0xffe2 APP2  |    2444 | ICC_PROFILE......|lcms.0..mntrRG chunk 1/1
   52056 | 0xffdb DQT   |      67
   52125 | 0xffdb DQT   |      67
   52194 | 0xffc0 SOF0  |      17
   52213 | 0xffc4 DHT   |      28
   52243 | 0xffc4 DHT   |      67
   52312 | 0xffc4 DHT   |      27
   52341 | 0xffc4 DHT   |      49
   52392 | 0xffda SOS

assert.strictEqual(true, metadata.iptc instanceof Buffer);
// XMP
assert.strictEqual('object', typeof metadata.xmp);
assert.strictEqual(true, metadata.xmp instanceof Buffer);
Copy link
Owner

@lovell lovell Jan 7, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

XMP is XML-ish so perhaps an assertion that the Buffer starts with <?xpacket will be enough here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've went through specs and it looks like <?xpacket will not be enough... I may be wrong though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the image I added for tests buffer definitely doesn't start from <?xpacket. exiv2 -pS ... shows that there are two APP1 markers. One is used by EXIF. The other one looks close to what we want:

⌘  exiv2 -pS test/fixtures/Landscape_9.jpg
STRUCTURE OF JPEG FILE: test/fixtures/Landscape_9.jpg
 address | marker       |  length | data
       0 | 0xffd8 SOI
       2 | 0xffe0 APP0  |      16 | JFIF............
      20 | 0xffe1 APP1  |   18835 | Exif..II*...............z......
   18857 | 0xffe1 APP1  |   12497 | http://ns.adobe.com/xap/1.0/.<?x
   31356 | 0xffed APP13 |   18252 | Photoshop 3.0.8BIM..............
   49610 | 0xffe2 APP2  |    2444 | ICC_PROFILE......|lcms.0..mntrRG chunk 1/1
   52056 | 0xffdb DQT   |      67
   52125 | 0xffdb DQT   |      67
   52194 | 0xffc0 SOF0  |      17
   52213 | 0xffc4 DHT   |      28
   52243 | 0xffc4 DHT   |      67
   52312 | 0xffc4 DHT   |      27
   52341 | 0xffc4 DHT   |      49
   52392 | 0xffda SOS

So http://ns.adobe.com/xap/1.0/ buffer header may work for tests. But even with this it looks like metadata.xmp buffer is wrong.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that byte length of both xmp and iptc property returned are equal. And content looks similar. Seems like we don't get appropriate buffers.

@oaleynik
Copy link
Contributor Author

oaleynik commented Jan 9, 2018

@lovell I've added tests for buffer length for both xmp and iptc properties. Also for iptc I have test for first bytes which should equal to Photoshop word. These tests should be failing now - looks like buffers which we get are wrong.

Copy link
Owner

@lovell lovell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello, the tests are failing as the ICC blob is erroneously being used - I've added a couple of comments inline.

src/metadata.cc Outdated
// IPTC
if (image.get_typeof(VIPS_META_IPCT_NAME) == VIPS_TYPE_BLOB) {
size_t iptcLength;
void const *iptc = image.get_blob(VIPS_META_ICC_NAME, &iptcLength);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-        void const *iptc = image.get_blob(VIPS_META_ICC_NAME, &iptcLength);
+        void const *iptc = image.get_blob(VIPS_META_IPTC_NAME, &iptcLength);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lovell fixed. Tests passing locally. Waiting for CI

src/metadata.cc Outdated
// XMP
if (image.get_typeof(VIPS_META_XMP_NAME) == VIPS_TYPE_BLOB) {
size_t xmpLength;
void const *xmp = image.get_blob(VIPS_META_ICC_NAME, &xmpLength);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-        void const *xmp = image.get_blob(VIPS_META_ICC_NAME, &xmpLength);
+        void const *xmp = image.get_blob(VIPS_META_XMP_NAME, &xmpLength);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uh, silly me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lovell fixed. Tests passing locally. Waiting for CI

@coveralls
Copy link

coveralls commented Jan 10, 2018

Coverage Status

Coverage remained the same at 99.226% when pulling 47ff8c0 on oaleynik:feat__iptc-xmp into 8afcb16 on lovell:master.

@oaleynik
Copy link
Contributor Author

Added one more test for xmp:

assert.strictEqual(metadata.xmp.indexOf(Buffer.from('http://ns.adobe.com/xap/1.0')), 0);

@oaleynik
Copy link
Contributor Author

@lovell strange failure in AppVayor

@coveralls
Copy link

coveralls commented Jan 10, 2018

Coverage Status

Coverage remained the same at 99.226% when pulling 99c49f3 on oaleynik:feat__iptc-xmp into 8afcb16 on lovell:master.

@lovell lovell merged commit c4df115 into lovell:master Jan 10, 2018
@lovell
Copy link
Owner

lovell commented Jan 10, 2018

Brilliant, thank you Oleg, this will be in v0.19.0.

@lovell lovell added this to the v0.19.0 milestone Jan 10, 2018
@oaleynik
Copy link
Contributor Author

Woot! Thanks for helping @lovell @jcupitt!

lovell added a commit that referenced this pull request Jan 10, 2018
@oaleynik oaleynik deleted the feat__iptc-xmp branch January 11, 2018 00:49
@rayshan
Copy link
Contributor

rayshan commented Jan 16, 2018

Thanks you guys rock! Will try later.

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.

5 participants