mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 18:40:16 +02:00
Deprecate limitInputPixels and sequentialRead, move to input options
This commit is contained in:
parent
6fdc79d569
commit
bd52e93fca
@ -11,6 +11,11 @@
|
|||||||
- `options` **[Object][3]?** if present, is an Object with optional attributes.
|
- `options` **[Object][3]?** if present, is an Object with optional attributes.
|
||||||
- `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.limitInputPixels` **([Number][5] \| [Boolean][4])** Do not process input images where the number of pixels
|
||||||
|
(width x height) exceeds this limit. Assumes image dimensions contained in the input metadata can be trusted.
|
||||||
|
An integral Number of pixels, zero or false to remove limit, true to use default limit of 268402689 (0x3FFF x 0x3FFF). (optional, default `268402689`)
|
||||||
|
- `options.sequentialRead` **[Boolean][4]** Set this to `true` to use sequential rather than random access where possible.
|
||||||
|
This can reduce memory usage and might improve performance on some systems. (optional, default `false`)
|
||||||
- `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.pages` **[Number][5]** number of pages to extract for multi-page input (GIF, TIFF, PDF), use -1 for all pages. (optional, default `1`)
|
- `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.page` **[Number][5]** page number to start extracting from for multi-page input (GIF, TIFF, PDF), zero based. (optional, default `0`)
|
||||||
|
@ -88,34 +88,6 @@ image
|
|||||||
|
|
||||||
Returns **[Promise][5]<[Object][6]>**
|
Returns **[Promise][5]<[Object][6]>**
|
||||||
|
|
||||||
## limitInputPixels
|
|
||||||
|
|
||||||
Do not process input images where the number of pixels (width x height) exceeds this limit.
|
|
||||||
Assumes image dimensions contained in the input metadata can be trusted.
|
|
||||||
The default limit is 268402689 (0x3FFF x 0x3FFF) pixels.
|
|
||||||
|
|
||||||
### Parameters
|
|
||||||
|
|
||||||
- `limit` **([Number][7] \| [Boolean][8])** an integral Number of pixels, zero or false to remove limit, true to use default limit.
|
|
||||||
|
|
||||||
|
|
||||||
- Throws **[Error][9]** Invalid limit
|
|
||||||
|
|
||||||
Returns **Sharp**
|
|
||||||
|
|
||||||
## sequentialRead
|
|
||||||
|
|
||||||
An advanced setting that switches the libvips access method to `VIPS_ACCESS_SEQUENTIAL`.
|
|
||||||
This will reduce memory usage and can improve performance on some systems.
|
|
||||||
|
|
||||||
The default behaviour _before_ function call is `false`, meaning the libvips access method is not sequential.
|
|
||||||
|
|
||||||
### Parameters
|
|
||||||
|
|
||||||
- `sequentialRead` **[Boolean][8]** (optional, default `true`)
|
|
||||||
|
|
||||||
Returns **Sharp**
|
|
||||||
|
|
||||||
[1]: https://github.com/libvips/libvips/blob/master/libvips/iofuncs/enumtypes.c#L636
|
[1]: https://github.com/libvips/libvips/blob/master/libvips/iofuncs/enumtypes.c#L636
|
||||||
|
|
||||||
[2]: https://github.com/libvips/libvips/blob/master/libvips/iofuncs/enumtypes.c#L672
|
[2]: https://github.com/libvips/libvips/blob/master/libvips/iofuncs/enumtypes.c#L672
|
||||||
@ -127,9 +99,3 @@ Returns **Sharp**
|
|||||||
[5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise
|
[5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise
|
||||||
|
|
||||||
[6]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
|
[6]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
|
||||||
|
|
||||||
[7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
|
|
||||||
|
|
||||||
[8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
|
|
||||||
|
|
||||||
[9]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error
|
|
||||||
|
@ -12,6 +12,8 @@ Requires libvips v8.9.0.
|
|||||||
* Drop support for undefined input where options also provided.
|
* Drop support for undefined input where options also provided.
|
||||||
[#1768](https://github.com/lovell/sharp/issues/1768)
|
[#1768](https://github.com/lovell/sharp/issues/1768)
|
||||||
|
|
||||||
|
* Move `limitInputPixels` and `sequentialRead` to input options, deprecating functions of the same name.
|
||||||
|
|
||||||
* Expose `delay` and `loop` metadata for animated images.
|
* Expose `delay` and `loop` metadata for animated images.
|
||||||
[#1905](https://github.com/lovell/sharp/issues/1905)
|
[#1905](https://github.com/lovell/sharp/issues/1905)
|
||||||
|
|
||||||
|
@ -86,6 +86,11 @@ const debuglog = util.debuglog('sharp');
|
|||||||
* @param {Object} [options] - if present, is an Object with optional attributes.
|
* @param {Object} [options] - if present, is an Object with optional attributes.
|
||||||
* @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|Boolean} [options.limitInputPixels=268402689] - Do not process input images where the number of pixels
|
||||||
|
* (width x height) exceeds this limit. Assumes image dimensions contained in the input metadata can be trusted.
|
||||||
|
* An integral Number of pixels, zero or false to remove limit, true to use default limit of 268402689 (0x3FFF x 0x3FFF).
|
||||||
|
* @param {Boolean} [options.sequentialRead=false] - Set this to `true` to use sequential rather than random access where possible.
|
||||||
|
* This can reduce memory usage and might improve performance on some systems.
|
||||||
* @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.pages=1] - number of pages to extract for multi-page input (GIF, TIFF, PDF), use -1 for all pages.
|
* @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 {Number} [options.page=0] - page number to start extracting from for multi-page input (GIF, TIFF, PDF), zero based.
|
||||||
@ -110,9 +115,6 @@ const Sharp = function (input, options) {
|
|||||||
}
|
}
|
||||||
stream.Duplex.call(this);
|
stream.Duplex.call(this);
|
||||||
this.options = {
|
this.options = {
|
||||||
// input options
|
|
||||||
sequentialRead: false,
|
|
||||||
limitInputPixels: Math.pow(0x3FFF, 2),
|
|
||||||
// resize options
|
// resize options
|
||||||
topOffsetPre: -1,
|
topOffsetPre: -1,
|
||||||
leftOffsetPre: -1,
|
leftOffsetPre: -1,
|
||||||
|
55
lib/input.js
55
lib/input.js
@ -1,5 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const util = require('util');
|
||||||
const color = require('color');
|
const color = require('color');
|
||||||
const is = require('./is');
|
const is = require('./is');
|
||||||
const sharp = require('../build/Release/sharp.node');
|
const sharp = require('../build/Release/sharp.node');
|
||||||
@ -9,7 +10,11 @@ const sharp = require('../build/Release/sharp.node');
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
function _createInputDescriptor (input, inputOptions, containerOptions) {
|
function _createInputDescriptor (input, inputOptions, containerOptions) {
|
||||||
const inputDescriptor = { failOnError: true };
|
const inputDescriptor = {
|
||||||
|
failOnError: true,
|
||||||
|
limitInputPixels: Math.pow(0x3FFF, 2),
|
||||||
|
sequentialRead: false
|
||||||
|
};
|
||||||
if (is.string(input)) {
|
if (is.string(input)) {
|
||||||
// filesystem
|
// filesystem
|
||||||
inputDescriptor.file = input;
|
inputDescriptor.file = input;
|
||||||
@ -48,6 +53,26 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
|||||||
throw is.invalidParameterError('density', 'number between 1 and 2400', inputOptions.density);
|
throw is.invalidParameterError('density', 'number between 1 and 2400', inputOptions.density);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// limitInputPixels
|
||||||
|
if (is.defined(inputOptions.limitInputPixels)) {
|
||||||
|
if (is.bool(inputOptions.limitInputPixels)) {
|
||||||
|
inputDescriptor.limitInputPixels = inputOptions.limitInputPixels
|
||||||
|
? Math.pow(0x3FFF, 2)
|
||||||
|
: 0;
|
||||||
|
} else if (is.integer(inputOptions.limitInputPixels) && inputOptions.limitInputPixels >= 0) {
|
||||||
|
inputDescriptor.limitInputPixels = inputOptions.limitInputPixels;
|
||||||
|
} else {
|
||||||
|
throw is.invalidParameterError('limitInputPixels', 'integer >= 0', inputOptions.limitInputPixels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// sequentialRead
|
||||||
|
if (is.defined(inputOptions.sequentialRead)) {
|
||||||
|
if (is.bool(inputOptions.sequentialRead)) {
|
||||||
|
inputDescriptor.sequentialRead = inputOptions.sequentialRead;
|
||||||
|
} else {
|
||||||
|
throw is.invalidParameterError('sequentialRead', 'boolean', inputOptions.sequentialRead);
|
||||||
|
}
|
||||||
|
}
|
||||||
// Raw pixel input
|
// Raw pixel input
|
||||||
if (is.defined(inputOptions.raw)) {
|
if (is.defined(inputOptions.raw)) {
|
||||||
if (
|
if (
|
||||||
@ -307,14 +332,9 @@ function stats (callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do not process input images where the number of pixels (width x height) exceeds this limit.
|
* @private
|
||||||
* Assumes image dimensions contained in the input metadata can be trusted.
|
|
||||||
* The default limit is 268402689 (0x3FFF x 0x3FFF) pixels.
|
|
||||||
* @param {(Number|Boolean)} limit - an integral Number of pixels, zero or false to remove limit, true to use default limit.
|
|
||||||
* @returns {Sharp}
|
|
||||||
* @throws {Error} Invalid limit
|
|
||||||
*/
|
*/
|
||||||
function limitInputPixels (limit) {
|
const limitInputPixels = util.deprecate(function limitInputPixels (limit) {
|
||||||
// if we pass in false we represent the integer as 0 to disable
|
// if we pass in false we represent the integer as 0 to disable
|
||||||
if (limit === false) {
|
if (limit === false) {
|
||||||
limit = 0;
|
limit = 0;
|
||||||
@ -322,26 +342,20 @@ function limitInputPixels (limit) {
|
|||||||
limit = Math.pow(0x3FFF, 2);
|
limit = Math.pow(0x3FFF, 2);
|
||||||
}
|
}
|
||||||
if (is.integer(limit) && limit >= 0) {
|
if (is.integer(limit) && limit >= 0) {
|
||||||
this.options.limitInputPixels = limit;
|
this.options.input.limitInputPixels = limit;
|
||||||
} else {
|
} else {
|
||||||
throw is.invalidParameterError('limitInputPixels', 'integer', limit);
|
throw is.invalidParameterError('limitInputPixels', 'integer', limit);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}, 'limitInputPixels is deprecated, use sharp(input, { limitInputPixels: false }) instead');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An advanced setting that switches the libvips access method to `VIPS_ACCESS_SEQUENTIAL`.
|
* @private
|
||||||
* This will reduce memory usage and can improve performance on some systems.
|
|
||||||
*
|
|
||||||
* The default behaviour *before* function call is `false`, meaning the libvips access method is not sequential.
|
|
||||||
*
|
|
||||||
* @param {Boolean} [sequentialRead=true]
|
|
||||||
* @returns {Sharp}
|
|
||||||
*/
|
*/
|
||||||
function sequentialRead (sequentialRead) {
|
const sequentialRead = util.deprecate(function sequentialRead (sequentialRead) {
|
||||||
this.options.sequentialRead = is.bool(sequentialRead) ? sequentialRead : true;
|
this.options.input.sequentialRead = is.bool(sequentialRead) ? sequentialRead : true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}, 'sequentialRead is deprecated, use sharp(input, { sequentialRead: true }) instead');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decorate the Sharp prototype with input-related functions.
|
* Decorate the Sharp prototype with input-related functions.
|
||||||
@ -357,6 +371,7 @@ module.exports = function (Sharp) {
|
|||||||
// Public
|
// Public
|
||||||
metadata,
|
metadata,
|
||||||
stats,
|
stats,
|
||||||
|
// Deprecated
|
||||||
limitInputPixels,
|
limitInputPixels,
|
||||||
sequentialRead
|
sequentialRead
|
||||||
});
|
});
|
||||||
|
@ -86,6 +86,10 @@ namespace sharp {
|
|||||||
descriptor->createHeight = AttrTo<uint32_t>(input, "createHeight");
|
descriptor->createHeight = AttrTo<uint32_t>(input, "createHeight");
|
||||||
descriptor->createBackground = AttrAsRgba(input, "createBackground");
|
descriptor->createBackground = AttrAsRgba(input, "createBackground");
|
||||||
}
|
}
|
||||||
|
// Limit input images to a given number of pixels, where pixels = width * height
|
||||||
|
descriptor->limitInputPixels = AttrTo<uint32_t>(input, "limitInputPixels");
|
||||||
|
// Allow switch from random to sequential access
|
||||||
|
descriptor->access = AttrTo<bool>(input, "sequentialRead") ? VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
|
||||||
return descriptor;
|
return descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,7 +248,7 @@ namespace sharp {
|
|||||||
/*
|
/*
|
||||||
Open an image from the given InputDescriptor (filesystem, compressed buffer, raw pixel data)
|
Open an image from the given InputDescriptor (filesystem, compressed buffer, raw pixel data)
|
||||||
*/
|
*/
|
||||||
std::tuple<VImage, ImageType> OpenInput(InputDescriptor *descriptor, VipsAccess accessMethod) {
|
std::tuple<VImage, ImageType> OpenInput(InputDescriptor *descriptor) {
|
||||||
VImage image;
|
VImage image;
|
||||||
ImageType imageType;
|
ImageType imageType;
|
||||||
if (descriptor->isBuffer) {
|
if (descriptor->isBuffer) {
|
||||||
@ -264,7 +268,7 @@ namespace sharp {
|
|||||||
if (imageType != ImageType::UNKNOWN) {
|
if (imageType != ImageType::UNKNOWN) {
|
||||||
try {
|
try {
|
||||||
vips::VOption *option = VImage::option()
|
vips::VOption *option = VImage::option()
|
||||||
->set("access", accessMethod)
|
->set("access", descriptor->access)
|
||||||
->set("fail", descriptor->failOnError);
|
->set("fail", descriptor->failOnError);
|
||||||
if (imageType == ImageType::SVG || imageType == ImageType::PDF) {
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF) {
|
||||||
option->set("dpi", descriptor->density);
|
option->set("dpi", descriptor->density);
|
||||||
@ -310,7 +314,7 @@ namespace sharp {
|
|||||||
if (imageType != ImageType::UNKNOWN) {
|
if (imageType != ImageType::UNKNOWN) {
|
||||||
try {
|
try {
|
||||||
vips::VOption *option = VImage::option()
|
vips::VOption *option = VImage::option()
|
||||||
->set("access", accessMethod)
|
->set("access", descriptor->access)
|
||||||
->set("fail", descriptor->failOnError);
|
->set("fail", descriptor->failOnError);
|
||||||
if (imageType == ImageType::SVG || imageType == ImageType::PDF) {
|
if (imageType == ImageType::SVG || imageType == ImageType::PDF) {
|
||||||
option->set("dpi", descriptor->density);
|
option->set("dpi", descriptor->density);
|
||||||
@ -334,6 +338,11 @@ namespace sharp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Limit input images to a given number of pixels, where pixels = width * height
|
||||||
|
if (descriptor->limitInputPixels > 0 &&
|
||||||
|
static_cast<uint64_t>(image.width() * image.height()) > static_cast<uint64_t>(descriptor->limitInputPixels)) {
|
||||||
|
throw vips::VError("Input image exceeds pixel limit");
|
||||||
|
}
|
||||||
return std::make_tuple(image, imageType);
|
return std::make_tuple(image, imageType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +48,8 @@ namespace sharp {
|
|||||||
std::string file;
|
std::string file;
|
||||||
char *buffer;
|
char *buffer;
|
||||||
bool failOnError;
|
bool failOnError;
|
||||||
|
int limitInputPixels;
|
||||||
|
VipsAccess access;
|
||||||
size_t bufferLength;
|
size_t bufferLength;
|
||||||
bool isBuffer;
|
bool isBuffer;
|
||||||
double density;
|
double density;
|
||||||
@ -64,6 +66,8 @@ namespace sharp {
|
|||||||
InputDescriptor():
|
InputDescriptor():
|
||||||
buffer(nullptr),
|
buffer(nullptr),
|
||||||
failOnError(TRUE),
|
failOnError(TRUE),
|
||||||
|
limitInputPixels(0x3FFF * 0x3FFF),
|
||||||
|
access(VIPS_ACCESS_RANDOM),
|
||||||
bufferLength(0),
|
bufferLength(0),
|
||||||
isBuffer(FALSE),
|
isBuffer(FALSE),
|
||||||
density(72.0),
|
density(72.0),
|
||||||
@ -156,7 +160,7 @@ namespace sharp {
|
|||||||
/*
|
/*
|
||||||
Open an image from the given InputDescriptor (filesystem, compressed buffer, raw pixel data)
|
Open an image from the given InputDescriptor (filesystem, compressed buffer, raw pixel data)
|
||||||
*/
|
*/
|
||||||
std::tuple<VImage, ImageType> OpenInput(InputDescriptor *descriptor, VipsAccess accessMethod);
|
std::tuple<VImage, ImageType> OpenInput(InputDescriptor *descriptor);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Does this image have an embedded profile?
|
Does this image have an embedded profile?
|
||||||
|
@ -46,7 +46,7 @@ class MetadataWorker : public Nan::AsyncWorker {
|
|||||||
vips::VImage image;
|
vips::VImage image;
|
||||||
sharp::ImageType imageType = sharp::ImageType::UNKNOWN;
|
sharp::ImageType imageType = sharp::ImageType::UNKNOWN;
|
||||||
try {
|
try {
|
||||||
std::tie(image, imageType) = OpenInput(baton->input, VIPS_ACCESS_SEQUENTIAL);
|
std::tie(image, imageType) = OpenInput(baton->input);
|
||||||
} catch (vips::VError const &err) {
|
} catch (vips::VError const &err) {
|
||||||
(baton->err).append(err.what());
|
(baton->err).append(err.what());
|
||||||
}
|
}
|
||||||
|
@ -77,15 +77,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|||||||
// Open input
|
// Open input
|
||||||
vips::VImage image;
|
vips::VImage image;
|
||||||
ImageType inputImageType;
|
ImageType inputImageType;
|
||||||
std::tie(image, inputImageType) = sharp::OpenInput(baton->input, baton->accessMethod);
|
std::tie(image, inputImageType) = sharp::OpenInput(baton->input);
|
||||||
|
|
||||||
// Limit input images to a given number of pixels, where pixels = width * height
|
|
||||||
// Ignore if 0
|
|
||||||
if (baton->limitInputPixels > 0 &&
|
|
||||||
static_cast<uint64_t>(image.width() * image.height()) > static_cast<uint64_t>(baton->limitInputPixels)) {
|
|
||||||
(baton->err).append("Input image exceeds pixel limit");
|
|
||||||
return Error();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate angle of rotation
|
// Calculate angle of rotation
|
||||||
VipsAngle rotation;
|
VipsAngle rotation;
|
||||||
@ -270,7 +262,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|||||||
if (shrink_on_load > 1) {
|
if (shrink_on_load > 1) {
|
||||||
// Reload input using shrink-on-load
|
// Reload input using shrink-on-load
|
||||||
vips::VOption *option = VImage::option()
|
vips::VOption *option = VImage::option()
|
||||||
->set("access", baton->accessMethod)
|
->set("access", baton->input->access)
|
||||||
->set("shrink", shrink_on_load)
|
->set("shrink", shrink_on_load)
|
||||||
->set("fail", baton->input->failOnError);
|
->set("fail", baton->input->failOnError);
|
||||||
if (baton->input->buffer != nullptr) {
|
if (baton->input->buffer != nullptr) {
|
||||||
@ -426,7 +418,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|||||||
ImageType joinImageType = ImageType::UNKNOWN;
|
ImageType joinImageType = ImageType::UNKNOWN;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < baton->joinChannelIn.size(); i++) {
|
for (unsigned int i = 0; i < baton->joinChannelIn.size(); i++) {
|
||||||
std::tie(joinImage, joinImageType) = sharp::OpenInput(baton->joinChannelIn[i], baton->accessMethod);
|
std::tie(joinImage, joinImageType) = sharp::OpenInput(baton->joinChannelIn[i]);
|
||||||
image = image.bandjoin(joinImage);
|
image = image.bandjoin(joinImage);
|
||||||
}
|
}
|
||||||
image = image.copy(VImage::option()->set("interpretation", baton->colourspace));
|
image = image.copy(VImage::option()->set("interpretation", baton->colourspace));
|
||||||
@ -479,7 +471,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|||||||
baton->height = image.height();
|
baton->height = image.height();
|
||||||
}
|
}
|
||||||
image = image.tilecache(VImage::option()
|
image = image.tilecache(VImage::option()
|
||||||
->set("access", baton->accessMethod)
|
->set("access", VIPS_ACCESS_RANDOM)
|
||||||
->set("threaded", TRUE));
|
->set("threaded", TRUE));
|
||||||
image = image.smartcrop(baton->width, baton->height, VImage::option()
|
image = image.smartcrop(baton->width, baton->height, VImage::option()
|
||||||
->set("interesting", baton->position == 16 ? VIPS_INTERESTING_ENTROPY : VIPS_INTERESTING_ATTENTION));
|
->set("interesting", baton->position == 16 ? VIPS_INTERESTING_ENTROPY : VIPS_INTERESTING_ATTENTION));
|
||||||
@ -556,7 +548,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|||||||
for (Composite *composite : baton->composite) {
|
for (Composite *composite : baton->composite) {
|
||||||
VImage compositeImage;
|
VImage compositeImage;
|
||||||
ImageType compositeImageType = ImageType::UNKNOWN;
|
ImageType compositeImageType = ImageType::UNKNOWN;
|
||||||
std::tie(compositeImage, compositeImageType) = OpenInput(composite->input, baton->accessMethod);
|
std::tie(compositeImage, compositeImageType) = OpenInput(composite->input);
|
||||||
// Verify within current dimensions
|
// Verify within current dimensions
|
||||||
if (compositeImage.width() > image.width() || compositeImage.height() > image.height()) {
|
if (compositeImage.width() > image.width() || compositeImage.height() > image.height()) {
|
||||||
throw vips::VError("Image to composite must have same dimensions or smaller");
|
throw vips::VError("Image to composite must have same dimensions or smaller");
|
||||||
@ -646,7 +638,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|||||||
if (baton->boolean != nullptr) {
|
if (baton->boolean != nullptr) {
|
||||||
VImage booleanImage;
|
VImage booleanImage;
|
||||||
ImageType booleanImageType = ImageType::UNKNOWN;
|
ImageType booleanImageType = ImageType::UNKNOWN;
|
||||||
std::tie(booleanImage, booleanImageType) = sharp::OpenInput(baton->boolean, baton->accessMethod);
|
std::tie(booleanImage, booleanImageType) = sharp::OpenInput(baton->boolean);
|
||||||
image = sharp::Boolean(image, booleanImage, baton->booleanOp);
|
image = sharp::Boolean(image, booleanImage, baton->booleanOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1193,10 +1185,6 @@ NAN_METHOD(pipeline) {
|
|||||||
|
|
||||||
// Input
|
// Input
|
||||||
baton->input = CreateInputDescriptor(AttrAs<v8::Object>(options, "input"), buffersToPersist);
|
baton->input = CreateInputDescriptor(AttrAs<v8::Object>(options, "input"), buffersToPersist);
|
||||||
baton->accessMethod = AttrTo<bool>(options, "sequentialRead") ?
|
|
||||||
VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
|
|
||||||
// Limit input images to a given number of pixels, where pixels = width * height
|
|
||||||
baton->limitInputPixels = AttrTo<int32_t>(options, "limitInputPixels");
|
|
||||||
// Extract image options
|
// Extract image options
|
||||||
baton->topOffsetPre = AttrTo<int32_t>(options, "topOffsetPre");
|
baton->topOffsetPre = AttrTo<int32_t>(options, "topOffsetPre");
|
||||||
baton->leftOffsetPre = AttrTo<int32_t>(options, "leftOffsetPre");
|
baton->leftOffsetPre = AttrTo<int32_t>(options, "leftOffsetPre");
|
||||||
@ -1408,11 +1396,12 @@ NAN_METHOD(pipeline) {
|
|||||||
// signal that we do not want to pass any value to dzSave
|
// signal that we do not want to pass any value to dzSave
|
||||||
baton->tileDepth = VIPS_FOREIGN_DZ_DEPTH_LAST;
|
baton->tileDepth = VIPS_FOREIGN_DZ_DEPTH_LAST;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force random access for certain operations
|
// Force random access for certain operations
|
||||||
if (baton->accessMethod == VIPS_ACCESS_SEQUENTIAL && (
|
if (baton->input->access == VIPS_ACCESS_SEQUENTIAL) {
|
||||||
baton->trimThreshold > 0.0 || baton->normalise ||
|
if (baton->trimThreshold > 0.0 || baton->normalise || baton->position == 16 || baton->position == 17) {
|
||||||
baton->position == 16 || baton->position == 17)) {
|
baton->input->access = VIPS_ACCESS_RANDOM;
|
||||||
baton->accessMethod = VIPS_ACCESS_RANDOM;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to notify of libvips warnings
|
// Function to notify of libvips warnings
|
||||||
|
@ -55,7 +55,6 @@ struct Composite {
|
|||||||
|
|
||||||
struct PipelineBaton {
|
struct PipelineBaton {
|
||||||
sharp::InputDescriptor *input;
|
sharp::InputDescriptor *input;
|
||||||
int limitInputPixels;
|
|
||||||
std::string formatOut;
|
std::string formatOut;
|
||||||
std::string fileOut;
|
std::string fileOut;
|
||||||
void *bufferOut;
|
void *bufferOut;
|
||||||
@ -119,7 +118,6 @@ struct PipelineBaton {
|
|||||||
int extendRight;
|
int extendRight;
|
||||||
std::vector<double> extendBackground;
|
std::vector<double> extendBackground;
|
||||||
bool withoutEnlargement;
|
bool withoutEnlargement;
|
||||||
VipsAccess accessMethod;
|
|
||||||
int jpegQuality;
|
int jpegQuality;
|
||||||
bool jpegProgressive;
|
bool jpegProgressive;
|
||||||
std::string jpegChromaSubsampling;
|
std::string jpegChromaSubsampling;
|
||||||
@ -182,7 +180,6 @@ struct PipelineBaton {
|
|||||||
|
|
||||||
PipelineBaton():
|
PipelineBaton():
|
||||||
input(nullptr),
|
input(nullptr),
|
||||||
limitInputPixels(0),
|
|
||||||
bufferOutLength(0),
|
bufferOutLength(0),
|
||||||
topOffsetPre(-1),
|
topOffsetPre(-1),
|
||||||
topOffsetPost(-1),
|
topOffsetPost(-1),
|
||||||
|
@ -62,7 +62,7 @@ class StatsWorker : public Nan::AsyncWorker {
|
|||||||
sharp::ImageType imageType = sharp::ImageType::UNKNOWN;
|
sharp::ImageType imageType = sharp::ImageType::UNKNOWN;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
std::tie(image, imageType) = OpenInput(baton->input, baton->accessMethod);
|
std::tie(image, imageType) = OpenInput(baton->input);
|
||||||
} catch (vips::VError const &err) {
|
} catch (vips::VError const &err) {
|
||||||
(baton->err).append(err.what());
|
(baton->err).append(err.what());
|
||||||
}
|
}
|
||||||
@ -178,7 +178,6 @@ NAN_METHOD(stats) {
|
|||||||
|
|
||||||
// Input
|
// Input
|
||||||
baton->input = sharp::CreateInputDescriptor(sharp::AttrAs<v8::Object>(options, "input"), buffersToPersist);
|
baton->input = sharp::CreateInputDescriptor(sharp::AttrAs<v8::Object>(options, "input"), buffersToPersist);
|
||||||
baton->accessMethod = AttrTo<bool>(options, "sequentialRead") ? VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
|
|
||||||
|
|
||||||
// Function to notify of libvips warnings
|
// Function to notify of libvips warnings
|
||||||
Nan::Callback *debuglog = new Nan::Callback(sharp::AttrAs<v8::Function>(options, "debuglog"));
|
Nan::Callback *debuglog = new Nan::Callback(sharp::AttrAs<v8::Function>(options, "debuglog"));
|
||||||
|
@ -46,7 +46,6 @@ struct ChannelStats {
|
|||||||
struct StatsBaton {
|
struct StatsBaton {
|
||||||
// Input
|
// Input
|
||||||
sharp::InputDescriptor *input;
|
sharp::InputDescriptor *input;
|
||||||
VipsAccess accessMethod;
|
|
||||||
|
|
||||||
// Output
|
// Output
|
||||||
std::vector<ChannelStats> channelStats;
|
std::vector<ChannelStats> channelStats;
|
||||||
|
@ -460,8 +460,7 @@ async.series({
|
|||||||
}).add('sharp-sequentialRead', {
|
}).add('sharp-sequentialRead', {
|
||||||
defer: true,
|
defer: true,
|
||||||
fn: function (deferred) {
|
fn: function (deferred) {
|
||||||
sharp(inputJpgBuffer)
|
sharp(inputJpgBuffer, { sequentialRead: true })
|
||||||
.sequentialRead()
|
|
||||||
.resize(width, height)
|
.resize(width, height)
|
||||||
.toBuffer(function (err, buffer) {
|
.toBuffer(function (err, buffer) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
100
test/unit/io.js
100
test/unit/io.js
@ -214,7 +214,27 @@ describe('Input/output', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Sequential read, force JPEG', function (done) {
|
it('Invalid sequential read option throws', () => {
|
||||||
|
assert.throws(() => {
|
||||||
|
sharp({ sequentialRead: 'fail' });
|
||||||
|
}, /Expected boolean for sequentialRead but received fail of type string/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Sequential read, force JPEG', () =>
|
||||||
|
sharp(fixtures.inputJpg, { sequentialRead: true })
|
||||||
|
.resize(320, 240)
|
||||||
|
.toFormat(sharp.format.jpeg)
|
||||||
|
.toBuffer({ resolveWithObject: true })
|
||||||
|
.then(({ data, info }) => {
|
||||||
|
assert.strictEqual(data.length > 0, true);
|
||||||
|
assert.strictEqual(data.length, info.size);
|
||||||
|
assert.strictEqual(info.format, 'jpeg');
|
||||||
|
assert.strictEqual(info.width, 320);
|
||||||
|
assert.strictEqual(info.height, 240);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
it('Sequential read, force JPEG - deprecated', function (done) {
|
||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.sequentialRead()
|
.sequentialRead()
|
||||||
.resize(320, 240)
|
.resize(320, 240)
|
||||||
@ -230,7 +250,21 @@ describe('Input/output', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Not sequential read, force JPEG', function (done) {
|
it('Not sequential read, force JPEG', () =>
|
||||||
|
sharp(fixtures.inputJpg, { sequentialRead: false })
|
||||||
|
.resize(320, 240)
|
||||||
|
.toFormat('jpeg')
|
||||||
|
.toBuffer({ resolveWithObject: true })
|
||||||
|
.then(({ data, info }) => {
|
||||||
|
assert.strictEqual(data.length > 0, true);
|
||||||
|
assert.strictEqual(data.length, info.size);
|
||||||
|
assert.strictEqual(info.format, 'jpeg');
|
||||||
|
assert.strictEqual(info.width, 320);
|
||||||
|
assert.strictEqual(info.height, 240);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
it('Not sequential read, force JPEG - deprecated', function (done) {
|
||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.sequentialRead(false)
|
.sequentialRead(false)
|
||||||
.resize(320, 240)
|
.resize(320, 240)
|
||||||
@ -559,7 +593,67 @@ describe('Input/output', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Limit pixel count of input image', function () {
|
describe('Limit pixel count of input image', () => {
|
||||||
|
it('Invalid fails - negative', () => {
|
||||||
|
assert.throws(() => {
|
||||||
|
sharp({ limitInputPixels: -1 });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Invalid fails - float', () => {
|
||||||
|
assert.throws(() => {
|
||||||
|
sharp({ limitInputPixels: 12.3 });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Invalid fails - string', () => {
|
||||||
|
assert.throws(() => {
|
||||||
|
sharp({ limitInputPixels: 'fail' });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Same size as input works', () =>
|
||||||
|
sharp(fixtures.inputJpg)
|
||||||
|
.metadata()
|
||||||
|
.then(({ width, height }) =>
|
||||||
|
sharp(fixtures.inputJpg, { limitInputPixels: width * height }).toBuffer()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
it('Disabling limit works', () =>
|
||||||
|
sharp(fixtures.inputJpgLarge, { limitInputPixels: false })
|
||||||
|
.resize(2)
|
||||||
|
.toBuffer()
|
||||||
|
);
|
||||||
|
|
||||||
|
it('Enabling default limit works and fails with a large image', () =>
|
||||||
|
sharp(fixtures.inputJpgLarge, { limitInputPixels: true })
|
||||||
|
.toBuffer()
|
||||||
|
.then(() => {
|
||||||
|
assert.fail('Expected to fail');
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
assert.strictEqual(err.message, 'Input image exceeds pixel limit');
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
it('Smaller than input fails', () =>
|
||||||
|
sharp(fixtures.inputJpg)
|
||||||
|
.metadata()
|
||||||
|
.then(({ width, height }) =>
|
||||||
|
sharp(fixtures.inputJpg, { limitInputPixels: width * height - 1 })
|
||||||
|
.toBuffer()
|
||||||
|
.then(() => {
|
||||||
|
assert.fail('Expected to fail');
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
assert.strictEqual(err.message, 'Input image exceeds pixel limit');
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Limit pixel count of input image - deprecated', function () {
|
||||||
it('Invalid fails - negative', function (done) {
|
it('Invalid fails - negative', function (done) {
|
||||||
let isValid = false;
|
let isValid = false;
|
||||||
try {
|
try {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user