Add chromaSubsampling and isProgressive to metadata #1186

This commit is contained in:
Lovell Fuller 2018-10-02 17:11:25 +01:00
parent 60438ebfe5
commit 17f942c802
6 changed files with 96 additions and 0 deletions

View File

@ -31,6 +31,8 @@ A Promises/A+ promise is returned when `callback` is not provided.
- `channels`: Number of bands e.g. `3` for sRGB, `4` for CMYK - `channels`: Number of bands e.g. `3` for sRGB, `4` for CMYK
- `depth`: Name of pixel depth format e.g. `uchar`, `char`, `ushort`, `float` [...][2] - `depth`: Name of pixel depth format e.g. `uchar`, `char`, `ushort`, `float` [...][2]
- `density`: Number of pixels per inch (DPI), if present - `density`: Number of pixels per inch (DPI), if present
- `chromaSubsampling`: String containing JPEG chroma subsampling, `4:2:0` or `4:4:4` for RGB, `4:2:0:4` or `4:4:4:4` for CMYK
- `isProgressive`: Boolean indicating whether the image is interlaced using a progressive scan
- `hasProfile`: Boolean indicating the presence of an embedded ICC profile - `hasProfile`: Boolean indicating the presence of an embedded ICC profile
- `hasAlpha`: Boolean indicating the presence of an alpha transparency channel - `hasAlpha`: Boolean indicating the presence of an alpha transparency channel
- `orientation`: Number value of the EXIF Orientation header, if present - `orientation`: Number value of the EXIF Orientation header, if present

View File

