diff --git a/README.md b/README.md index ffe6b749..e553949d 100755 --- a/README.md +++ b/README.md @@ -344,6 +344,7 @@ Fast access to image metadata without decoding any compressed image data. * `hasAlpha`: Boolean indicating the presence of an alpha transparency channel * `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 A Promises/A+ promise is returned when `callback` is not provided. diff --git a/package.json b/package.json index b75cd70a..49f90f64 100755 --- a/package.json +++ b/package.json @@ -51,9 +51,10 @@ "semver": "^4.3.6" }, "devDependencies": { - "async": "^1.2.1", + "async": "^1.3.0", "coveralls": "^2.11.2", "exif-reader": "1.0.0", + "icc": "^0.0.2", "istanbul": "^0.3.17", "mocha": "^2.2.5", "mocha-jshint": "^2.2.3", diff --git a/src/metadata.cc b/src/metadata.cc index e86df506..665954e5 100755 --- a/src/metadata.cc +++ b/src/metadata.cc @@ -40,12 +40,15 @@ struct MetadataBaton { int orientation; char *exif; size_t exifLength; + char *icc; + size_t iccLength; std::string err; MetadataBaton(): bufferInLength(0), orientation(0), - exifLength(0) {} + exifLength(0), + iccLength(0) {} }; /* @@ -130,6 +133,16 @@ class MetadataWorker : public NanAsyncWorker { memcpy(baton->exif, exif, exifLength); } } + // ICC profile + if (vips_image_get_typeof(image, VIPS_META_ICC_NAME) == VIPS_TYPE_BLOB) { + void* icc; + size_t iccLength; + if (!vips_image_get_blob(image, VIPS_META_ICC_NAME, &icc, &iccLength)) { + baton->iccLength = iccLength; + baton->icc = new char[iccLength]; + memcpy(baton->icc, icc, iccLength); + } + } // Drop image reference g_object_unref(image); } @@ -161,6 +174,9 @@ class MetadataWorker : public NanAsyncWorker { if (baton->exifLength > 0) { info->Set(NanNew("exif"), NanBufferUse(baton->exif, baton->exifLength)); } + if (baton->iccLength > 0) { + info->Set(NanNew("icc"), NanBufferUse(baton->icc, baton->iccLength)); + } argv[1] = info; } delete baton; diff --git a/test/unit/metadata.js b/test/unit/metadata.js index 48d7099e..2ccfa196 100755 --- a/test/unit/metadata.js +++ b/test/unit/metadata.js @@ -3,6 +3,7 @@ var fs = require('fs'); var assert = require('assert'); var exifReader = require('exif-reader'); +var icc = require('icc'); var sharp = require('../../index'); var fixtures = require('../fixtures'); @@ -23,11 +24,12 @@ describe('Image metadata', function() { assert.strictEqual(false, metadata.hasAlpha); assert.strictEqual('undefined', typeof metadata.orientation); assert.strictEqual('undefined', typeof metadata.exif); + assert.strictEqual('undefined', typeof metadata.icc); done(); }); }); - it('JPEG with EXIF', function(done) { + it('JPEG with EXIF/ICC', function(done) { sharp(fixtures.inputJpgWithExif).metadata(function(err, metadata) { if (err) throw err; assert.strictEqual('jpeg', metadata.format); @@ -38,12 +40,19 @@ describe('Image metadata', function() { assert.strictEqual(true, metadata.hasProfile); assert.strictEqual(false, metadata.hasAlpha); assert.strictEqual(8, metadata.orientation); + // EXIF assert.strictEqual('object', typeof metadata.exif); assert.strictEqual(true, metadata.exif instanceof Buffer); var exif = exifReader(metadata.exif); assert.strictEqual('object', typeof exif); assert.strictEqual('object', typeof exif.image); assert.strictEqual('number', typeof exif.image.XResolution); + // ICC + assert.strictEqual('object', typeof metadata.icc); + assert.strictEqual(true, metadata.icc instanceof Buffer); + var profile = icc.parse(metadata.icc); + assert.strictEqual('object', typeof profile); + assert.strictEqual('Generic RGB Profile', profile.description); done(); }); }); @@ -58,6 +67,9 @@ describe('Image metadata', function() { assert.strictEqual(1, metadata.channels); assert.strictEqual(false, metadata.hasProfile); assert.strictEqual(false, metadata.hasAlpha); + assert.strictEqual('undefined', typeof metadata.orientation); + assert.strictEqual('undefined', typeof metadata.exif); + assert.strictEqual('undefined', typeof metadata.icc); done(); }); }); @@ -72,6 +84,9 @@ describe('Image metadata', function() { assert.strictEqual(1, metadata.channels); assert.strictEqual(false, metadata.hasProfile); assert.strictEqual(false, metadata.hasAlpha); + assert.strictEqual('undefined', typeof metadata.orientation); + assert.strictEqual('undefined', typeof metadata.exif); + assert.strictEqual('undefined', typeof metadata.icc); done(); }); }); @@ -86,6 +101,9 @@ describe('Image metadata', function() { assert.strictEqual(4, metadata.channels); assert.strictEqual(false, metadata.hasProfile); assert.strictEqual(true, metadata.hasAlpha); + assert.strictEqual('undefined', typeof metadata.orientation); + assert.strictEqual('undefined', typeof metadata.exif); + assert.strictEqual('undefined', typeof metadata.icc); done(); }); }); @@ -101,6 +119,9 @@ describe('Image metadata', function() { assert.strictEqual(3, metadata.channels); assert.strictEqual(false, metadata.hasProfile); assert.strictEqual(false, metadata.hasAlpha); + assert.strictEqual('undefined', typeof metadata.orientation); + assert.strictEqual('undefined', typeof metadata.exif); + assert.strictEqual('undefined', typeof metadata.icc); done(); }); }); @@ -115,6 +136,9 @@ describe('Image metadata', function() { assert.strictEqual(3, metadata.channels); assert.strictEqual(false, metadata.hasProfile); assert.strictEqual(false, metadata.hasAlpha); + assert.strictEqual('undefined', typeof metadata.orientation); + assert.strictEqual('undefined', typeof metadata.exif); + assert.strictEqual('undefined', typeof metadata.icc); done(); }); }); @@ -130,6 +154,9 @@ describe('Image metadata', function() { assert.strictEqual('rgb', metadata.space); assert.strictEqual(false, metadata.hasProfile); assert.strictEqual(true, metadata.hasAlpha); + assert.strictEqual('undefined', typeof metadata.orientation); + assert.strictEqual('undefined', typeof metadata.exif); + assert.strictEqual('undefined', typeof metadata.icc); done(); }); }); @@ -144,6 +171,9 @@ describe('Image metadata', function() { assert.strictEqual(3, metadata.channels); assert.strictEqual(false, metadata.hasProfile); assert.strictEqual(false, metadata.hasAlpha); + assert.strictEqual('undefined', typeof metadata.orientation); + assert.strictEqual('undefined', typeof metadata.exif); + assert.strictEqual('undefined', typeof metadata.icc); done(); }); }); @@ -168,6 +198,9 @@ describe('Image metadata', function() { assert.strictEqual(3, metadata.channels); assert.strictEqual(false, metadata.hasProfile); assert.strictEqual(false, metadata.hasAlpha); + assert.strictEqual('undefined', typeof metadata.orientation); + assert.strictEqual('undefined', typeof metadata.exif); + assert.strictEqual('undefined', typeof metadata.icc); done(); }).catch(function(err) { throw err; @@ -186,6 +219,9 @@ describe('Image metadata', function() { assert.strictEqual(3, metadata.channels); assert.strictEqual(false, metadata.hasProfile); assert.strictEqual(false, metadata.hasAlpha); + assert.strictEqual('undefined', typeof metadata.orientation); + assert.strictEqual('undefined', typeof metadata.exif); + assert.strictEqual('undefined', typeof metadata.icc); done(); }); readable.pipe(pipeline); @@ -202,6 +238,9 @@ describe('Image metadata', function() { assert.strictEqual(3, metadata.channels); assert.strictEqual(false, metadata.hasProfile); assert.strictEqual(false, metadata.hasAlpha); + assert.strictEqual('undefined', typeof metadata.orientation); + assert.strictEqual('undefined', typeof metadata.exif); + assert.strictEqual('undefined', typeof metadata.icc); image.resize(Math.floor(metadata.width / 2)).toBuffer(function(err, data, info) { if (err) throw err; assert.strictEqual(true, data.length > 0); @@ -212,7 +251,7 @@ describe('Image metadata', function() { }); }); - it('Keep EXIF metadata after a resize', function(done) { + it('Keep EXIF metadata and add sRGB profile after a resize', function(done) { sharp(fixtures.inputJpgWithExif) .resize(320, 240) .withMetadata() @@ -222,6 +261,19 @@ describe('Image metadata', function() { if (err) throw err; assert.strictEqual(true, metadata.hasProfile); assert.strictEqual(8, metadata.orientation); + assert.strictEqual('object', typeof metadata.exif); + assert.strictEqual(true, metadata.exif instanceof Buffer); + // EXIF + var exif = exifReader(metadata.exif); + assert.strictEqual('object', typeof exif); + assert.strictEqual('object', typeof exif.image); + assert.strictEqual('number', typeof exif.image.XResolution); + // ICC + assert.strictEqual('object', typeof metadata.icc); + assert.strictEqual(true, metadata.icc instanceof Buffer); + var profile = icc.parse(metadata.icc); + assert.strictEqual('object', typeof profile); + assert.strictEqual('sRGB IEC61966-2-1 black scaled', profile.description); done(); }); }); @@ -237,6 +289,8 @@ describe('Image metadata', function() { if (err) throw err; assert.strictEqual(false, metadata.hasProfile); assert.strictEqual('undefined', typeof metadata.orientation); + assert.strictEqual('undefined', typeof metadata.exif); + assert.strictEqual('undefined', typeof metadata.icc); done(); }); });