Expose raw TIFFTAG_PHOTOSHOP metadata #1600

This commit is contained in:
Lovell Fuller 2019-11-29 13:05:07 +00:00
parent 400ef71b6f
commit d31a91a599
8 changed files with 40 additions and 1 deletions

View File

@ -44,6 +44,7 @@ A `Promise` is returned when `callback` is not provided.
- `icc`: Buffer containing raw [ICC][3] profile data, if present - `icc`: Buffer containing raw [ICC][3] profile data, if present
- `iptc`: Buffer containing raw IPTC data, if present - `iptc`: Buffer containing raw IPTC data, if present
- `xmp`: Buffer containing raw XMP data, if present - `xmp`: Buffer containing raw XMP data, if present
- `tifftagPhotoshop`: Buffer containing raw TIFFTAG_PHOTOSHOP data, if present
### Parameters ### Parameters

View File

@ -8,6 +8,9 @@ Requires libvips v8.8.1.
* Handle zero-length Buffer objects when using Node.js v13.2.0+. * Handle zero-length Buffer objects when using Node.js v13.2.0+.
* Expose raw TIFFTAG_PHOTOSHOP metadata.
[#1600](https://github.com/lovell/sharp/issues/1600)
* Improve thread safety by using copy-on-write when updating metadata. * Improve thread safety by using copy-on-write when updating metadata.
[#1986](https://github.com/lovell/sharp/issues/1986) [#1986](https://github.com/lovell/sharp/issues/1986)

View File

@ -207,6 +207,7 @@ function clone () {
* - `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 * - `iptc`: Buffer containing raw IPTC data, if present
* - `xmp`: Buffer containing raw XMP data, if present * - `xmp`: Buffer containing raw XMP data, if present
* - `tifftagPhotoshop`: Buffer containing raw TIFFTAG_PHOTOSHOP data, if present
* *
* @example * @example
* const image = sharp(inputJpg); * const image = sharp(inputJpg);

View File

@ -116,6 +116,14 @@ class MetadataWorker : public Nan::AsyncWorker {
memcpy(baton->xmp, xmp, xmpLength); memcpy(baton->xmp, xmp, xmpLength);
baton->xmpLength = xmpLength; baton->xmpLength = xmpLength;
} }
// TIFFTAG_PHOTOSHOP
if (image.get_typeof(VIPS_META_PHOTOSHOP_NAME) == VIPS_TYPE_BLOB) {
size_t tifftagPhotoshopLength;
void const *tifftagPhotoshop = image.get_blob(VIPS_META_PHOTOSHOP_NAME, &tifftagPhotoshopLength);
baton->tifftagPhotoshop = static_cast<char *>(g_malloc(tifftagPhotoshopLength));
memcpy(baton->tifftagPhotoshop, tifftagPhotoshop, tifftagPhotoshopLength);
baton->tifftagPhotoshopLength = tifftagPhotoshopLength;
}
} }
// Clean up // Clean up
@ -189,6 +197,12 @@ class MetadataWorker : public Nan::AsyncWorker {
New("xmp").ToLocalChecked(), New("xmp").ToLocalChecked(),
Nan::NewBuffer(baton->xmp, baton->xmpLength, sharp::FreeCallback, nullptr).ToLocalChecked()); Nan::NewBuffer(baton->xmp, baton->xmpLength, sharp::FreeCallback, nullptr).ToLocalChecked());
} }
if (baton->tifftagPhotoshopLength > 0) {
Set(info,
New("tifftagPhotoshop").ToLocalChecked(),
Nan::NewBuffer(baton->tifftagPhotoshop, baton->tifftagPhotoshopLength, sharp::FreeCallback, nullptr)
.ToLocalChecked());
}
argv[1] = info; argv[1] = info;
} }

View File

@ -48,6 +48,8 @@ struct MetadataBaton {
size_t iptcLength; size_t iptcLength;
char *xmp; char *xmp;
size_t xmpLength; size_t xmpLength;
char *tifftagPhotoshop;
size_t tifftagPhotoshopLength;
std::string err; std::string err;
MetadataBaton(): MetadataBaton():
@ -71,7 +73,9 @@ struct MetadataBaton {
iptc(nullptr), iptc(nullptr),
iptcLength(0), iptcLength(0),
xmp(nullptr), xmp(nullptr),
xmpLength(0) {} xmpLength(0),
tifftagPhotoshop(nullptr),
tifftagPhotoshopLength(0) {}
}; };
NAN_METHOD(metadata); NAN_METHOD(metadata);

View File

@ -97,6 +97,7 @@ module.exports = {
inputTiffCielab: getPath('cielab-dagams.tiff'), // https://github.com/lovell/sharp/issues/646 inputTiffCielab: getPath('cielab-dagams.tiff'), // https://github.com/lovell/sharp/issues/646
inputTiffUncompressed: getPath('uncompressed_tiff.tiff'), // https://code.google.com/archive/p/imagetestsuite/wikis/TIFFTestSuite.wiki file: 0c84d07e1b22b76f24cccc70d8788e4a.tif inputTiffUncompressed: getPath('uncompressed_tiff.tiff'), // https://code.google.com/archive/p/imagetestsuite/wikis/TIFFTestSuite.wiki file: 0c84d07e1b22b76f24cccc70d8788e4a.tif
inputTiff8BitDepth: getPath('8bit_depth.tiff'), inputTiff8BitDepth: getPath('8bit_depth.tiff'),
inputTifftagPhotoshop: getPath('tifftag-photoshop.tiff'), // https://github.com/lovell/sharp/issues/1600
inputGif: getPath('Crash_test.gif'), // http://upload.wikimedia.org/wikipedia/commons/e/e3/Crash_test.gif inputGif: getPath('Crash_test.gif'), // http://upload.wikimedia.org/wikipedia/commons/e/e3/Crash_test.gif
inputGifGreyPlusAlpha: getPath('grey-plus-alpha.gif'), // http://i.imgur.com/gZ5jlmE.gif inputGifGreyPlusAlpha: getPath('grey-plus-alpha.gif'), // http://i.imgur.com/gZ5jlmE.gif
inputGifAnimated: getPath('rotating-squares.gif'), // CC0 https://loading.io/spinner/blocks/-rotating-squares-preloader-gif inputGifAnimated: getPath('rotating-squares.gif'), // CC0 https://loading.io/spinner/blocks/-rotating-squares-preloader-gif

BIN
test/fixtures/tifftag-photoshop.tiff vendored Normal file

Binary file not shown.

View File

@ -515,6 +515,21 @@ describe('Image metadata', function () {
}); });
}); });
it('16-bit TIFF with TIFFTAG_PHOTOSHOP metadata', () =>
sharp(fixtures.inputTifftagPhotoshop)
.metadata()
.then(metadata => {
assert.strictEqual(metadata.format, 'tiff');
assert.strictEqual(metadata.width, 317);
assert.strictEqual(metadata.height, 211);
assert.strictEqual(metadata.space, 'rgb16');
assert.strictEqual(metadata.channels, 3);
assert.strictEqual(typeof metadata.tifftagPhotoshop, 'object');
assert.strictEqual(metadata.tifftagPhotoshop instanceof Buffer, true);
assert.strictEqual(metadata.tifftagPhotoshop.length, 6634);
})
);
it('File input with corrupt header fails gracefully', function (done) { it('File input with corrupt header fails gracefully', function (done) {
sharp(fixtures.inputJpgWithCorruptHeader) sharp(fixtures.inputJpgWithCorruptHeader)
.metadata(function (err) { .metadata(function (err) {