Skip to content

Commit

Permalink
Expose IPTC and XMP metadata when available (#1079)
Browse files Browse the repository at this point in the history
  • Loading branch information
oaleynik authored and lovell committed Jan 10, 2018
1 parent 8afcb16 commit c4df115
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 2 deletions.
2 changes: 2 additions & 0 deletions lib/input.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ function clone () {
* - `orientation`: Number value of the EXIF Orientation header, if present
* - `exif`: Buffer containing raw EXIF data, if present
* - `icc`: Buffer containing raw [ICC](https://www.npmjs.com/package/icc) profile data, if present
* - `iptc`: Buffer containing raw IPTC data, if present
* - `xmp`: Buffer containing raw XMP data, if present
*
* @example
* const image = sharp(inputJpg);
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@
"Matt Parrish <matt.r.parrish@gmail.com>",
"Matthew McEachen <matthew+github@mceachen.org>",
"Jarda Kotěšovec <jarda.kotesovec@gmail.com>",
"Kenric D'Souza <kenric.dsouza@gmail.com>"
"Kenric D'Souza <kenric.dsouza@gmail.com>",
"Oleh Aleinyk <oleg.aleynik@gmail.com>"
],
"scripts": {
"clean": "rm -rf node_modules/ build/ vendor/ coverage/ test/fixtures/output.*",
Expand Down
26 changes: 26 additions & 0 deletions src/metadata.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
size_t iptcLength;
void const *iptc = image.get_blob(VIPS_META_IPCT_NAME, &iptcLength);
baton->iptc = static_cast<char *>(g_malloc(iptcLength));
memcpy(baton->iptc, iptc, iptcLength);
baton->iptcLength = iptcLength;
}
// XMP
if (image.get_typeof(VIPS_META_XMP_NAME) == VIPS_TYPE_BLOB) {
size_t xmpLength;
void const *xmp = image.get_blob(VIPS_META_XMP_NAME, &xmpLength);
baton->xmp = static_cast<char *>(g_malloc(xmpLength));
memcpy(baton->xmp, xmp, xmpLength);
baton->xmpLength = xmpLength;
}
}

// Clean up
Expand Down Expand Up @@ -123,6 +139,16 @@ class MetadataWorker : public Nan::AsyncWorker {
New("icc").ToLocalChecked(),
Nan::NewBuffer(baton->icc, baton->iccLength, sharp::FreeCallback, nullptr).ToLocalChecked());
}
if (baton->iptcLength > 0) {
Set(info,
New("iptc").ToLocalChecked(),
Nan::NewBuffer(baton->iptc, baton->iptcLength, sharp::FreeCallback, nullptr).ToLocalChecked());
}
if (baton->xmpLength > 0) {
Set(info,
New("xmp").ToLocalChecked(),
Nan::NewBuffer(baton->xmp, baton->xmpLength, sharp::FreeCallback, nullptr).ToLocalChecked());
}
argv[1] = info;
}

Expand Down
10 changes: 9 additions & 1 deletion src/metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ struct MetadataBaton {
size_t exifLength;
char *icc;
size_t iccLength;
char *iptc;
size_t iptcLength;
char *xmp;
size_t xmpLength;
std::string err;

MetadataBaton():
Expand All @@ -52,7 +56,11 @@ struct MetadataBaton {
exif(nullptr),
exifLength(0),
icc(nullptr),
iccLength(0) {}
iccLength(0),
iptc(nullptr),
iptcLength(0),
xmp(nullptr),
xmpLength(0) {}
};

NAN_METHOD(metadata);
Expand Down
Binary file added test/fixtures/Landscape_9.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions test/fixtures/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
inputJpgWithExifMirroring: getPath('Landscape_5.jpg'), // https://github.com/recurser/exif-orientation-examples/blob/master/Landscape_5.jpg
inputJpgWithGammaHoliness: getPath('gamma_dalai_lama_gray.jpg'), // http://www.4p8.com/eric.brasseur/gamma.html
inputJpgWithCmykProfile: getPath('Channel_digital_image_CMYK_color.jpg'), // http://en.wikipedia.org/wiki/File:Channel_digital_image_CMYK_color.jpg
Expand Down
17 changes: 17 additions & 0 deletions test/unit/metadata.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,23 @@ describe('Image metadata', function () {
});
});

it('JPEG with IPTC/XMP', function (done) {
sharp(fixtures.inputJpgWithIptcAndXmp).metadata(function (err, metadata) {
if (err) throw err;
// IPTC
assert.strictEqual('object', typeof metadata.iptc);
assert.strictEqual(true, metadata.iptc instanceof Buffer);
assert.strictEqual(18250, metadata.iptc.byteLength);
assert.strictEqual(metadata.iptc.indexOf(Buffer.from('Photoshop')), 0);
// XMP
assert.strictEqual('object', typeof metadata.xmp);
assert.strictEqual(true, metadata.xmp instanceof Buffer);
assert.strictEqual(12495, metadata.xmp.byteLength);
assert.strictEqual(metadata.xmp.indexOf(Buffer.from('http://ns.adobe.com/xap/1.0')), 0);
done();
});
});

it('TIFF', function (done) {
sharp(fixtures.inputTiff).metadata(function (err, metadata) {
if (err) throw err;
Expand Down

0 comments on commit c4df115

Please sign in to comment.