mirror of
https://github.com/lovell/sharp.git
synced 2026-02-07 07:06:16 +01:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1ff84b20b7 | ||
|
|
97655d2dfd | ||
|
|
d10d7b02d4 | ||
|
|
2ffdae2914 | ||
|
|
342de36973 | ||
|
|
b33231d4bd | ||
|
|
319db21f29 | ||
|
|
d359331426 | ||
|
|
7ae151362b | ||
|
|
648a1e05da | ||
|
|
b9f211fe34 | ||
|
|
e475d9e47f | ||
|
|
f37ca8249a | ||
|
|
1dd4be670d | ||
|
|
197d4cf835 | ||
|
|
83eed86b53 | ||
|
|
bbf612cb9e | ||
|
|
2679bb567b | ||
|
|
481e350f39 |
@@ -379,6 +379,8 @@ Returns **Sharp**
|
|||||||
|
|
||||||
Use these TIFF options for output image.
|
Use these TIFF options for output image.
|
||||||
|
|
||||||
|
The `density` can be set in pixels/inch via [withMetadata][1] instead of providing `xres` and `yres` in pixels/mm.
|
||||||
|
|
||||||
### Parameters
|
### Parameters
|
||||||
|
|
||||||
* `options` **[Object][6]?** output options
|
* `options` **[Object][6]?** output options
|
||||||
@@ -542,6 +544,26 @@ sharp('input.tiff')
|
|||||||
|
|
||||||
Returns **Sharp**
|
Returns **Sharp**
|
||||||
|
|
||||||
|
## timeout
|
||||||
|
|
||||||
|
Set a timeout for processing, in seconds.
|
||||||
|
Use a value of zero to continue processing indefinitely, the default behaviour.
|
||||||
|
|
||||||
|
The clock starts when libvips opens an input image for processing.
|
||||||
|
Time spent waiting for a libuv thread to become available is not included.
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
* `options` **[Object][6]**
|
||||||
|
|
||||||
|
* `options.seconds` **[number][9]** Number of seconds after which processing will be stopped
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
**Meta**
|
||||||
|
|
||||||
|
* **since**: 0.29.2
|
||||||
|
|
||||||
[1]: #withmetadata
|
[1]: #withmetadata
|
||||||
|
|
||||||
[2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
|
[2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
|
||||||
|
|||||||
@@ -4,6 +4,35 @@
|
|||||||
|
|
||||||
Requires libvips v8.11.3
|
Requires libvips v8.11.3
|
||||||
|
|
||||||
|
### v0.29.3 - 14th November 2021
|
||||||
|
|
||||||
|
* Ensure correct dimensions when containing image resized to 1px.
|
||||||
|
[#2951](https://github.com/lovell/sharp/issues/2951)
|
||||||
|
|
||||||
|
* Impute TIFF `xres`/`yres` from `density` provided to `withMetadata`.
|
||||||
|
[#2952](https://github.com/lovell/sharp/pull/2952)
|
||||||
|
[@mbklein](https://github.com/mbklein)
|
||||||
|
|
||||||
|
### v0.29.2 - 21st October 2021
|
||||||
|
|
||||||
|
* Add `timeout` function to limit processing time.
|
||||||
|
|
||||||
|
* Ensure `sharp.versions` is populated from vendored libvips.
|
||||||
|
|
||||||
|
* Remove animation properties from single page images.
|
||||||
|
[#2890](https://github.com/lovell/sharp/issues/2890)
|
||||||
|
|
||||||
|
* Allow use of 'tif' to select TIFF output.
|
||||||
|
[#2893](https://github.com/lovell/sharp/pull/2893)
|
||||||
|
[@erf](https://github.com/erf)
|
||||||
|
|
||||||
|
* Improve error message on Windows for version conflict.
|
||||||
|
[#2918](https://github.com/lovell/sharp/pull/2918)
|
||||||
|
[@dkrnl](https://github.com/dkrnl)
|
||||||
|
|
||||||
|
* Throw error rather than exit when invalid binaries detected.
|
||||||
|
[#2931](https://github.com/lovell/sharp/issues/2931)
|
||||||
|
|
||||||
### v0.29.1 - 7th September 2021
|
### v0.29.1 - 7th September 2021
|
||||||
|
|
||||||
* Add `lightness` option to `modulate` operation.
|
* Add `lightness` option to `modulate` operation.
|
||||||
|
|||||||
@@ -223,4 +223,7 @@ Name: Tenpi
|
|||||||
GitHub: https://github.com/Tenpi
|
GitHub: https://github.com/Tenpi
|
||||||
|
|
||||||
Name: Zaruike
|
Name: Zaruike
|
||||||
https://github.com/Zaruike
|
GitHub: https://github.com/Zaruike
|
||||||
|
|
||||||
|
Name: Erlend F
|
||||||
|
GitHub: https://github.com/erf
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ JPEG, PNG, WebP, AVIF, TIFF, GIF (input) and SVG (input) image formats.
|
|||||||
|
|
||||||
The following platforms have prebuilt libvips but not sharp:
|
The following platforms have prebuilt libvips but not sharp:
|
||||||
|
|
||||||
* Linux ARMv6
|
|
||||||
* Linux ARMv7 (glibc >= 2.28)
|
* Linux ARMv7 (glibc >= 2.28)
|
||||||
|
* Linux ARMv6 (glibc >= 2.28)
|
||||||
* Windows ARM64
|
* Windows ARM64
|
||||||
|
|
||||||
The following platforms require compilation of both libvips and sharp from source:
|
The following platforms require compilation of both libvips and sharp from source:
|
||||||
@@ -40,6 +40,8 @@ The following platforms require compilation of both libvips and sharp from sourc
|
|||||||
* Linux x86
|
* Linux x86
|
||||||
* Linux x64 (glibc <= 2.16, includes RHEL/CentOS 6)
|
* Linux x64 (glibc <= 2.16, includes RHEL/CentOS 6)
|
||||||
* Linux ARM64 (glibc <= 2.28)
|
* Linux ARM64 (glibc <= 2.28)
|
||||||
|
* Linux ARMv7 (glibc <= 2.27, musl)
|
||||||
|
* Linux ARMv6 (glibc <= 2.27, musl)
|
||||||
* Linux PowerPC
|
* Linux PowerPC
|
||||||
* FreeBSD
|
* FreeBSD
|
||||||
* OpenBSD
|
* OpenBSD
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -273,6 +273,7 @@ const Sharp = function (input, options) {
|
|||||||
tileBackground: [255, 255, 255, 255],
|
tileBackground: [255, 255, 255, 255],
|
||||||
tileCentre: false,
|
tileCentre: false,
|
||||||
tileId: 'https://example.com/iiif',
|
tileId: 'https://example.com/iiif',
|
||||||
|
timeoutSeconds: 0,
|
||||||
linearA: 1,
|
linearA: 1,
|
||||||
linearB: 0,
|
linearB: 0,
|
||||||
// Function to notify of libvips warnings
|
// Function to notify of libvips warnings
|
||||||
@@ -288,7 +289,8 @@ const Sharp = function (input, options) {
|
|||||||
this.options.input = this._createInputDescriptor(input, options, { allowStream: true });
|
this.options.input = this._createInputDescriptor(input, options, { allowStream: true });
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
util.inherits(Sharp, stream.Duplex);
|
Object.setPrototypeOf(Sharp.prototype, stream.Duplex.prototype);
|
||||||
|
Object.setPrototypeOf(Sharp, stream.Duplex);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Take a "snapshot" of the Sharp instance, returning a new instance.
|
* Take a "snapshot" of the Sharp instance, returning a new instance.
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ const formats = new Map([
|
|||||||
['png', 'png'],
|
['png', 'png'],
|
||||||
['raw', 'raw'],
|
['raw', 'raw'],
|
||||||
['tiff', 'tiff'],
|
['tiff', 'tiff'],
|
||||||
|
['tif', 'tiff'],
|
||||||
['webp', 'webp'],
|
['webp', 'webp'],
|
||||||
['gif', 'gif'],
|
['gif', 'gif'],
|
||||||
['jp2', 'jp2'],
|
['jp2', 'jp2'],
|
||||||
@@ -636,6 +637,8 @@ function trySetAnimationOptions (source, target) {
|
|||||||
/**
|
/**
|
||||||
* Use these TIFF options for output image.
|
* Use these TIFF options for output image.
|
||||||
*
|
*
|
||||||
|
* The `density` can be set in pixels/inch via {@link withMetadata} instead of providing `xres` and `yres` in pixels/mm.
|
||||||
|
*
|
||||||
* @example
|
* @example
|
||||||
* // Convert SVG input to LZW-compressed, 1 bit per pixel TIFF output
|
* // Convert SVG input to LZW-compressed, 1 bit per pixel TIFF output
|
||||||
* sharp('input.svg')
|
* sharp('input.svg')
|
||||||
@@ -974,6 +977,31 @@ function tile (options) {
|
|||||||
return this._updateFormatOut('dz');
|
return this._updateFormatOut('dz');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a timeout for processing, in seconds.
|
||||||
|
* Use a value of zero to continue processing indefinitely, the default behaviour.
|
||||||
|
*
|
||||||
|
* The clock starts when libvips opens an input image for processing.
|
||||||
|
* Time spent waiting for a libuv thread to become available is not included.
|
||||||
|
*
|
||||||
|
* @since 0.29.2
|
||||||
|
*
|
||||||
|
* @param {Object} options
|
||||||
|
* @param {number} options.seconds - Number of seconds after which processing will be stopped
|
||||||
|
* @returns {Sharp}
|
||||||
|
*/
|
||||||
|
function timeout (options) {
|
||||||
|
if (!is.plainObject(options)) {
|
||||||
|
throw is.invalidParameterError('options', 'object', options);
|
||||||
|
}
|
||||||
|
if (is.integer(options.seconds) && is.inRange(options.seconds, 0, 3600)) {
|
||||||
|
this.options.timeoutSeconds = options.seconds;
|
||||||
|
} else {
|
||||||
|
throw is.invalidParameterError('seconds', 'integer between 0 and 3600', options.seconds);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the output format unless options.force is false,
|
* Update the output format unless options.force is false,
|
||||||
* in which case revert to input format.
|
* in which case revert to input format.
|
||||||
@@ -1128,6 +1156,7 @@ module.exports = function (Sharp) {
|
|||||||
gif,
|
gif,
|
||||||
raw,
|
raw,
|
||||||
tile,
|
tile,
|
||||||
|
timeout,
|
||||||
// Private
|
// Private
|
||||||
_updateFormatOut,
|
_updateFormatOut,
|
||||||
_setBooleanOption,
|
_setBooleanOption,
|
||||||
|
|||||||
11
lib/sharp.js
11
lib/sharp.js
@@ -19,6 +19,13 @@ try {
|
|||||||
help.push(
|
help.push(
|
||||||
'- Consult the installation documentation: https://sharp.pixelplumbing.com/install'
|
'- Consult the installation documentation: https://sharp.pixelplumbing.com/install'
|
||||||
);
|
);
|
||||||
console.error(help.join('\n'));
|
// Check loaded
|
||||||
process.exit(1);
|
if (process.platform === 'win32') {
|
||||||
|
const loadedModule = Object.keys(require.cache).find((i) => /[\\/]build[\\/]Release[\\/]sharp(.*)\.node$/.test(i));
|
||||||
|
if (loadedModule) {
|
||||||
|
const [, loadedPackage] = loadedModule.match(/node_modules[\\/]([^\\/]+)[\\/]/);
|
||||||
|
help.push(`- Ensure the version of sharp aligns with the ${loadedPackage} package: "npm ls sharp"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error(help.join('\n'));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ const events = require('events');
|
|||||||
const detectLibc = require('detect-libc');
|
const detectLibc = require('detect-libc');
|
||||||
|
|
||||||
const is = require('./is');
|
const is = require('./is');
|
||||||
|
const platformAndArch = require('./platform')();
|
||||||
const sharp = require('./sharp');
|
const sharp = require('./sharp');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,7 +46,7 @@ let versions = {
|
|||||||
vips: sharp.libvipsVersion()
|
vips: sharp.libvipsVersion()
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
versions = require(`../vendor/${versions.vips}/versions.json`);
|
versions = require(`../vendor/${versions.vips}/${platformAndArch}/versions.json`);
|
||||||
} catch (err) {}
|
} catch (err) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
16
package.json
16
package.json
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "sharp",
|
"name": "sharp",
|
||||||
"description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, AVIF and TIFF images",
|
"description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, AVIF and TIFF images",
|
||||||
"version": "0.29.1",
|
"version": "0.29.3",
|
||||||
"author": "Lovell Fuller <npm@lovell.info>",
|
"author": "Lovell Fuller <npm@lovell.info>",
|
||||||
"homepage": "https://github.com/lovell/sharp",
|
"homepage": "https://github.com/lovell/sharp",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
@@ -126,25 +126,25 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"color": "^4.0.1",
|
"color": "^4.0.1",
|
||||||
"detect-libc": "^1.0.3",
|
"detect-libc": "^1.0.3",
|
||||||
"node-addon-api": "^4.1.0",
|
"node-addon-api": "^4.2.0",
|
||||||
"prebuild-install": "^6.1.4",
|
"prebuild-install": "^7.0.0",
|
||||||
"semver": "^7.3.5",
|
"semver": "^7.3.5",
|
||||||
"simple-get": "^3.1.0",
|
"simple-get": "^4.0.0",
|
||||||
"tar-fs": "^2.1.1",
|
"tar-fs": "^2.1.1",
|
||||||
"tunnel-agent": "^0.6.0"
|
"tunnel-agent": "^0.6.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"async": "^3.2.1",
|
"async": "^3.2.2",
|
||||||
"cc": "^3.0.1",
|
"cc": "^3.0.1",
|
||||||
"decompress-zip": "^0.3.3",
|
"decompress-zip": "^0.3.3",
|
||||||
"documentation": "^13.2.5",
|
"documentation": "^13.2.5",
|
||||||
"exif-reader": "^1.0.3",
|
"exif-reader": "^1.0.3",
|
||||||
"icc": "^2.0.0",
|
"icc": "^2.0.0",
|
||||||
"license-checker": "^25.0.1",
|
"license-checker": "^25.0.1",
|
||||||
"mocha": "^9.1.1",
|
"mocha": "^9.1.3",
|
||||||
"mock-fs": "^5.0.0",
|
"mock-fs": "^5.1.2",
|
||||||
"nyc": "^15.1.0",
|
"nyc": "^15.1.0",
|
||||||
"prebuild": "^10.0.1",
|
"prebuild": "^11.0.0",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"semistandard": "^16.0.1"
|
"semistandard": "^16.0.1"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -610,6 +610,33 @@ namespace sharp {
|
|||||||
return warning;
|
return warning;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Attach an event listener for progress updates, used to detect timeout
|
||||||
|
*/
|
||||||
|
void SetTimeout(VImage image, int const seconds) {
|
||||||
|
if (seconds > 0) {
|
||||||
|
VipsImage *im = image.get_image();
|
||||||
|
if (im->progress_signal == NULL) {
|
||||||
|
int *timeout = VIPS_NEW(im, int);
|
||||||
|
*timeout = seconds;
|
||||||
|
g_signal_connect(im, "eval", G_CALLBACK(VipsProgressCallBack), timeout);
|
||||||
|
vips_image_set_progress(im, TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Event listener for progress updates, used to detect timeout
|
||||||
|
*/
|
||||||
|
void VipsProgressCallBack(VipsImage *im, VipsProgress *progress, int *timeout) {
|
||||||
|
// printf("VipsProgressCallBack progress=%d run=%d timeout=%d\n", progress->percent, progress->run, *timeout);
|
||||||
|
if (*timeout > 0 && progress->run >= *timeout) {
|
||||||
|
vips_image_set_kill(im, TRUE);
|
||||||
|
vips_error("timeout", "%d%% complete", progress->percent);
|
||||||
|
*timeout = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Calculate the (left, top) coordinates of the output image
|
Calculate the (left, top) coordinates of the output image
|
||||||
within the input image, applying the given gravity during an embed.
|
within the input image, applying the given gravity during an embed.
|
||||||
|
|||||||
10
src/common.h
10
src/common.h
@@ -250,6 +250,16 @@ namespace sharp {
|
|||||||
*/
|
*/
|
||||||
std::string VipsWarningPop();
|
std::string VipsWarningPop();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Attach an event listener for progress updates, used to detect timeout
|
||||||
|
*/
|
||||||
|
void SetTimeout(VImage image, int const timeoutSeconds);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Event listener for progress updates, used to detect timeout
|
||||||
|
*/
|
||||||
|
void VipsProgressCallBack(VipsImage *image, VipsProgress *progress, int *timeoutSeconds);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Calculate the (left, top) coordinates of the output image
|
Calculate the (left, top) coordinates of the output image
|
||||||
within the input image, applying the given gravity during an embed.
|
within the input image, applying the given gravity during an embed.
|
||||||
|
|||||||
@@ -289,6 +289,10 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
yfactor = static_cast<double>(shrunkOnLoadHeight) / static_cast<double>(targetResizeHeight);
|
yfactor = static_cast<double>(shrunkOnLoadHeight) / static_cast<double>(targetResizeHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Remove animation properties from single page images
|
||||||
|
if (baton->input->pages == 1) {
|
||||||
|
image = sharp::RemoveAnimationProperties(image);
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure we're using a device-independent colour space
|
// Ensure we're using a device-independent colour space
|
||||||
char const *processingProfile = image.interpretation() == VIPS_INTERPRETATION_RGB16 ? "p3" : "srgb";
|
char const *processingProfile = image.interpretation() == VIPS_INTERPRETATION_RGB16 ? "p3" : "srgb";
|
||||||
@@ -378,11 +382,15 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
// Ensure shortest edge is at least 1 pixel
|
// Ensure shortest edge is at least 1 pixel
|
||||||
if (image.width() / xfactor < 0.5) {
|
if (image.width() / xfactor < 0.5) {
|
||||||
xfactor = 2 * image.width();
|
xfactor = 2 * image.width();
|
||||||
baton->width = 1;
|
if (baton->canvas != Canvas::EMBED) {
|
||||||
|
baton->width = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (image.height() / yfactor < 0.5) {
|
if (image.height() / yfactor < 0.5) {
|
||||||
yfactor = 2 * image.height();
|
yfactor = 2 * image.height();
|
||||||
baton->height = 1;
|
if (baton->canvas != Canvas::EMBED) {
|
||||||
|
baton->height = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
image = image.resize(1.0 / xfactor, VImage::option()
|
image = image.resize(1.0 / xfactor, VImage::option()
|
||||||
->set("vscale", 1.0 / yfactor)
|
->set("vscale", 1.0 / yfactor)
|
||||||
@@ -764,6 +772,7 @@ class PipelineWorker : public Napi::AsyncWorker {
|
|||||||
baton->loop);
|
baton->loop);
|
||||||
|
|
||||||
// Output
|
// Output
|
||||||
|
sharp::SetTimeout(image, baton->timeoutSeconds);
|
||||||
if (baton->fileOut.empty()) {
|
if (baton->fileOut.empty()) {
|
||||||
// Buffer output
|
// Buffer output
|
||||||
if (baton->formatOut == "jpeg" || (baton->formatOut == "input" && inputImageType == sharp::ImageType::JPEG)) {
|
if (baton->formatOut == "jpeg" || (baton->formatOut == "input" && inputImageType == sharp::ImageType::JPEG)) {
|
||||||
@@ -1451,6 +1460,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|||||||
std::string k = sharp::AttrAsStr(mdStrKeys, i);
|
std::string k = sharp::AttrAsStr(mdStrKeys, i);
|
||||||
baton->withMetadataStrs.insert(std::make_pair(k, sharp::AttrAsStr(mdStrs, k)));
|
baton->withMetadataStrs.insert(std::make_pair(k, sharp::AttrAsStr(mdStrs, k)));
|
||||||
}
|
}
|
||||||
|
baton->timeoutSeconds = sharp::AttrAsUint32(options, "timeoutSeconds");
|
||||||
// Format-specific
|
// Format-specific
|
||||||
baton->jpegQuality = sharp::AttrAsUint32(options, "jpegQuality");
|
baton->jpegQuality = sharp::AttrAsUint32(options, "jpegQuality");
|
||||||
baton->jpegProgressive = sharp::AttrAsBool(options, "jpegProgressive");
|
baton->jpegProgressive = sharp::AttrAsBool(options, "jpegProgressive");
|
||||||
@@ -1486,6 +1496,9 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) {
|
|||||||
baton->tiffTileHeight = sharp::AttrAsUint32(options, "tiffTileHeight");
|
baton->tiffTileHeight = sharp::AttrAsUint32(options, "tiffTileHeight");
|
||||||
baton->tiffXres = sharp::AttrAsDouble(options, "tiffXres");
|
baton->tiffXres = sharp::AttrAsDouble(options, "tiffXres");
|
||||||
baton->tiffYres = sharp::AttrAsDouble(options, "tiffYres");
|
baton->tiffYres = sharp::AttrAsDouble(options, "tiffYres");
|
||||||
|
if (baton->tiffXres == 1.0 && baton->tiffYres == 1.0 && baton->withMetadataDensity > 0) {
|
||||||
|
baton->tiffXres = baton->tiffYres = baton->withMetadataDensity / 25.4;
|
||||||
|
}
|
||||||
// tiff compression options
|
// tiff compression options
|
||||||
baton->tiffCompression = static_cast<VipsForeignTiffCompression>(
|
baton->tiffCompression = static_cast<VipsForeignTiffCompression>(
|
||||||
vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_TIFF_COMPRESSION,
|
vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_TIFF_COMPRESSION,
|
||||||
|
|||||||
@@ -182,6 +182,7 @@ struct PipelineBaton {
|
|||||||
double withMetadataDensity;
|
double withMetadataDensity;
|
||||||
std::string withMetadataIcc;
|
std::string withMetadataIcc;
|
||||||
std::unordered_map<std::string, std::string> withMetadataStrs;
|
std::unordered_map<std::string, std::string> withMetadataStrs;
|
||||||
|
int timeoutSeconds;
|
||||||
std::unique_ptr<double[]> convKernel;
|
std::unique_ptr<double[]> convKernel;
|
||||||
int convKernelWidth;
|
int convKernelWidth;
|
||||||
int convKernelHeight;
|
int convKernelHeight;
|
||||||
@@ -315,6 +316,7 @@ struct PipelineBaton {
|
|||||||
withMetadata(false),
|
withMetadata(false),
|
||||||
withMetadataOrientation(-1),
|
withMetadataOrientation(-1),
|
||||||
withMetadataDensity(0.0),
|
withMetadataDensity(0.0),
|
||||||
|
timeoutSeconds(0),
|
||||||
convKernelWidth(0),
|
convKernelWidth(0),
|
||||||
convKernelHeight(0),
|
convKernelHeight(0),
|
||||||
convKernelScale(0.0),
|
convKernelScale(0.0),
|
||||||
|
|||||||
@@ -298,6 +298,21 @@ describe('Input/output', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Support output to tif format', function (done) {
|
||||||
|
sharp(fixtures.inputTiff)
|
||||||
|
.resize(320, 240)
|
||||||
|
.toFormat('tif')
|
||||||
|
.toBuffer(function (err, data, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual(true, data.length > 0);
|
||||||
|
assert.strictEqual(data.length, info.size);
|
||||||
|
assert.strictEqual('tiff', info.format);
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
assert.strictEqual(240, info.height);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('Fail when output File is input File', function (done) {
|
it('Fail when output File is input File', function (done) {
|
||||||
sharp(fixtures.inputJpg).toFile(fixtures.inputJpg, function (err) {
|
sharp(fixtures.inputJpg).toFile(fixtures.inputJpg, function (err) {
|
||||||
assert(err instanceof Error);
|
assert(err instanceof Error);
|
||||||
|
|||||||
@@ -605,6 +605,40 @@ describe('Resize dimensions', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Ensure embedded shortest edge (height) is at least 1 pixel', function () {
|
||||||
|
return sharp({
|
||||||
|
create: {
|
||||||
|
width: 200,
|
||||||
|
height: 1,
|
||||||
|
channels: 3,
|
||||||
|
background: 'red'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.resize({ width: 50, height: 50, fit: sharp.fit.contain })
|
||||||
|
.toBuffer({ resolveWithObject: true })
|
||||||
|
.then(function (output) {
|
||||||
|
assert.strictEqual(50, output.info.width);
|
||||||
|
assert.strictEqual(50, output.info.height);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Ensure embedded shortest edge (width) is at least 1 pixel', function () {
|
||||||
|
return sharp({
|
||||||
|
create: {
|
||||||
|
width: 1,
|
||||||
|
height: 200,
|
||||||
|
channels: 3,
|
||||||
|
background: 'red'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.resize({ width: 50, height: 50, fit: sharp.fit.contain })
|
||||||
|
.toBuffer({ resolveWithObject: true })
|
||||||
|
.then(function (output) {
|
||||||
|
assert.strictEqual(50, output.info.width);
|
||||||
|
assert.strictEqual(50, output.info.height);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('Skip shrink-on-load where one dimension <4px', async () => {
|
it('Skip shrink-on-load where one dimension <4px', async () => {
|
||||||
const jpeg = await sharp({
|
const jpeg = await sharp({
|
||||||
create: {
|
create: {
|
||||||
|
|||||||
@@ -188,6 +188,26 @@ describe('TIFF', function () {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
it('TIFF imputes xres and yres from withMetadataDensity if not explicitly provided', async () => {
|
||||||
|
const data = await sharp(fixtures.inputTiff)
|
||||||
|
.resize(8, 8)
|
||||||
|
.tiff()
|
||||||
|
.withMetadata({ density: 600 })
|
||||||
|
.toBuffer();
|
||||||
|
const { density } = await sharp(data).metadata();
|
||||||
|
assert.strictEqual(600, density);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('TIFF uses xres and yres over withMetadataDensity if explicitly provided', async () => {
|
||||||
|
const data = await sharp(fixtures.inputTiff)
|
||||||
|
.resize(8, 8)
|
||||||
|
.tiff({ xres: 1000, yres: 1000 })
|
||||||
|
.withMetadata({ density: 600 })
|
||||||
|
.toBuffer();
|
||||||
|
const { density } = await sharp(data).metadata();
|
||||||
|
assert.strictEqual(25400, density);
|
||||||
|
});
|
||||||
|
|
||||||
it('TIFF invalid xres value should throw an error', function () {
|
it('TIFF invalid xres value should throw an error', function () {
|
||||||
assert.throws(function () {
|
assert.throws(function () {
|
||||||
sharp().tiff({ xres: '1000.0' });
|
sharp().tiff({ xres: '1000.0' });
|
||||||
|
|||||||
26
test/unit/timeout.js
Normal file
26
test/unit/timeout.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const assert = require('assert');
|
||||||
|
|
||||||
|
const sharp = require('../../');
|
||||||
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
|
describe('Timeout', function () {
|
||||||
|
it('Will timeout after 1s when performing slow blur operation', () => assert.rejects(
|
||||||
|
() => sharp(fixtures.inputJpg)
|
||||||
|
.blur(100)
|
||||||
|
.timeout({ seconds: 1 })
|
||||||
|
.toBuffer(),
|
||||||
|
/timeout: [0-9]+% complete/
|
||||||
|
));
|
||||||
|
|
||||||
|
it('invalid object', () => assert.throws(
|
||||||
|
() => sharp().timeout('fail'),
|
||||||
|
/Expected object for options but received fail of type string/
|
||||||
|
));
|
||||||
|
|
||||||
|
it('invalid seconds', () => assert.throws(
|
||||||
|
() => sharp().timeout({ seconds: 'fail' }),
|
||||||
|
/Expected integer between 0 and 3600 for seconds but received fail of type string/
|
||||||
|
));
|
||||||
|
});
|
||||||
@@ -209,4 +209,24 @@ describe('WebP', function () {
|
|||||||
fixtures.assertSimilar(fixtures.inputWebPAnimated, data, done);
|
fixtures.assertSimilar(fixtures.inputWebPAnimated, data, done);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should remove animation properties when loading single page', async () => {
|
||||||
|
const data = await sharp(fixtures.inputGifAnimatedLoop3)
|
||||||
|
.resize({ height: 570 })
|
||||||
|
.webp({ reductionEffort: 0 })
|
||||||
|
.toBuffer();
|
||||||
|
const metadata = await sharp(data).metadata();
|
||||||
|
assert.deepStrictEqual(metadata, {
|
||||||
|
format: 'webp',
|
||||||
|
size: 2580,
|
||||||
|
width: 740,
|
||||||
|
height: 570,
|
||||||
|
space: 'srgb',
|
||||||
|
channels: 3,
|
||||||
|
depth: 'uchar',
|
||||||
|
isProgressive: false,
|
||||||
|
hasProfile: false,
|
||||||
|
hasAlpha: false
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user