mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 10:30:15 +02:00
Add support for pages option for multi-page input #1566
This commit is contained in:
parent
7457b50373
commit
9cc06c887b
@ -12,7 +12,8 @@
|
|||||||
- `options.failOnError` **[Boolean][4]** by default halt processing and raise an error when loading invalid images.
|
- `options.failOnError` **[Boolean][4]** by default halt processing and raise an error when loading invalid images.
|
||||||
Set this flag to `false` if you'd rather apply a "best effort" to decode images, even if the data is corrupt or invalid. (optional, default `true`)
|
Set this flag to `false` if you'd rather apply a "best effort" to decode images, even if the data is corrupt or invalid. (optional, default `true`)
|
||||||
- `options.density` **[Number][5]** number representing the DPI for vector images. (optional, default `72`)
|
- `options.density` **[Number][5]** number representing the DPI for vector images. (optional, default `72`)
|
||||||
- `options.page` **[Number][5]** page number to extract for multi-page input (GIF, TIFF, PDF) (optional, default `0`)
|
- `options.pages` **[Number][5]** number of pages to extract for multi-page input (GIF, TIFF, PDF), use -1 for all pages. (optional, default `1`)
|
||||||
|
- `options.page` **[Number][5]** page number to start extracting from for multi-page input (GIF, TIFF, PDF), zero based. (optional, default `0`)
|
||||||
- `options.raw` **[Object][3]?** describes raw pixel input image data. See `raw()` for pixel ordering.
|
- `options.raw` **[Object][3]?** describes raw pixel input image data. See `raw()` for pixel ordering.
|
||||||
- `options.raw.width` **[Number][5]?**
|
- `options.raw.width` **[Number][5]?**
|
||||||
- `options.raw.height` **[Number][5]?**
|
- `options.raw.height` **[Number][5]?**
|
||||||
|
@ -12,6 +12,9 @@ Requires libvips v8.7.4.
|
|||||||
* Add `composite` operation supporting multiple images and blend modes; deprecate `overlayWith`.
|
* Add `composite` operation supporting multiple images and blend modes; deprecate `overlayWith`.
|
||||||
[#728](https://github.com/lovell/sharp/issues/728)
|
[#728](https://github.com/lovell/sharp/issues/728)
|
||||||
|
|
||||||
|
* Add support for `pages` input option for multi-page input.
|
||||||
|
[#1566](https://github.com/lovell/sharp/issues/1566)
|
||||||
|
|
||||||
* Add support for `page` input option to GIF and PDF.
|
* Add support for `page` input option to GIF and PDF.
|
||||||
[#1595](https://github.com/lovell/sharp/pull/1595)
|
[#1595](https://github.com/lovell/sharp/pull/1595)
|
||||||
[@ramiel](https://github.com/ramiel)
|
[@ramiel](https://github.com/ramiel)
|
||||||
|
@ -64,7 +64,8 @@ const debuglog = util.debuglog('sharp');
|
|||||||
* @param {Boolean} [options.failOnError=true] - by default halt processing and raise an error when loading invalid images.
|
* @param {Boolean} [options.failOnError=true] - by default halt processing and raise an error when loading invalid images.
|
||||||
* Set this flag to `false` if you'd rather apply a "best effort" to decode images, even if the data is corrupt or invalid.
|
* Set this flag to `false` if you'd rather apply a "best effort" to decode images, even if the data is corrupt or invalid.
|
||||||
* @param {Number} [options.density=72] - number representing the DPI for vector images.
|
* @param {Number} [options.density=72] - number representing the DPI for vector images.
|
||||||
* @param {Number} [options.page=0] - page number to extract for multi-page input (GIF, TIFF, PDF)
|
* @param {Number} [options.pages=1] - number of pages to extract for multi-page input (GIF, TIFF, PDF), use -1 for all pages.
|
||||||
|
* @param {Number} [options.page=0] - page number to start extracting from for multi-page input (GIF, TIFF, PDF), zero based.
|
||||||
* @param {Object} [options.raw] - describes raw pixel input image data. See `raw()` for pixel ordering.
|
* @param {Object} [options.raw] - describes raw pixel input image data. See `raw()` for pixel ordering.
|
||||||
* @param {Number} [options.raw.width]
|
* @param {Number} [options.raw.width]
|
||||||
* @param {Number} [options.raw.height]
|
* @param {Number} [options.raw.height]
|
||||||
|
@ -57,7 +57,12 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
|||||||
throw new Error('Expected width, height and channels for raw pixel input');
|
throw new Error('Expected width, height and channels for raw pixel input');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Page input for multi-page images (GIF, TIFF, PDF)
|
// Multi-page input (GIF, TIFF, PDF)
|
||||||
|
if (is.defined(inputOptions.pages)) {
|
||||||
|
if (is.integer(inputOptions.pages) && is.inRange(inputOptions.pages, -1, 100000)) {
|
||||||
|
inputDescriptor.pages = inputOptions.pages;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (is.defined(inputOptions.page)) {
|
if (is.defined(inputOptions.page)) {
|
||||||
if (is.integer(inputOptions.page) && is.inRange(inputOptions.page, 0, 100000)) {
|
if (is.integer(inputOptions.page) && is.inRange(inputOptions.page, 0, 100000)) {
|
||||||
inputDescriptor.page = inputOptions.page;
|
inputDescriptor.page = inputOptions.page;
|
||||||
|
@ -71,7 +71,10 @@ namespace sharp {
|
|||||||
descriptor->rawWidth = AttrTo<uint32_t>(input, "rawWidth");
|
descriptor->rawWidth = AttrTo<uint32_t>(input, "rawWidth");
|
||||||
descriptor->rawHeight = AttrTo<uint32_t>(input, "rawHeight");
|
descriptor->rawHeight = AttrTo<uint32_t>(input, "rawHeight");
|
||||||
}
|
}
|
||||||
// Page input for multi-page TIFF, PDF
|
// Multi-page input (GIF, TIFF, PDF)
|
||||||
|
if (HasAttr(input, "pages")) {
|
||||||
|
descriptor->pages = AttrTo<int32_t>(input, "pages");
|
||||||
|
}
|
||||||
if (HasAttr(input, "page")) {
|
if (HasAttr(input, "page")) {
|
||||||
descriptor->page = AttrTo<uint32_t>(input, "page");
|
descriptor->page = AttrTo<uint32_t>(input, "page");
|
||||||
}
|
}
|
||||||
@ -254,7 +257,8 @@ namespace sharp {
|
|||||||
option->set("density", std::to_string(descriptor->density).data());
|
option->set("density", std::to_string(descriptor->density).data());
|
||||||
}
|
}
|
||||||
if (ImageTypeSupportsPage(imageType)) {
|
if (ImageTypeSupportsPage(imageType)) {
|
||||||
option->set("page", descriptor->page);
|
option->set("n", descriptor->pages);
|
||||||
|
option->set("page", descriptor->page);
|
||||||
}
|
}
|
||||||
image = VImage::new_from_buffer(descriptor->buffer, descriptor->bufferLength, nullptr, option);
|
image = VImage::new_from_buffer(descriptor->buffer, descriptor->bufferLength, nullptr, option);
|
||||||
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
||||||
@ -299,7 +303,8 @@ namespace sharp {
|
|||||||
option->set("density", std::to_string(descriptor->density).data());
|
option->set("density", std::to_string(descriptor->density).data());
|
||||||
}
|
}
|
||||||
if (ImageTypeSupportsPage(imageType)) {
|
if (ImageTypeSupportsPage(imageType)) {
|
||||||
option->set("page", descriptor->page);
|
option->set("n", descriptor->pages);
|
||||||
|
option->set("page", descriptor->page);
|
||||||
}
|
}
|
||||||
image = VImage::new_from_file(descriptor->file.data(), option);
|
image = VImage::new_from_file(descriptor->file.data(), option);
|
||||||
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
||||||
|
@ -53,6 +53,7 @@ namespace sharp {
|
|||||||
int rawChannels;
|
int rawChannels;
|
||||||
int rawWidth;
|
int rawWidth;
|
||||||
int rawHeight;
|
int rawHeight;
|
||||||
|
int pages;
|
||||||
int page;
|
int page;
|
||||||
int createChannels;
|
int createChannels;
|
||||||
int createWidth;
|
int createWidth;
|
||||||
@ -67,6 +68,7 @@ namespace sharp {
|
|||||||
rawChannels(0),
|
rawChannels(0),
|
||||||
rawWidth(0),
|
rawWidth(0),
|
||||||
rawHeight(0),
|
rawHeight(0),
|
||||||
|
pages(1),
|
||||||
page(0),
|
page(0),
|
||||||
createChannels(0),
|
createChannels(0),
|
||||||
createWidth(0),
|
createWidth(0),
|
||||||
|
1
test/fixtures/index.js
vendored
1
test/fixtures/index.js
vendored
@ -100,6 +100,7 @@ module.exports = {
|
|||||||
inputTiff8BitDepth: getPath('8bit_depth.tiff'),
|
inputTiff8BitDepth: getPath('8bit_depth.tiff'),
|
||||||
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
|
||||||
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
|
||||||
|
|
||||||
|
BIN
test/fixtures/rotating-squares.gif
vendored
Normal file
BIN
test/fixtures/rotating-squares.gif
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 41 KiB |
64
test/unit/gif.js
Normal file
64
test/unit/gif.js
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const assert = require('assert');
|
||||||
|
|
||||||
|
const sharp = require('../../');
|
||||||
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
|
describe('GIF input', () => {
|
||||||
|
it('GIF Buffer to JPEG Buffer', () =>
|
||||||
|
sharp(fs.readFileSync(fixtures.inputGif))
|
||||||
|
.resize(8, 4)
|
||||||
|
.jpeg()
|
||||||
|
.toBuffer({ resolveWithObject: true })
|
||||||
|
.then(({ data, info }) => {
|
||||||
|
assert.strictEqual(true, data.length > 0);
|
||||||
|
assert.strictEqual(data.length, info.size);
|
||||||
|
assert.strictEqual('jpeg', info.format);
|
||||||
|
assert.strictEqual(8, info.width);
|
||||||
|
assert.strictEqual(4, info.height);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
it('2 channel GIF file to PNG Buffer', () =>
|
||||||
|
sharp(fixtures.inputGifGreyPlusAlpha)
|
||||||
|
.resize(8, 4)
|
||||||
|
.png()
|
||||||
|
.toBuffer({ resolveWithObject: true })
|
||||||
|
.then(({ data, info }) => {
|
||||||
|
assert.strictEqual(true, data.length > 0);
|
||||||
|
assert.strictEqual(data.length, info.size);
|
||||||
|
assert.strictEqual('png', info.format);
|
||||||
|
assert.strictEqual(8, info.width);
|
||||||
|
assert.strictEqual(4, info.height);
|
||||||
|
assert.strictEqual(4, info.channels);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
it('Animated GIF first page to PNG', () =>
|
||||||
|
sharp(fixtures.inputGifAnimated)
|
||||||
|
.toBuffer({ resolveWithObject: true })
|
||||||
|
.then(({ data, info }) => {
|
||||||
|
assert.strictEqual(true, data.length > 0);
|
||||||
|
assert.strictEqual(data.length, info.size);
|
||||||
|
assert.strictEqual('png', info.format);
|
||||||
|
assert.strictEqual(80, info.width);
|
||||||
|
assert.strictEqual(80, info.height);
|
||||||
|
assert.strictEqual(4, info.channels);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
it('Animated GIF all pages to PNG "toilet roll"', () =>
|
||||||
|
sharp(fixtures.inputGifAnimated, { pages: -1 })
|
||||||
|
.toBuffer({ resolveWithObject: true })
|
||||||
|
.then(({ data, info }) => {
|
||||||
|
assert.strictEqual(true, data.length > 0);
|
||||||
|
assert.strictEqual(data.length, info.size);
|
||||||
|
assert.strictEqual('png', info.format);
|
||||||
|
assert.strictEqual(80, info.width);
|
||||||
|
assert.strictEqual(2400, info.height);
|
||||||
|
assert.strictEqual(4, info.channels);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
@ -517,37 +517,6 @@ describe('Input/output', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Load GIF from Buffer', function (done) {
|
|
||||||
const inputGifBuffer = fs.readFileSync(fixtures.inputGif);
|
|
||||||
sharp(inputGifBuffer)
|
|
||||||
.resize(320, 240)
|
|
||||||
.jpeg()
|
|
||||||
.toBuffer(function (err, data, info) {
|
|
||||||
if (err) throw err;
|
|
||||||
assert.strictEqual(true, data.length > 0);
|
|
||||||
assert.strictEqual(data.length, info.size);
|
|
||||||
assert.strictEqual('jpeg', info.format);
|
|
||||||
assert.strictEqual(320, info.width);
|
|
||||||
assert.strictEqual(240, info.height);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Load GIF grey+alpha from file, auto convert to PNG', function (done) {
|
|
||||||
sharp(fixtures.inputGifGreyPlusAlpha)
|
|
||||||
.resize(8, 4)
|
|
||||||
.toBuffer(function (err, data, info) {
|
|
||||||
if (err) throw err;
|
|
||||||
assert.strictEqual(true, data.length > 0);
|
|
||||||
assert.strictEqual(data.length, info.size);
|
|
||||||
assert.strictEqual('png', info.format);
|
|
||||||
assert.strictEqual(8, info.width);
|
|
||||||
assert.strictEqual(4, info.height);
|
|
||||||
assert.strictEqual(4, info.channels);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Load Vips V file', function (done) {
|
it('Load Vips V file', function (done) {
|
||||||
sharp(fixtures.inputV)
|
sharp(fixtures.inputV)
|
||||||
.jpeg()
|
.jpeg()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user