mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 10:30:15 +02:00
Expose delay/loop metadata for animated images #1905
This commit is contained in:
parent
057074b238
commit
4a745f2d2e
@ -9,6 +9,9 @@ Requires libvips v8.9.0.
|
|||||||
* Drop support for Node.js 8.
|
* Drop support for Node.js 8.
|
||||||
[#1910](https://github.com/lovell/sharp/issues/1910)
|
[#1910](https://github.com/lovell/sharp/issues/1910)
|
||||||
|
|
||||||
|
* Expose `delay` and `loop` metadata for animated images.
|
||||||
|
[#1905](https://github.com/lovell/sharp/issues/1905)
|
||||||
|
|
||||||
* Ensure correct colour output for 16-bit, 2-channel PNG input with ICC profile.
|
* Ensure correct colour output for 16-bit, 2-channel PNG input with ICC profile.
|
||||||
[#2013](https://github.com/lovell/sharp/issues/2013)
|
[#2013](https://github.com/lovell/sharp/issues/2013)
|
||||||
|
|
||||||
|
@ -77,6 +77,12 @@ class MetadataWorker : public Nan::AsyncWorker {
|
|||||||
if (image.get_typeof(VIPS_META_PAGE_HEIGHT) == G_TYPE_INT) {
|
if (image.get_typeof(VIPS_META_PAGE_HEIGHT) == G_TYPE_INT) {
|
||||||
baton->pageHeight = image.get_int(VIPS_META_PAGE_HEIGHT);
|
baton->pageHeight = image.get_int(VIPS_META_PAGE_HEIGHT);
|
||||||
}
|
}
|
||||||
|
if (image.get_typeof("loop") == G_TYPE_INT) {
|
||||||
|
baton->loop = image.get_int("loop");
|
||||||
|
}
|
||||||
|
if (image.get_typeof("delay") == VIPS_TYPE_ARRAY_INT) {
|
||||||
|
baton->delay = image.get_array_int("delay");
|
||||||
|
}
|
||||||
if (image.get_typeof("heif-primary") == G_TYPE_INT) {
|
if (image.get_typeof("heif-primary") == G_TYPE_INT) {
|
||||||
baton->pagePrimary = image.get_int("heif-primary");
|
baton->pagePrimary = image.get_int("heif-primary");
|
||||||
}
|
}
|
||||||
@ -169,6 +175,17 @@ class MetadataWorker : public Nan::AsyncWorker {
|
|||||||
if (baton->pageHeight > 0) {
|
if (baton->pageHeight > 0) {
|
||||||
Set(info, New("pageHeight").ToLocalChecked(), New<v8::Uint32>(baton->pageHeight));
|
Set(info, New("pageHeight").ToLocalChecked(), New<v8::Uint32>(baton->pageHeight));
|
||||||
}
|
}
|
||||||
|
if (baton->loop >= 0) {
|
||||||
|
Set(info, New("loop").ToLocalChecked(), New<v8::Uint32>(baton->loop));
|
||||||
|
}
|
||||||
|
if (!baton->delay.empty()) {
|
||||||
|
int i = 0;
|
||||||
|
v8::Local<v8::Array> delay = New<v8::Array>(baton->delay.size());
|
||||||
|
for (int const d : baton->delay) {
|
||||||
|
Set(delay, i++, New<v8::Number>(d));
|
||||||
|
}
|
||||||
|
Set(info, New("delay").ToLocalChecked(), delay);
|
||||||
|
}
|
||||||
if (baton->pagePrimary > -1) {
|
if (baton->pagePrimary > -1) {
|
||||||
Set(info, New("pagePrimary").ToLocalChecked(), New<v8::Uint32>(baton->pagePrimary));
|
Set(info, New("pagePrimary").ToLocalChecked(), New<v8::Uint32>(baton->pagePrimary));
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,8 @@ struct MetadataBaton {
|
|||||||
int paletteBitDepth;
|
int paletteBitDepth;
|
||||||
int pages;
|
int pages;
|
||||||
int pageHeight;
|
int pageHeight;
|
||||||
|
int loop;
|
||||||
|
std::vector<int> delay;
|
||||||
int pagePrimary;
|
int pagePrimary;
|
||||||
bool hasProfile;
|
bool hasProfile;
|
||||||
bool hasAlpha;
|
bool hasAlpha;
|
||||||
@ -62,6 +64,7 @@ struct MetadataBaton {
|
|||||||
paletteBitDepth(0),
|
paletteBitDepth(0),
|
||||||
pages(0),
|
pages(0),
|
||||||
pageHeight(0),
|
pageHeight(0),
|
||||||
|
loop(-1),
|
||||||
pagePrimary(-1),
|
pagePrimary(-1),
|
||||||
hasProfile(false),
|
hasProfile(false),
|
||||||
hasAlpha(false),
|
hasAlpha(false),
|
||||||
|
BIN
test/fixtures/animated-loop-3.gif
vendored
Normal file
BIN
test/fixtures/animated-loop-3.gif
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.6 KiB |
1
test/fixtures/index.js
vendored
1
test/fixtures/index.js
vendored
@ -102,6 +102,7 @@ module.exports = {
|
|||||||
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
|
||||||
|
inputGifAnimatedLoop3: getPath('animated-loop-3.gif'), // CC-BY-SA-4.0 Petrus3743 https://commons.wikimedia.org/wiki/File:01-Goldener_Schnitt_Formel-Animation.gif
|
||||||
inputSvg: getPath('check.svg'), // http://dev.w3.org/SVG/tools/svgweb/samples/svg-files/check.svg
|
inputSvg: getPath('check.svg'), // http://dev.w3.org/SVG/tools/svgweb/samples/svg-files/check.svg
|
||||||
inputSvgWithEmbeddedImages: getPath('struct-image-04-t.svg'), // https://dev.w3.org/SVG/profiles/1.2T/test/svg/struct-image-04-t.svg
|
inputSvgWithEmbeddedImages: getPath('struct-image-04-t.svg'), // https://dev.w3.org/SVG/profiles/1.2T/test/svg/struct-image-04-t.svg
|
||||||
|
|
||||||
|
@ -232,6 +232,55 @@ describe('Image metadata', function () {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Animated GIF', () =>
|
||||||
|
sharp(fixtures.inputGifAnimated)
|
||||||
|
.metadata()
|
||||||
|
.then(({
|
||||||
|
format, width, height, space, channels, depth,
|
||||||
|
isProgressive, pages, pageHeight, loop, delay,
|
||||||
|
hasProfile, hasAlpha
|
||||||
|
}) => {
|
||||||
|
assert.strictEqual(format, 'gif');
|
||||||
|
assert.strictEqual(width, 80);
|
||||||
|
assert.strictEqual(height, 80);
|
||||||
|
assert.strictEqual(space, 'srgb');
|
||||||
|
assert.strictEqual(channels, 4);
|
||||||
|
assert.strictEqual(depth, 'uchar');
|
||||||
|
assert.strictEqual(isProgressive, false);
|
||||||
|
assert.strictEqual(pages, 30);
|
||||||
|
assert.strictEqual(pageHeight, 80);
|
||||||
|
assert.strictEqual(loop, 0);
|
||||||
|
assert.deepStrictEqual(delay, Array(30).fill(30));
|
||||||
|
assert.strictEqual(hasProfile, false);
|
||||||
|
assert.strictEqual(hasAlpha, true);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
it('Animated GIF with limited looping', () =>
|
||||||
|
sharp(fixtures.inputGifAnimatedLoop3)
|
||||||
|
.metadata()
|
||||||
|
.then(({
|
||||||
|
format, width, height, space, channels, depth,
|
||||||
|
isProgressive, pages, pageHeight, loop, delay,
|
||||||
|
hasProfile, hasAlpha
|
||||||
|
}) => {
|
||||||
|
assert.strictEqual(format, 'gif');
|
||||||
|
assert.strictEqual(width, 370);
|
||||||
|
assert.strictEqual(height, 285);
|
||||||
|
assert.strictEqual(space, 'srgb');
|
||||||
|
assert.strictEqual(channels, 4);
|
||||||
|
assert.strictEqual(depth, 'uchar');
|
||||||
|
assert.strictEqual(isProgressive, false);
|
||||||
|
assert.strictEqual(pages, 10);
|
||||||
|
assert.strictEqual(pageHeight, 285);
|
||||||
|
assert.strictEqual(loop, 3);
|
||||||
|
assert.deepStrictEqual(delay, [...Array(9).fill(3000), 15000]);
|
||||||
|
assert.strictEqual(hasProfile, false);
|
||||||
|
assert.strictEqual(hasAlpha, true);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
it('vips', () =>
|
it('vips', () =>
|
||||||
sharp(fixtures.inputV)
|
sharp(fixtures.inputV)
|
||||||
.metadata()
|
.metadata()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user