mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 10:30:15 +02:00
Expose IPTC and XMP metadata when available (#1079)
This commit is contained in:
parent
8afcb16d8e
commit
c4df115948
@ -182,6 +182,8 @@ function clone () {
|
|||||||
* - `orientation`: Number value of the EXIF Orientation header, if present
|
* - `orientation`: Number value of the EXIF Orientation header, if present
|
||||||
* - `exif`: Buffer containing raw EXIF data, 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
|
* - `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
|
* @example
|
||||||
* const image = sharp(inputJpg);
|
* const image = sharp(inputJpg);
|
||||||
|
@ -41,7 +41,8 @@
|
|||||||
"Matt Parrish <matt.r.parrish@gmail.com>",
|
"Matt Parrish <matt.r.parrish@gmail.com>",
|
||||||
"Matthew McEachen <matthew+github@mceachen.org>",
|
"Matthew McEachen <matthew+github@mceachen.org>",
|
||||||
"Jarda Kotěšovec <jarda.kotesovec@gmail.com>",
|
"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": {
|
"scripts": {
|
||||||
"clean": "rm -rf node_modules/ build/ vendor/ coverage/ test/fixtures/output.*",
|
"clean": "rm -rf node_modules/ build/ vendor/ coverage/ test/fixtures/output.*",
|
||||||
|
@ -81,6 +81,22 @@ class MetadataWorker : public Nan::AsyncWorker {
|
|||||||
memcpy(baton->icc, icc, iccLength);
|
memcpy(baton->icc, icc, iccLength);
|
||||||
baton->iccLength = 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
|
// Clean up
|
||||||
@ -123,6 +139,16 @@ class MetadataWorker : public Nan::AsyncWorker {
|
|||||||
New("icc").ToLocalChecked(),
|
New("icc").ToLocalChecked(),
|
||||||
Nan::NewBuffer(baton->icc, baton->iccLength, sharp::FreeCallback, nullptr).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;
|
argv[1] = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +38,10 @@ struct MetadataBaton {
|
|||||||
size_t exifLength;
|
size_t exifLength;
|
||||||
char *icc;
|
char *icc;
|
||||||
size_t iccLength;
|
size_t iccLength;
|
||||||
|
char *iptc;
|
||||||
|
size_t iptcLength;
|
||||||
|
char *xmp;
|
||||||
|
size_t xmpLength;
|
||||||
std::string err;
|
std::string err;
|
||||||
|
|
||||||
MetadataBaton():
|
MetadataBaton():
|
||||||
@ -52,7 +56,11 @@ struct MetadataBaton {
|
|||||||
exif(nullptr),
|
exif(nullptr),
|
||||||
exifLength(0),
|
exifLength(0),
|
||||||
icc(nullptr),
|
icc(nullptr),
|
||||||
iccLength(0) {}
|
iccLength(0),
|
||||||
|
iptc(nullptr),
|
||||||
|
iptcLength(0),
|
||||||
|
xmp(nullptr),
|
||||||
|
xmpLength(0) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
NAN_METHOD(metadata);
|
NAN_METHOD(metadata);
|
||||||
|
BIN
test/fixtures/Landscape_9.jpg
vendored
Normal file
BIN
test/fixtures/Landscape_9.jpg
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 91 KiB |
1
test/fixtures/index.js
vendored
1
test/fixtures/index.js
vendored
@ -57,6 +57,7 @@ module.exports = {
|
|||||||
|
|
||||||
inputJpg: getPath('2569067123_aca715a2ee_o.jpg'), // http://www.flickr.com/photos/grizdave/2569067123/
|
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
|
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
|
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
|
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
|
inputJpgWithCmykProfile: getPath('Channel_digital_image_CMYK_color.jpg'), // http://en.wikipedia.org/wiki/File:Channel_digital_image_CMYK_color.jpg
|
||||||
|
@ -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) {
|
it('TIFF', function (done) {
|
||||||
sharp(fixtures.inputTiff).metadata(function (err, metadata) {
|
sharp(fixtures.inputTiff).metadata(function (err, metadata) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user