@ -22,6 +22,9 @@ Requires libvips v8.7.0.
* Switch from custom trim operation to `vips_find_trim`. * Switch from custom trim operation to `vips_find_trim`.
[#914](https://github.com/lovell/sharp/issues/914) [#914](https://github.com/lovell/sharp/issues/914)
* Add `chromaSubsampling` and `isProgressive` properties to `metadata` response.
[#1186](https://github.com/lovell/sharp/issues/1186)
* Drop Node 4 support. * Drop Node 4 support.
[#1212](https://github.com/lovell/sharp/issues/1212) [#1212](https://github.com/lovell/sharp/issues/1212)

View File

@ -183,6 +183,8 @@ function clone () {
* - `channels`: Number of bands e.g. `3` for sRGB, `4` for CMYK * - `channels`: Number of bands e.g. `3` for sRGB, `4` for CMYK
* - `depth`: Name of pixel depth format e.g. `uchar`, `char`, `ushort`, `float` [...](https://github.com/libvips/libvips/blob/master/libvips/iofuncs/enumtypes.c#L672) * - `depth`: Name of pixel depth format e.g. `uchar`, `char`, `ushort`, `float` [...](https://github.com/libvips/libvips/blob/master/libvips/iofuncs/enumtypes.c#L672)
* - `density`: Number of pixels per inch (DPI), if present * - `density`: Number of pixels per inch (DPI), if present
* - `chromaSubsampling`: String containing JPEG chroma subsampling, `4:2:0` or `4:4:4` for RGB, `4:2:0:4` or `4:4:4:4` for CMYK
* - `isProgressive`: Boolean indicating whether the image is interlaced using a progressive scan
* - `hasProfile`: Boolean indicating the presence of an embedded ICC profile * - `hasProfile`: Boolean indicating the presence of an embedded ICC profile
* - `hasAlpha`: Boolean indicating the presence of an alpha transparency channel * - `hasAlpha`: Boolean indicating the presence of an alpha transparency channel
* - `orientation`: Number value of the EXIF Orientation header, if present * - `orientation`: Number value of the EXIF Orientation header, if present

View File

@ -62,6 +62,12 @@ class MetadataWorker : public Nan::AsyncWorker {
if (sharp::HasDensity(image)) { if (sharp::HasDensity(image)) {
baton->density = sharp::GetDensity(image); baton->density = sharp::GetDensity(image);
} }
if (image.get_typeof("jpeg-chroma-subsample") == VIPS_TYPE_REF_STRING) {
baton->chromaSubsampling = image.get_string("jpeg-chroma-subsample");
}
if (image.get_typeof("interlaced") == G_TYPE_INT) {
baton->isProgressive = image.get_int("interlaced") == 1;
}
baton->hasProfile = sharp::HasProfile(image); baton->hasProfile = sharp::HasProfile(image);
// Derived attributes // Derived attributes
baton->hasAlpha = sharp::HasAlpha(image); baton->hasAlpha = sharp::HasAlpha(image);
@ -125,6 +131,12 @@ class MetadataWorker : public Nan::AsyncWorker {
if (baton->density > 0) { if (baton->density > 0) {
Set(info, New("density").ToLocalChecked(), New<v8::Uint32>(baton->density)); Set(info, New("density").ToLocalChecked(), New<v8::Uint32>(baton->density));
} }
if (!baton->chromaSubsampling.empty()) {
Set(info,
New("chromaSubsampling").ToLocalChecked(),
New<v8::String>(baton->chromaSubsampling).ToLocalChecked());
}
Set(info, New("isProgressive").ToLocalChecked(), New<v8::Boolean>(baton->isProgressive));
Set(info, New("hasProfile").ToLocalChecked(), New<v8::Boolean>(baton->hasProfile)); Set(info, New("hasProfile").ToLocalChecked(), New<v8::Boolean>(baton->hasProfile));
Set(info, New("hasAlpha").ToLocalChecked(), New<v8::Boolean>(baton->hasAlpha)); Set(info, New("hasAlpha").ToLocalChecked(), New<v8::Boolean>(baton->hasAlpha));
if (baton->orientation > 0) { if (baton->orientation > 0) {

View File

@ -31,6 +31,8 @@ struct MetadataBaton {
int channels; int channels;
std::string depth; std::string depth;
int density; int density;
std::string chromaSubsampling;
bool isProgressive;
bool hasProfile; bool hasProfile;
bool hasAlpha; bool hasAlpha;
int orientation; int orientation;
@ -50,6 +52,7 @@ struct MetadataBaton {
height(0), height(0),
channels(0), channels(0),
density(0), density(0),
isProgressive(false),
hasProfile(false), hasProfile(false),
hasAlpha(false), hasAlpha(false),
orientation(0), orientation(0),

View File

@ -19,6 +19,8 @@ describe('Image metadata', function () {
assert.strictEqual(3, metadata.channels); assert.strictEqual(3, metadata.channels);
assert.strictEqual('uchar', metadata.depth); assert.strictEqual('uchar', metadata.depth);
assert.strictEqual('undefined', typeof metadata.density); assert.strictEqual('undefined', typeof metadata.density);
assert.strictEqual('4:2:0', metadata.chromaSubsampling);
assert.strictEqual(false, metadata.isProgressive);
assert.strictEqual(false, metadata.hasProfile); assert.strictEqual(false, metadata.hasProfile);
assert.strictEqual(false, metadata.hasAlpha); assert.strictEqual(false, metadata.hasAlpha);
assert.strictEqual('undefined', typeof metadata.orientation); assert.strictEqual('undefined', typeof metadata.orientation);
@ -38,6 +40,8 @@ describe('Image metadata', function () {
assert.strictEqual(3, metadata.channels); assert.strictEqual(3, metadata.channels);
assert.strictEqual('uchar', metadata.depth); assert.strictEqual('uchar', metadata.depth);
assert.strictEqual(72, metadata.density); assert.strictEqual(72, metadata.density);
assert.strictEqual('4:2:0', metadata.chromaSubsampling);
assert.strictEqual(false, metadata.isProgressive);
assert.strictEqual(true, metadata.hasProfile); assert.strictEqual(true, metadata.hasProfile);
assert.strictEqual(false, metadata.hasAlpha); assert.strictEqual(false, metadata.hasAlpha);
assert.strictEqual(8, metadata.orientation); assert.strictEqual(8, metadata.orientation);
@ -85,6 +89,8 @@ describe('Image metadata', function () {
assert.strictEqual(1, metadata.channels); assert.strictEqual(1, metadata.channels);
assert.strictEqual('uchar', metadata.depth); assert.strictEqual('uchar', metadata.depth);
assert.strictEqual(300, metadata.density); assert.strictEqual(300, metadata.density);
assert.strictEqual('undefined', typeof metadata.chromaSubsampling);
assert.strictEqual(false, metadata.isProgressive);
assert.strictEqual(false, metadata.hasProfile); assert.strictEqual(false, metadata.hasProfile);
assert.strictEqual(false, metadata.hasAlpha); assert.strictEqual(false, metadata.hasAlpha);
assert.strictEqual(1, metadata.orientation); assert.strictEqual(1, metadata.orientation);
@ -104,6 +110,8 @@ describe('Image metadata', function () {
assert.strictEqual(1, metadata.channels); assert.strictEqual(1, metadata.channels);
assert.strictEqual('uchar', metadata.depth); assert.strictEqual('uchar', metadata.depth);
assert.strictEqual(300, metadata.density); assert.strictEqual(300, metadata.density);
assert.strictEqual('undefined', typeof metadata.chromaSubsampling);
assert.strictEqual(false, metadata.isProgressive);
assert.strictEqual(false, metadata.hasProfile); assert.strictEqual(false, metadata.hasProfile);
assert.strictEqual(false, metadata.hasAlpha); assert.strictEqual(false, metadata.hasAlpha);
assert.strictEqual('undefined', typeof metadata.orientation); assert.strictEqual('undefined', typeof metadata.orientation);
@ -123,6 +131,8 @@ describe('Image metadata', function () {
assert.strictEqual(4, metadata.channels); assert.strictEqual(4, metadata.channels);
assert.strictEqual('uchar', metadata.depth); assert.strictEqual('uchar', metadata.depth);
assert.strictEqual(72, metadata.density); assert.strictEqual(72, metadata.density);
assert.strictEqual('undefined', typeof metadata.chromaSubsampling);
assert.strictEqual(false, metadata.isProgressive);
assert.strictEqual(false, metadata.hasProfile); assert.strictEqual(false, metadata.hasProfile);
assert.strictEqual(true, metadata.hasAlpha); assert.strictEqual(true, metadata.hasAlpha);
assert.strictEqual('undefined', typeof metadata.orientation); assert.strictEqual('undefined', typeof metadata.orientation);
@ -142,6 +152,8 @@ describe('Image metadata', function () {
assert.strictEqual(3, metadata.channels); assert.strictEqual(3, metadata.channels);
assert.strictEqual('uchar', metadata.depth); assert.strictEqual('uchar', metadata.depth);
assert.strictEqual('undefined', typeof metadata.density); assert.strictEqual('undefined', typeof metadata.density);
assert.strictEqual('undefined', typeof metadata.chromaSubsampling);
assert.strictEqual(false, metadata.isProgressive);
assert.strictEqual(false, metadata.hasProfile); assert.strictEqual(false, metadata.hasProfile);
assert.strictEqual(false, metadata.hasAlpha); assert.strictEqual(false, metadata.hasAlpha);
assert.strictEqual('undefined', typeof metadata.orientation); assert.strictEqual('undefined', typeof metadata.orientation);
@ -160,6 +172,8 @@ describe('Image metadata', function () {
assert.strictEqual(3, metadata.channels); assert.strictEqual(3, metadata.channels);
assert.strictEqual('uchar', metadata.depth); assert.strictEqual('uchar', metadata.depth);
assert.strictEqual('undefined', typeof metadata.density); assert.strictEqual('undefined', typeof metadata.density);
assert.strictEqual('undefined', typeof metadata.chromaSubsampling);
assert.strictEqual(false, metadata.isProgressive);
assert.strictEqual(false, metadata.hasProfile); assert.strictEqual(false, metadata.hasProfile);
assert.strictEqual(false, metadata.hasAlpha); assert.strictEqual(false, metadata.hasAlpha);
assert.strictEqual('undefined', typeof metadata.orientation); assert.strictEqual('undefined', typeof metadata.orientation);
@ -177,6 +191,8 @@ describe('Image metadata', function () {
assert.strictEqual(2, metadata.channels); assert.strictEqual(2, metadata.channels);
assert.strictEqual('uchar', metadata.depth); assert.strictEqual('uchar', metadata.depth);
assert.strictEqual('undefined', typeof metadata.density); assert.strictEqual('undefined', typeof metadata.density);
assert.strictEqual('undefined', typeof metadata.chromaSubsampling);
assert.strictEqual(false, metadata.isProgressive);
assert.strictEqual(false, metadata.hasProfile); assert.strictEqual(false, metadata.hasProfile);
assert.strictEqual(true, metadata.hasAlpha); assert.strictEqual(true, metadata.hasAlpha);
assert.strictEqual('undefined', typeof metadata.orientation); assert.strictEqual('undefined', typeof metadata.orientation);
@ -195,6 +211,8 @@ describe('Image metadata', function () {
assert.strictEqual(3, metadata.channels); assert.strictEqual(3, metadata.channels);
assert.strictEqual('uchar', metadata.depth); assert.strictEqual('uchar', metadata.depth);
assert.strictEqual('undefined', typeof metadata.density); assert.strictEqual('undefined', typeof metadata.density);
assert.strictEqual('4:2:0', metadata.chromaSubsampling);
assert.strictEqual(false, metadata.isProgressive);
assert.strictEqual(false, metadata.hasProfile); assert.strictEqual(false, metadata.hasProfile);
assert.strictEqual(false, metadata.hasAlpha); assert.strictEqual(false, metadata.hasAlpha);
assert.strictEqual('undefined', typeof metadata.orientation); assert.strictEqual('undefined', typeof metadata.orientation);
@ -224,6 +242,8 @@ describe('Image metadata', function () {
assert.strictEqual(3, metadata.channels); assert.strictEqual(3, metadata.channels);
assert.strictEqual('uchar', metadata.depth); assert.strictEqual('uchar', metadata.depth);
assert.strictEqual('undefined', typeof metadata.density); assert.strictEqual('undefined', typeof metadata.density);
assert.strictEqual('4:2:0', metadata.chromaSubsampling);
assert.strictEqual(false, metadata.isProgressive);
assert.strictEqual(false, metadata.hasProfile); assert.strictEqual(false, metadata.hasProfile);
assert.strictEqual(false, metadata.hasAlpha); assert.strictEqual(false, metadata.hasAlpha);
assert.strictEqual('undefined', typeof metadata.orientation); assert.strictEqual('undefined', typeof metadata.orientation);
@ -247,6 +267,8 @@ describe('Image metadata', function () {
assert.strictEqual(3, metadata.channels); assert.strictEqual(3, metadata.channels);
assert.strictEqual('uchar', metadata.depth); assert.strictEqual('uchar', metadata.depth);
assert.strictEqual('undefined', typeof metadata.density); assert.strictEqual('undefined', typeof metadata.density);
assert.strictEqual('4:2:0', metadata.chromaSubsampling);
assert.strictEqual(false, metadata.isProgressive);
assert.strictEqual(false, metadata.hasProfile); assert.strictEqual(false, metadata.hasProfile);
assert.strictEqual(false, metadata.hasAlpha); assert.strictEqual(false, metadata.hasAlpha);
assert.strictEqual('undefined', typeof metadata.orientation); assert.strictEqual('undefined', typeof metadata.orientation);
@ -268,6 +290,8 @@ describe('Image metadata', function () {
assert.strictEqual(3, metadata.channels); assert.strictEqual(3, metadata.channels);
assert.strictEqual('uchar', metadata.depth); assert.strictEqual('uchar', metadata.depth);
assert.strictEqual('undefined', typeof metadata.density); assert.strictEqual('undefined', typeof metadata.density);
assert.strictEqual('4:2:0', metadata.chromaSubsampling);
assert.strictEqual(false, metadata.isProgressive);
assert.strictEqual(false, metadata.hasProfile); assert.strictEqual(false, metadata.hasProfile);
assert.strictEqual(false, metadata.hasAlpha); assert.strictEqual(false, metadata.hasAlpha);
assert.strictEqual('undefined', typeof metadata.orientation); assert.strictEqual('undefined', typeof metadata.orientation);
@ -346,6 +370,56 @@ describe('Image metadata', function () {
}); });
}); });
it('chromaSubsampling 4:4:4:4 CMYK JPEG', function () {
return sharp(fixtures.inputJpgWithCmykProfile)
.metadata()
.then(function (metadata) {
assert.strictEqual('4:4:4:4', metadata.chromaSubsampling);
});
});
it('chromaSubsampling 4:4:4 RGB JPEG', function () {
return sharp(fixtures.inputJpg)
.resize(10, 10)
.jpeg({ chromaSubsampling: '4:4:4' })
.toBuffer()
.then(function (data) {
return sharp(data)
.metadata()
.then(function (metadata) {
assert.strictEqual('4:4:4', metadata.chromaSubsampling);
});
});
});
it('isProgressive JPEG', function () {
return sharp(fixtures.inputJpg)
.resize(10, 10)
.jpeg({ progressive: true })
.toBuffer()
.then(function (data) {
return sharp(data)
.metadata()
.then(function (metadata) {
assert.strictEqual(true, metadata.isProgressive);
});
});
});
it('isProgressive PNG', function () {
return sharp(fixtures.inputJpg)
.resize(10, 10)
.png({ progressive: true })
.toBuffer()
.then(function (data) {
return sharp(data)
.metadata()
.then(function (metadata) {
assert.strictEqual(true, metadata.isProgressive);
});
});
});
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) {