Compare commits

..

28 Commits

Author SHA1 Message Date
Lovell Fuller
34d5252242 Release v0.21.1 2018-12-07 19:23:54 +00:00
Lovell Fuller
f31e4d2869 Changelog, credit and doc refresh for #1483 2018-12-06 21:58:14 +00:00
Michael B. Klein
c695c40abc Expose libvips pyramid/tile options for TIFF output (#1483) 2018-12-06 22:33:46 +01:00
Lovell Fuller
fd1ca1dbb2 Ensure the tests for #1477 pass on OS X 2018-12-04 23:58:02 +01:00
Lovell Fuller
f25dbd5f61 Ensure the tests for #1477 pass on OS X 2018-12-04 23:45:08 +01:00
Keith
541e7104fd Expose libvips recombination matrix operation #1477 2018-12-04 23:06:34 +01:00
Lovell Fuller
94945cf6ac Changelog and credit for #1475 2018-12-04 07:49:41 +00:00
Lovell Fuller
db76e655f8 Ensure licensing checker works on Windows 2018-11-29 10:15:13 +00:00
Lovell Fuller
d43c7b581d Add licensing checker for production dependencies 2018-11-29 09:53:00 +00:00
Julian Aubourg
383b933e26 Build prototype with Object.assign to allow minification (#1475) 2018-11-26 19:40:06 +01:00
Lovell Fuller
d26ccf6294 Docs: update Alpine repository URLs 2018-11-21 22:42:58 +00:00
Lovell Fuller
6f9699f605 Ensure correct channel info for raw, greyscale output #1425 2018-11-19 20:00:30 +00:00
Quinn Pan
1e9093d781 Docs: correct code example in extend operation 2018-11-19 20:35:16 +01:00
Lovell Fuller
9dc6492e52 Docs: correct code example in extend operation 2018-11-19 19:34:16 +00:00
Lovell Fuller
d22f7cae6a Silence cast-function-type warnings from GCC 8+ 2018-11-19 18:47:35 +00:00
Lovell Fuller
473afaab45 Install: detect missing libvips on OpenBSD and SunOS
See https://github.com/lovell/sharp-libvips/issues/12
2018-11-19 18:46:05 +00:00
Lovell Fuller
dcd68303a4 Docs: add installation details for Lambda without Docker 2018-11-16 10:28:34 +00:00
Lovell Fuller
03394556b5 Update semistandard linter to latest 2018-11-11 18:05:40 +00:00
Lovell Fuller
1c4f6f75f3 Add Node 11 to CI, experimental only, no prebuild
Hide deprecation warnings - see nodejs/nan#811
2018-11-11 17:55:35 +00:00
Lovell Fuller
f00928dedb Doc refresh for #1438 #1439 2018-11-11 17:40:19 +00:00
Daiz
a48f8fbb61 Allow separate parameters for gamma encoding and decoding (#1439) 2018-11-11 10:15:38 +01:00
Daiz
1fa388370e Add support for the "mitchell" kernel for image reductions (#1438) 2018-10-28 15:11:27 +00:00
Christoph Tavan
95ef6b3f71 Docs: update Alpine libvips installation instructions (#1429)
With version 8.7.0 of the vips-dev Alpine package the documented installation instructions no longer work and result in:

ERROR: unsatisfiable constraints:
  pc:fftw3 (missing):
    required by: vips-dev-8.7.0-r0[pc:fftw3] vips-dev-8.7.0-r0[pc:fftw3] vips-dev-8.7.0-r0[pc:fftw3]

The fix was proposed in https://bugs.alpinelinux.org/issues/9561#note-2
2018-10-24 14:31:32 +01:00
Lovell Fuller
de11d36d00 Minor version bumps 2018-10-22 19:38:06 +01:00
Lovell Fuller
d77c2adabe Changelog and docs for #1422 2018-10-22 19:17:42 +01:00
SethWen
c89c055ae0 Install: add support for npm_config_sharp_dist_base_url (#1422) 2018-10-22 18:54:47 +01:00
Lovell Fuller
dac8117f32 Docs: ensure options are included for flatten op 2018-10-08 19:56:30 +01:00
Waylon Walker
937b091bab Docs: clear _libvips cache on Windows (#1403) 2018-10-07 16:49:05 +01:00
40 changed files with 693 additions and 182 deletions

View File

@@ -21,6 +21,14 @@ matrix:
after_success:
- npm install coveralls
- cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js
- name: "Linux (glibc) - Node 11 (Experimental)"
os: linux
dist: trusty
sudo: false
language: node_js
node_js: "11"
before_install:
- unset PREBUILD_TOKEN
- name: "Linux (musl) - Node 8"
os: linux
dist: trusty
@@ -41,6 +49,16 @@ matrix:
- sudo docker exec sharp apk add build-base git python2 --update-cache
install: sudo docker exec sharp sh -c "npm install --unsafe-perm"
script: sudo docker exec sharp sh -c "npm test"
- name: "Linux (musl) - Node 11 (Experimental)"
os: linux
dist: trusty
sudo: true
language: minimal
before_install:
- sudo docker run -dit --name sharp --env CI --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp node:11-alpine
- sudo docker exec sharp apk add build-base git python2 --update-cache
install: sudo docker exec sharp sh -c "npm install --unsafe-perm"
script: sudo docker exec sharp sh -c "npm test"
- name: "OS X - Node 6"
os: osx
osx_image: xcode9.2
@@ -56,3 +74,10 @@ matrix:
osx_image: xcode9.2
language: node_js
node_js: "10"
- name: "OS X - Node 11 (Experimental)"
os: osx
osx_image: xcode9.2
language: node_js
node_js: "11"
before_install:
- unset PREBUILD_TOKEN

View File

@@ -7,6 +7,8 @@ environment:
- nodejs_version: "6"
- nodejs_version: "8"
- nodejs_version: "10"
- nodejs_version: "11"
PREBUILD_TOKEN: ""
install:
- ps: Install-Product node $env:nodejs_version x64
- npm install -g npm@5

View File

@@ -183,13 +183,23 @@
},
'configurations': {
'Release': {
'cflags_cc': [
'-Wno-cast-function-type',
'-Wno-deprecated-declarations'
],
'xcode_settings': {
'OTHER_CPLUSPLUSFLAGS': [
'-Wno-deprecated-declarations'
]
},
'msvs_settings': {
'VCCLCompilerTool': {
'ExceptionHandling': 1
}
},
'msvs_disabled_warnings': [
4275
4275,
4996
]
}
},

View File

@@ -118,7 +118,8 @@ Merge alpha transparency channel, if any, with a background.
### Parameters
- `options`
- `options` **[Object][2]?**
- `options.background` **([String][3] \| [Object][2])** background colour, parsed by the [color][4] module, defaults to black. (optional, default `{r:0,g:0,b:0}`)
Returns **Sharp**
@@ -130,9 +131,12 @@ This can improve the perceived brightness of a resized image in non-linear colou
JPEG and WebP input images will not take advantage of the shrink-on-load performance optimisation
when applying a gamma correction.
Supply a second argument to use a different output gamma value, otherwise the first value is used in both cases.
### Parameters
- `gamma` **[Number][1]** value between 1.0 and 3.0. (optional, default `2.2`)
- `gammaOut` **[Number][1]?** value between 1.0 and 3.0. (optional, defaults to same as `gamma`)
- Throws **[Error][5]** Invalid parameters
@@ -250,6 +254,35 @@ Apply the linear formula a \* input + b to the image (levels adjustment)
- `b` **[Number][1]** offset (optional, default `0.0`)
- Throws **[Error][5]** Invalid parameters
Returns **Sharp**
## recomb
Recomb the image with the specified matrix.
### Parameters
- `inputMatrix`
- `3x3` **[Array][7]<[Array][7]<[Number][1]>>** Recombination matrix
### Examples
```javascript
sharp(input)
.recomb([
[0.3588, 0.7044, 0.1368],
[0.2990, 0.5870, 0.1140],
[0.2392, 0.4696, 0.0912],
])
.raw()
.toBuffer(function(err, data, info) {
// data contains the raw pixel data after applying the recomb
// With this example input, a sepia filter has been applied
});
```
- Throws **[Error][5]** Invalid parameters
Returns **Sharp**

View File

@@ -206,6 +206,10 @@ Use these TIFF options for output image.
- `options.force` **[Boolean][6]** force TIFF output, otherwise attempt to use input format (optional, default `true`)
- `options.compression` **[Boolean][6]** compression options: lzw, deflate, jpeg, ccittfax4 (optional, default `'jpeg'`)
- `options.predictor` **[Boolean][6]** compression predictor options: none, horizontal, float (optional, default `'horizontal'`)
- `options.pyramid` **[Boolean][6]** write an image pyramid (optional, default `false`)
- `options.tile` **[Boolean][6]** write a tiled tiff (optional, default `false`)
- `options.tileWidth` **[Boolean][6]** horizontal tile size (optional, default `256`)
- `options.tileHeight` **[Boolean][6]** vertical tile size (optional, default `256`)
- `options.xres` **[Number][8]** horizontal resolution in pixels/mm (optional, default `1.0`)
- `options.yres` **[Number][8]** vertical resolution in pixels/mm (optional, default `1.0`)
- `options.squash` **[Boolean][6]** squash 8-bit images down to 1 bit (optional, default `false`)

View File

@@ -30,22 +30,23 @@ Possible interpolation kernels are:
- `nearest`: Use [nearest neighbour interpolation][4].
- `cubic`: Use a [Catmull-Rom spline][5].
- `lanczos2`: Use a [Lanczos kernel][6] with `a=2`.
- `mitchell`: Use a [Mitchell-Netravali spline][6].
- `lanczos2`: Use a [Lanczos kernel][7] with `a=2`.
- `lanczos3`: Use a Lanczos kernel with `a=3` (the default).
### Parameters
- `width` **[Number][7]?** pixels wide the resultant image should be. Use `null` or `undefined` to auto-scale the width to match the height.
- `height` **[Number][7]?** pixels high the resultant image should be. Use `null` or `undefined` to auto-scale the height to match the width.
- `options` **[Object][8]?**
- `options.width` **[String][9]?** alternative means of specifying `width`. If both are present this take priority.
- `options.height` **[String][9]?** alternative means of specifying `height`. If both are present this take priority.
- `options.fit` **[String][9]** how the image should be resized to fit both provided dimensions, one of `cover`, `contain`, `fill`, `inside` or `outside`. (optional, default `'cover'`)
- `options.position` **[String][9]** position, gravity or strategy to use when `fit` is `cover` or `contain`. (optional, default `'centre'`)
- `options.background` **([String][9] \| [Object][8])** background colour when using a `fit` of `contain`, parsed by the [color][10] module, defaults to black without transparency. (optional, default `{r:0,g:0,b:0,alpha:1}`)
- `options.kernel` **[String][9]** the kernel to use for image reduction. (optional, default `'lanczos3'`)
- `options.withoutEnlargement` **[Boolean][11]** do not enlarge if the width _or_ height are already less than the specified dimensions, equivalent to GraphicsMagick's `>` geometry option. (optional, default `false`)
- `options.fastShrinkOnLoad` **[Boolean][11]** take greater advantage of the JPEG and WebP shrink-on-load feature, which can lead to a slight moiré pattern on some images. (optional, default `true`)
- `width` **[Number][8]?** pixels wide the resultant image should be. Use `null` or `undefined` to auto-scale the width to match the height.
- `height` **[Number][8]?** pixels high the resultant image should be. Use `null` or `undefined` to auto-scale the height to match the width.
- `options` **[Object][9]?**
- `options.width` **[String][10]?** alternative means of specifying `width`. If both are present this take priority.
- `options.height` **[String][10]?** alternative means of specifying `height`. If both are present this take priority.
- `options.fit` **[String][10]** how the image should be resized to fit both provided dimensions, one of `cover`, `contain`, `fill`, `inside` or `outside`. (optional, default `'cover'`)
- `options.position` **[String][10]** position, gravity or strategy to use when `fit` is `cover` or `contain`. (optional, default `'centre'`)
- `options.background` **([String][10] \| [Object][9])** background colour when using a `fit` of `contain`, parsed by the [color][11] module, defaults to black without transparency. (optional, default `{r:0,g:0,b:0,alpha:1}`)
- `options.kernel` **[String][10]** the kernel to use for image reduction. (optional, default `'lanczos3'`)
- `options.withoutEnlargement` **[Boolean][12]** do not enlarge if the width _or_ height are already less than the specified dimensions, equivalent to GraphicsMagick's `>` geometry option. (optional, default `false`)
- `options.fastShrinkOnLoad` **[Boolean][12]** take greater advantage of the JPEG and WebP shrink-on-load feature, which can lead to a slight moiré pattern on some images. (optional, default `true`)
### Examples
@@ -113,7 +114,7 @@ sharp(input)
});
```
- Throws **[Error][12]** Invalid parameters
- Throws **[Error][13]** Invalid parameters
Returns **Sharp**
@@ -124,12 +125,12 @@ This operation will always occur after resizing and extraction, if any.
### Parameters
- `extend` **([Number][7] \| [Object][8])** single pixel count to add to all edges or an Object with per-edge counts
- `extend.top` **[Number][7]?**
- `extend.left` **[Number][7]?**
- `extend.bottom` **[Number][7]?**
- `extend.right` **[Number][7]?**
- `extend.background` **([String][9] \| [Object][8])** background colour, parsed by the [color][10] module, defaults to black without transparency. (optional, default `{r:0,g:0,b:0,alpha:1}`)
- `extend` **([Number][8] \| [Object][9])** single pixel count to add to all edges or an Object with per-edge counts
- `extend.top` **[Number][8]?**
- `extend.left` **[Number][8]?**
- `extend.bottom` **[Number][8]?**
- `extend.right` **[Number][8]?**
- `extend.background` **([String][10] \| [Object][9])** background colour, parsed by the [color][11] module, defaults to black without transparency. (optional, default `{r:0,g:0,b:0,alpha:1}`)
### Examples
@@ -138,7 +139,6 @@ This operation will always occur after resizing and extraction, if any.
// to the top, left and right edges and 20 to the bottom edge
sharp(input)
.resize(140)
.)
.extend({
top: 10,
bottom: 20,
@@ -149,7 +149,7 @@ sharp(input)
...
```
- Throws **[Error][12]** Invalid parameters
- Throws **[Error][13]** Invalid parameters
Returns **Sharp**
@@ -163,11 +163,11 @@ Extract a region of the image.
### Parameters
- `options` **[Object][8]**
- `options.left` **[Number][7]** zero-indexed offset from left edge
- `options.top` **[Number][7]** zero-indexed offset from top edge
- `options.width` **[Number][7]** dimension of extracted image
- `options.height` **[Number][7]** dimension of extracted image
- `options` **[Object][9]**
- `options.left` **[Number][8]** zero-indexed offset from left edge
- `options.top` **[Number][8]** zero-indexed offset from top edge
- `options.width` **[Number][8]** dimension of extracted image
- `options.height` **[Number][8]** dimension of extracted image
### Examples
@@ -189,7 +189,7 @@ sharp(input)
});
```
- Throws **[Error][12]** Invalid parameters
- Throws **[Error][13]** Invalid parameters
Returns **Sharp**
@@ -200,10 +200,10 @@ The `info` response Object will contain `trimOffsetLeft` and `trimOffsetTop` pro
### Parameters
- `threshold` **[Number][7]** the allowed difference from the top-left pixel, a number greater than zero. (optional, default `10`)
- `threshold` **[Number][8]** the allowed difference from the top-left pixel, a number greater than zero. (optional, default `10`)
- Throws **[Error][12]** Invalid parameters
- Throws **[Error][13]** Invalid parameters
Returns **Sharp**
@@ -217,16 +217,18 @@ Returns **Sharp**
[5]: https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline
[6]: https://en.wikipedia.org/wiki/Lanczos_resampling#Lanczos_kernel
[6]: https://www.cs.utexas.edu/~fussell/courses/cs384g-fall2013/lectures/mitchell/Mitchell.pdf
[7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
[7]: https://en.wikipedia.org/wiki/Lanczos_resampling#Lanczos_kernel
[8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
[8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
[9]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
[9]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
[10]: https://www.npmjs.org/package/color
[10]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
[11]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
[11]: https://www.npmjs.org/package/color
[12]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error
[12]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
[13]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error

View File

@@ -4,6 +4,35 @@
Requires libvips v8.7.0.
#### v0.21.1 - 7<sup>th</sup> December 2018
* Install: support `sharp_dist_base_url` npm config, like existing `SHARP_DIST_BASE_URL`.
[#1422](https://github.com/lovell/sharp/pull/1422)
[@SethWen](https://github.com/SethWen)
* Ensure `channel` metadata is correct for raw, greyscale output.
[#1425](https://github.com/lovell/sharp/issues/1425)
* Add support for the "mitchell" kernel for image reductions.
[#1438](https://github.com/lovell/sharp/pull/1438)
[@Daiz](https://github.com/Daiz)
* Allow separate parameters for gamma encoding and decoding.
[#1439](https://github.com/lovell/sharp/pull/1439)
[@Daiz](https://github.com/Daiz)
* Build prototype with `Object.assign` to allow minification.
[#1475](https://github.com/lovell/sharp/pull/1475)
[@jaubourg](https://github.com/jaubourg)
* Expose libvips' recombination matrix operation.
[#1477](https://github.com/lovell/sharp/pull/1477)
[@fromkeith](https://github.com/fromkeith)
* Expose libvips' pyramid/tile options for TIFF output.
[#1483](https://github.com/lovell/sharp/pull/1483)
[@mbklein](https://github.com/mbklein)
#### v0.21.0 - 4<sup>th</sup> October 2018
* Deprecate the following resize-related functions:

View File

@@ -119,6 +119,9 @@ the help and code contributions of the following people:
* [Aidan Hoolachan](https://github.com/ajhool)
* [Axel Eirola](https://github.com/aeirola)
* [Freezy](https://github.com/freezy)
* [Julian Aubourg](https://github.com/jaubourg)
* [Keith Belovay](https://github.com/fromkeith)
* [Michael B. Klein](https://github.com/mbklein)
Thank you!

View File

@@ -72,7 +72,9 @@ libvips is available in the
[testing repository](https://pkgs.alpinelinux.org/packages?name=vips-dev):
```sh
apk add vips-dev fftw-dev build-base --update-cache --repository https://dl-3.alpinelinux.org/alpine/edge/testing/
apk add vips-dev fftw-dev build-base --update-cache \
--repository https://alpine.global.ssl.fastly.net/alpine/edge/testing/ \
--repository https://alpine.global.ssl.fastly.net/alpine/edge/main
```
The smaller stack size of musl libc means
@@ -95,7 +97,8 @@ that it can be located using `pkg-config --modversion vips-cpp`.
[![Windows x64 Build Status](https://ci.appveyor.com/api/projects/status/pgtul704nkhhg6sg)](https://ci.appveyor.com/project/lovell/sharp)
libvips and its dependencies are fetched and stored within `node_modules\sharp\vendor` during `npm install`.
This involves an automated HTTPS download of approximately 13MB.
This involves an automated HTTPS download of approximately 13MB. If you are having issues during
installation consider removing the directory ```C:\Users\[user]\AppData\Roaming\npm-cache\_libvips```.
Only 64-bit (x64) `node.exe` is supported.
@@ -146,16 +149,25 @@ docker pull tailor/docker-libvips
### AWS Lambda
A [deployment package](http://docs.aws.amazon.com/lambda/latest/dg/nodejs-create-deployment-pkg.html) for the
[Lambda Execution Environment](http://docs.aws.amazon.com/lambda/latest/dg/current-supported-versions.html)
can be built using Docker.
Set the Lambda runtime to Node.js 8.10.
The binaries in the `node_modules` directory of the
[deployment package](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-create-deployment-pkg.html)
must be for the Linux x64 platform/architecture.
On non-Linux machines such as OS X and Windows run the following:
```sh
rm -rf node_modules/sharp
docker run -v "$PWD":/var/task lambci/lambda:build-nodejs8.10 npm install
npm install --arch=x64 --platform=linux --target=8.10.0 sharp
```
Set the Lambda runtime to Node.js 8.10.
Alternatively a Docker container closely matching the Lambda runtime can be used:
```sh
rm -rf node_modules/sharp
docker run -v "$PWD":/var/task lambci/lambda:build-nodejs8.10 npm install sharp
```
To get the best performance select the largest memory available.
A 1536 MB function provides ~12x more CPU time than a 128 MB function.
@@ -217,7 +229,14 @@ you can do so via
[https://github.com/lovell/sharp-libvips/releases](https://github.com/lovell/sharp-libvips/releases)
Should you wish to install these from your own location,
set the `SHARP_DIST_BASE_URL` environment variable, e.g.
set the `sharp_dist_base_url` npm config option, e.g.
```sh
npm config set sharp_dist_base_url "https://hostname/path/"
npm install sharp
```
or set the `SHARP_DIST_BASE_URL` environment variable, e.g.
```sh
SHARP_DIST_BASE_URL="https://hostname/path/" npm install sharp

View File

@@ -16,7 +16,7 @@ const libvips = require('../lib/libvips');
const platform = require('../lib/platform');
const minimumLibvipsVersion = libvips.minimumLibvipsVersion;
const distBaseUrl = process.env.SHARP_DIST_BASE_URL || `https://github.com/lovell/sharp-libvips/releases/download/v${minimumLibvipsVersion}/`;
const distBaseUrl = process.env.npm_config_sharp_dist_base_url || process.env.SHARP_DIST_BASE_URL || `https://github.com/lovell/sharp-libvips/releases/download/v${minimumLibvipsVersion}/`;
const fail = function (err) {
npmLog.error('sharp', err.message);
@@ -55,8 +55,8 @@ try {
if (arch === 'ia32') {
throw new Error(`Intel Architecture 32-bit systems require manual installation of libvips >= ${minimumLibvipsVersion}`);
}
if (platformAndArch === 'freebsd-x64') {
throw new Error(`FreeBSD systems require manual installation of libvips >= ${minimumLibvipsVersion}`);
if (platformAndArch === 'freebsd-x64' || platformAndArch === 'openbsd-x64' || platformAndArch === 'sunos-x64') {
throw new Error(`BSD/SunOS systems require manual installation of libvips >= ${minimumLibvipsVersion}`);
}
if (detectLibc.family === detectLibc.GLIBC && detectLibc.version && semver.lt(`${detectLibc.version}.0`, '2.13.0')) {
throw new Error(`Use with glibc version ${detectLibc.version} requires manual installation of libvips >= ${minimumLibvipsVersion}`);

View File

@@ -117,14 +117,12 @@ function bandbool (boolOp) {
* @private
*/
module.exports = function (Sharp) {
// Public instance functions
[
Object.assign(Sharp.prototype, {
// Public instance functions
removeAlpha,
extractChannel,
joinChannel,
bandbool
].forEach(function (f) {
Sharp.prototype[f.name] = f;
});
// Class attributes
Sharp.bool = bool;

View File

@@ -123,7 +123,7 @@ function _setColourOption (key, val) {
* @private
*/
module.exports = function (Sharp) {
[
Object.assign(Sharp.prototype, {
// Public
tint,
greyscale,
@@ -132,8 +132,6 @@ module.exports = function (Sharp) {
toColorspace,
// Private
_setColourOption
].forEach(function (f) {
Sharp.prototype[f.name] = f;
});
// Class attributes
Sharp.colourspace = colourspace;

View File

@@ -7,7 +7,7 @@ const events = require('events');
const is = require('./is');
require('./libvips').hasVendoredLibvips();
const sharp = require('../build/Release/sharp.node');
const sharp = require('bindings')('sharp.node');
// Use NODE_DEBUG=sharp to enable libvips warnings
const debuglog = util.debuglog('sharp');
@@ -136,6 +136,7 @@ const Sharp = function (input, options) {
thresholdGrayscale: true,
trimThreshold: 0,
gamma: 0,
gammaOut: 0,
greyscale: false,
normalise: 0,
booleanBufferIn: null,
@@ -176,7 +177,11 @@ const Sharp = function (input, options) {
tiffQuality: 80,
tiffCompression: 'jpeg',
tiffPredictor: 'horizontal',
tiffPyramid: false,
tiffSquash: false,
tiffTile: false,
tiffTileHeight: 256,
tiffTileWidth: 256,
tiffXres: 1.0,
tiffYres: 1.0,
tileSize: 256,

View File

@@ -362,7 +362,7 @@ function sequentialRead (sequentialRead) {
* @private
*/
module.exports = function (Sharp) {
[
Object.assign(Sharp.prototype, {
// Private
_createInputDescriptor,
_write,
@@ -374,7 +374,5 @@ module.exports = function (Sharp) {
stats,
limitInputPixels,
sequentialRead
].forEach(function (f) {
Sharp.prototype[f.name] = f;
});
};

View File

@@ -172,6 +172,7 @@ function blur (sigma) {
/**
* Merge alpha transparency channel, if any, with a background.
* @param {Object} [options]
* @param {String|Object} [options.background={r: 0, g: 0, b: 0}] - background colour, parsed by the [color](https://www.npmjs.org/package/color) module, defaults to black.
* @returns {Sharp}
*/
@@ -189,11 +190,15 @@ function flatten (options) {
* This can improve the perceived brightness of a resized image in non-linear colour spaces.
* JPEG and WebP input images will not take advantage of the shrink-on-load performance optimisation
* when applying a gamma correction.
*
* Supply a second argument to use a different output gamma value, otherwise the first value is used in both cases.
*
* @param {Number} [gamma=2.2] value between 1.0 and 3.0.
* @param {Number} [gammaOut] value between 1.0 and 3.0. (optional, defaults to same as `gamma`)
* @returns {Sharp}
* @throws {Error} Invalid parameters
*/
function gamma (gamma) {
function gamma (gamma, gammaOut) {
if (!is.defined(gamma)) {
// Default gamma correction of 2.2 (sRGB)
this.options.gamma = 2.2;
@@ -202,6 +207,14 @@ function gamma (gamma) {
} else {
throw new Error('Invalid gamma correction (1.0 to 3.0) ' + gamma);
}
if (!is.defined(gammaOut)) {
// Default gamma correction for output is same as input
this.options.gammaOut = this.options.gamma;
} else if (is.number(gammaOut) && is.inRange(gammaOut, 1, 3)) {
this.options.gammaOut = gammaOut;
} else {
throw new Error('Invalid output gamma correction (1.0 to 3.0) ' + gammaOut);
}
return this;
}
@@ -365,12 +378,49 @@ function linear (a, b) {
return this;
}
/**
* Recomb the image with the specified matrix.
*
* @example
* sharp(input)
* .recomb([
* [0.3588, 0.7044, 0.1368],
* [0.2990, 0.5870, 0.1140],
* [0.2392, 0.4696, 0.0912],
* ])
* .raw()
* .toBuffer(function(err, data, info) {
* // data contains the raw pixel data after applying the recomb
* // With this example input, a sepia filter has been applied
* });
*
* @param {Array<Array<Number>>} 3x3 Recombination matrix
* @returns {Sharp}
* @throws {Error} Invalid parameters
*/
function recomb (inputMatrix) {
if (!Array.isArray(inputMatrix) || inputMatrix.length !== 3 ||
inputMatrix[0].length !== 3 ||
inputMatrix[1].length !== 3 ||
inputMatrix[2].length !== 3
) {
// must pass in a kernel
throw new Error('Invalid Recomb Matrix');
}
this.options.recombMatrix = [
inputMatrix[0][0], inputMatrix[0][1], inputMatrix[0][2],
inputMatrix[1][0], inputMatrix[1][1], inputMatrix[1][2],
inputMatrix[2][0], inputMatrix[2][1], inputMatrix[2][2]
].map(Number);
return this;
}
/**
* Decorate the Sharp prototype with operation-related functions.
* @private
*/
module.exports = function (Sharp) {
[
Object.assign(Sharp.prototype, {
rotate,
flip,
flop,
@@ -385,8 +435,7 @@ module.exports = function (Sharp) {
convolve,
threshold,
boolean,
linear
].forEach(function (f) {
Sharp.prototype[f.name] = f;
linear,
recomb
});
};

View File

@@ -304,6 +304,10 @@ function webp (options) {
* @param {Boolean} [options.force=true] - force TIFF output, otherwise attempt to use input format
* @param {Boolean} [options.compression='jpeg'] - compression options: lzw, deflate, jpeg, ccittfax4
* @param {Boolean} [options.predictor='horizontal'] - compression predictor options: none, horizontal, float
* @param {Boolean} [options.pyramid=false] - write an image pyramid
* @param {Boolean} [options.tile=false] - write a tiled tiff
* @param {Boolean} [options.tileWidth=256] - horizontal tile size
* @param {Boolean} [options.tileHeight=256] - vertical tile size
* @param {Number} [options.xres=1.0] - horizontal resolution in pixels/mm
* @param {Number} [options.yres=1.0] - vertical resolution in pixels/mm
* @param {Boolean} [options.squash=false] - squash 8-bit images down to 1 bit
@@ -311,51 +315,83 @@ function webp (options) {
* @throws {Error} Invalid options
*/
function tiff (options) {
if (is.object(options) && is.defined(options.quality)) {
if (is.integer(options.quality) && is.inRange(options.quality, 1, 100)) {
this.options.tiffQuality = options.quality;
} else {
throw new Error('Invalid quality (integer, 1-100) ' + options.quality);
if (is.object(options)) {
if (is.defined(options.quality)) {
if (is.integer(options.quality) && is.inRange(options.quality, 1, 100)) {
this.options.tiffQuality = options.quality;
} else {
throw new Error('Invalid quality (integer, 1-100) ' + options.quality);
}
}
}
if (is.object(options) && is.defined(options.squash)) {
if (is.bool(options.squash)) {
this.options.tiffSquash = options.squash;
} else {
throw new Error('Invalid Value for squash ' + options.squash + ' Only Boolean Values allowed for options.squash.');
if (is.defined(options.squash)) {
if (is.bool(options.squash)) {
this.options.tiffSquash = options.squash;
} else {
throw new Error('Invalid Value for squash ' + options.squash + ' Only Boolean Values allowed for options.squash.');
}
}
}
// resolution
if (is.object(options) && is.defined(options.xres)) {
if (is.number(options.xres)) {
this.options.tiffXres = options.xres;
} else {
throw new Error('Invalid Value for xres ' + options.xres + ' Only numeric values allowed for options.xres');
// tiling
if (is.defined(options.tile)) {
if (is.bool(options.tile)) {
this.options.tiffTile = options.tile;
} else {
throw new Error('Invalid Value for tile ' + options.tile + ' Only Boolean values allowed for options.tile');
}
}
}
if (is.object(options) && is.defined(options.yres)) {
if (is.number(options.yres)) {
this.options.tiffYres = options.yres;
} else {
throw new Error('Invalid Value for yres ' + options.yres + ' Only numeric values allowed for options.yres');
if (is.defined(options.tileWidth)) {
if (is.number(options.tileWidth) && options.tileWidth > 0) {
this.options.tiffTileWidth = options.tileWidth;
} else {
throw new Error('Invalid Value for tileWidth ' + options.tileWidth + ' Only positive numeric values allowed for options.tileWidth');
}
}
}
// compression
if (is.defined(options) && is.defined(options.compression)) {
if (is.string(options.compression) && is.inArray(options.compression, ['lzw', 'deflate', 'jpeg', 'ccittfax4', 'none'])) {
this.options.tiffCompression = options.compression;
} else {
const message = `Invalid compression option "${options.compression}". Should be one of: lzw, deflate, jpeg, ccittfax4, none`;
throw new Error(message);
if (is.defined(options.tileHeight)) {
if (is.number(options.tileHeight) && options.tileHeight > 0) {
this.options.tiffTileHeight = options.tileHeight;
} else {
throw new Error('Invalid Value for tileHeight ' + options.tileHeight + ' Only positive numeric values allowed for options.tileHeight');
}
}
}
// predictor
if (is.defined(options) && is.defined(options.predictor)) {
if (is.string(options.predictor) && is.inArray(options.predictor, ['none', 'horizontal', 'float'])) {
this.options.tiffPredictor = options.predictor;
} else {
const message = `Invalid predictor option "${options.predictor}". Should be one of: none, horizontal, float`;
throw new Error(message);
// pyramid
if (is.defined(options.pyramid)) {
if (is.bool(options.pyramid)) {
this.options.tiffPyramid = options.pyramid;
} else {
throw new Error('Invalid Value for pyramid ' + options.pyramid + ' Only Boolean values allowed for options.pyramid');
}
}
// resolution
if (is.defined(options.xres)) {
if (is.number(options.xres)) {
this.options.tiffXres = options.xres;
} else {
throw new Error('Invalid Value for xres ' + options.xres + ' Only numeric values allowed for options.xres');
}
}
if (is.defined(options.yres)) {
if (is.number(options.yres)) {
this.options.tiffYres = options.yres;
} else {
throw new Error('Invalid Value for yres ' + options.yres + ' Only numeric values allowed for options.yres');
}
}
// compression
if (is.defined(options.compression)) {
if (is.string(options.compression) && is.inArray(options.compression, ['lzw', 'deflate', 'jpeg', 'ccittfax4', 'none'])) {
this.options.tiffCompression = options.compression;
} else {
const message = `Invalid compression option "${options.compression}". Should be one of: lzw, deflate, jpeg, ccittfax4, none`;
throw new Error(message);
}
}
// predictor
if (is.defined(options.predictor)) {
if (is.string(options.predictor) && is.inArray(options.predictor, ['none', 'horizontal', 'float'])) {
this.options.tiffPredictor = options.predictor;
} else {
const message = `Invalid predictor option "${options.predictor}". Should be one of: none, horizontal, float`;
throw new Error(message);
}
}
}
return this._updateFormatOut('tiff', options);
@@ -641,7 +677,7 @@ function _pipeline (callback) {
* @private
*/
module.exports = function (Sharp) {
[
Object.assign(Sharp.prototype, {
// Public
toFile,
toBuffer,
@@ -658,7 +694,5 @@ module.exports = function (Sharp) {
_setBooleanOption,
_read,
_pipeline
].forEach(function (f) {
Sharp.prototype[f.name] = f;
});
};

View File

@@ -55,6 +55,7 @@ const strategy = {
const kernel = {
nearest: 'nearest',
cubic: 'cubic',
mitchell: 'mitchell',
lanczos2: 'lanczos2',
lanczos3: 'lanczos3'
};
@@ -110,6 +111,7 @@ const mapFitToCanvas = {
* Possible interpolation kernels are:
* - `nearest`: Use [nearest neighbour interpolation](http://en.wikipedia.org/wiki/Nearest-neighbor_interpolation).
* - `cubic`: Use a [Catmull-Rom spline](https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline).
* - `mitchell`: Use a [Mitchell-Netravali spline](https://www.cs.utexas.edu/~fussell/courses/cs384g-fall2013/lectures/mitchell/Mitchell.pdf).
* - `lanczos2`: Use a [Lanczos kernel](https://en.wikipedia.org/wiki/Lanczos_resampling#Lanczos_kernel) with `a=2`.
* - `lanczos3`: Use a Lanczos kernel with `a=3` (the default).
*
@@ -269,7 +271,6 @@ function resize (width, height, options) {
* // to the top, left and right edges and 20 to the bottom edge
* sharp(input)
* .resize(140)
* .)
* .extend({
* top: 10,
* bottom: 20,
@@ -468,13 +469,11 @@ function withoutEnlargement (withoutEnlargement) {
* @private
*/
module.exports = function (Sharp) {
[
Object.assign(Sharp.prototype, {
resize,
extend,
extract,
trim
].forEach(function (f) {
Sharp.prototype[f.name] = f;
});
// Class attributes
Sharp.gravity = gravity;

View File

@@ -1,7 +1,7 @@
{
"name": "sharp",
"description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP and TIFF images",
"version": "0.21.0",
"version": "0.21.1",
"author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://github.com/lovell/sharp",
"contributors": [
@@ -55,13 +55,19 @@
"Alun Davies <alun.owain.davies@googlemail.com>",
"Aidan Hoolachan <ajhoolachan21@gmail.com>",
"Axel Eirola <axel.eirola@iki.fi>",
"Freezy <freezy@xbmc.org>"
"Freezy <freezy@xbmc.org>",
"Daiz <taneli.vatanen@gmail.com>",
"Julian Aubourg <j@ubourg.net>",
"Keith Belovay <keith@picthrive.com>",
"Michael B. Klein <mbklein@gmail.com>"
],
"scripts": {
"install": "(node install/libvips && node install/dll-copy && prebuild-install) || (node-gyp rebuild && node install/dll-copy)",
"clean": "rm -rf node_modules/ build/ vendor/ .nyc_output/ coverage/ test/fixtures/output.*",
"test": "semistandard && cc && nyc --reporter=lcov --branches=99 mocha --slow=5000 --timeout=60000 ./test/unit/*.js && prebuild-ci",
"coverage": "./test/coverage/report.sh",
"test": "semistandard && cc && npm run test-unit && npm run test-licensing && prebuild-ci",
"test-unit": "nyc --reporter=lcov --branches=99 mocha --slow=5000 --timeout=60000 ./test/unit/*.js",
"test-licensing": "license-checker --production --summary --onlyAllow=\"Apache-2.0;BSD;ISC;MIT\"",
"test-coverage": "./test/coverage/report.sh",
"test-leak": "./test/leak/leak.sh",
"docs": "for m in constructor input resize composite operation colour channel output utility; do documentation build --shallow --format=md --markdown-toc=false lib/$m.js >docs/api-$m.md; done"
},
@@ -87,15 +93,16 @@
"vips"
],
"dependencies": {
"color": "^3.0.0",
"bindings": "^1.3.1",
"color": "^3.1.0",
"detect-libc": "^1.0.3",
"nan": "^2.11.1",
"fs-copy-file-sync": "^1.1.1",
"nan": "^2.11.1",
"npmlog": "^4.1.2",
"prebuild-install": "^5.2.0",
"semver": "^5.5.1",
"prebuild-install": "^5.2.2",
"semver": "^5.6.0",
"simple-get": "^3.0.3",
"tar": "^4.4.6",
"tar": "^4.4.8",
"tunnel-agent": "^0.6.0"
},
"devDependencies": {
@@ -105,13 +112,14 @@
"documentation": "^8.1.2",
"exif-reader": "^1.0.2",
"icc": "^1.0.0",
"license-checker": "^24.0.1",
"mocha": "^5.2.0",
"mock-fs": "^4.7.0",
"nyc": "^13.1.0",
"prebuild": "^8.1.0",
"prebuild-ci": "^2.2.3",
"prebuild": "^8.1.2",
"prebuild-ci": "^2.3.0",
"rimraf": "^2.6.2",
"semistandard": "^12.0.1"
"semistandard": "^13.0.1"
},
"license": "Apache-2.0",
"config": {

View File

@@ -278,6 +278,25 @@ namespace sharp {
return image.conv(kernel);
}
/*
* Recomb with a Matrix of the given bands/channel size.
* Eg. RGB will be a 3x3 matrix.
*/
VImage Recomb(VImage image, std::unique_ptr<double[]> const &matrix) {
double *m = matrix.get();
return image
.colourspace(VIPS_INTERPRETATION_sRGB)
.recomb(image.bands() == 3
? VImage::new_from_memory(
m, 9 * sizeof(double), 3, 3, 1, VIPS_FORMAT_DOUBLE
)
: VImage::new_matrixv(4, 4,
m[0], m[1], m[2], 0.0,
m[3], m[4], m[5], 0.0,
m[6], m[7], m[8], 0.0,
0.0, 0.0, 0.0, 1.0));
}
/*
* Sharpen flat and jagged areas. Use sigma of -1.0 for fast sharpen.
*/

View File

@@ -107,6 +107,12 @@ namespace sharp {
*/
VImage Linear(VImage image, double const a, double const b);
/*
* Recomb with a Matrix of the given bands/channel size.
* Eg. RGB will be a 3x3 matrix.
*/
VImage Recomb(VImage image, std::unique_ptr<double[]> const &matrix);
} // namespace sharp
#endif // SRC_OPERATIONS_H_

View File

@@ -381,7 +381,7 @@ class PipelineWorker : public Nan::AsyncWorker {
vips_enum_from_nick(nullptr, VIPS_TYPE_KERNEL, baton->kernel.data()));
if (
kernel != VIPS_KERNEL_NEAREST && kernel != VIPS_KERNEL_CUBIC && kernel != VIPS_KERNEL_LANCZOS2 &&
kernel != VIPS_KERNEL_LANCZOS3
kernel != VIPS_KERNEL_LANCZOS3 && kernel != VIPS_KERNEL_MITCHELL
) {
throw vips::VError("Unknown kernel");
}
@@ -525,6 +525,11 @@ class PipelineWorker : public Nan::AsyncWorker {
baton->convKernel);
}
// Recomb
if (baton->recombMatrix != NULL) {
image = sharp::Recomb(image, baton->recombMatrix);
}
// Sharpen
if (shouldSharpen) {
image = sharp::Sharpen(image, baton->sharpenSigma, baton->sharpenFlat, baton->sharpenJagged);
@@ -612,8 +617,8 @@ class PipelineWorker : public Nan::AsyncWorker {
baton->premultiplied = shouldPremultiplyAlpha;
// Gamma decoding (brighten)
if (baton->gamma >= 1 && baton->gamma <= 3) {
image = sharp::Gamma(image, baton->gamma);
if (baton->gammaOut >= 1 && baton->gammaOut <= 3) {
image = sharp::Gamma(image, baton->gammaOut);
}
// Linear adjustment (a * in + b)
@@ -758,6 +763,10 @@ class PipelineWorker : public Nan::AsyncWorker {
->set("squash", baton->tiffSquash)
->set("compression", baton->tiffCompression)
->set("predictor", baton->tiffPredictor)
->set("pyramid", baton->tiffPyramid)
->set("tile", baton->tiffTile)
->set("tile_height", baton->tiffTileHeight)
->set("tile_width", baton->tiffTileWidth)
->set("xres", baton->tiffXres)
->set("yres", baton->tiffYres)));
baton->bufferOut = static_cast<char*>(area->data);
@@ -771,6 +780,7 @@ class PipelineWorker : public Nan::AsyncWorker {
if (baton->greyscale || image.interpretation() == VIPS_INTERPRETATION_B_W) {
// Extract first band for greyscale image
image = image[0];
baton->channels = 1;
}
if (image.format() != VIPS_FORMAT_UCHAR) {
// Cast pixels to uint8 (unsigned char)
@@ -856,6 +866,10 @@ class PipelineWorker : public Nan::AsyncWorker {
->set("squash", baton->tiffSquash)
->set("compression", baton->tiffCompression)
->set("predictor", baton->tiffPredictor)
->set("pyramid", baton->tiffPyramid)
->set("tile", baton->tiffTile)
->set("tile_height", baton->tiffTileHeight)
->set("tile_width", baton->tiffTileWidth)
->set("xres", baton->tiffXres)
->set("yres", baton->tiffYres));
baton->formatOut = "tiff";
@@ -1193,6 +1207,7 @@ NAN_METHOD(pipeline) {
baton->thresholdGrayscale = AttrTo<bool>(options, "thresholdGrayscale");
baton->trimThreshold = AttrTo<double>(options, "trimThreshold");
baton->gamma = AttrTo<double>(options, "gamma");
baton->gammaOut = AttrTo<double>(options, "gammaOut");
baton->linearA = AttrTo<double>(options, "linearA");
baton->linearB = AttrTo<double>(options, "linearB");
baton->greyscale = AttrTo<bool>(options, "greyscale");
@@ -1232,6 +1247,13 @@ NAN_METHOD(pipeline) {
baton->convKernel[i] = AttrTo<double>(kdata, i);
}
}
if (HasAttr(options, "recombMatrix")) {
baton->recombMatrix = std::unique_ptr<double[]>(new double[9]);
v8::Local<v8::Array> recombMatrix = AttrAs<v8::Array>(options, "recombMatrix");
for (unsigned int i = 0; i < 9; i++) {
baton->recombMatrix[i] = AttrTo<double>(recombMatrix, i);
}
}
baton->colourspace = sharp::GetInterpretation(AttrAsStr(options, "colourspace"));
if (baton->colourspace == VIPS_INTERPRETATION_ERROR) {
baton->colourspace = VIPS_INTERPRETATION_sRGB;
@@ -1258,7 +1280,11 @@ NAN_METHOD(pipeline) {
baton->webpLossless = AttrTo<bool>(options, "webpLossless");
baton->webpNearLossless = AttrTo<bool>(options, "webpNearLossless");
baton->tiffQuality = AttrTo<uint32_t>(options, "tiffQuality");
baton->tiffPyramid = AttrTo<bool>(options, "tiffPyramid");
baton->tiffSquash = AttrTo<bool>(options, "tiffSquash");
baton->tiffTile = AttrTo<bool>(options, "tiffTile");
baton->tiffTileWidth = AttrTo<uint32_t>(options, "tiffTileWidth");
baton->tiffTileHeight = AttrTo<uint32_t>(options, "tiffTileHeight");
baton->tiffXres = AttrTo<double>(options, "tiffXres");
baton->tiffYres = AttrTo<double>(options, "tiffYres");
// tiff compression options

View File

@@ -87,6 +87,7 @@ struct PipelineBaton {
double linearA;
double linearB;
double gamma;
double gammaOut;
bool greyscale;
bool normalise;
bool useExifOrientation;
@@ -121,7 +122,11 @@ struct PipelineBaton {
int tiffQuality;
VipsForeignTiffCompression tiffCompression;
VipsForeignTiffPredictor tiffPredictor;
bool tiffPyramid;
bool tiffSquash;
bool tiffTile;
int tiffTileHeight;
int tiffTileWidth;
double tiffXres;
double tiffYres;
std::string err;
@@ -145,6 +150,7 @@ struct PipelineBaton {
std::string tileFormat;
int tileAngle;
VipsForeignDzDepth tileDepth;
std::unique_ptr<double[]> recombMatrix;
PipelineBaton():
input(nullptr),
@@ -213,7 +219,11 @@ struct PipelineBaton {
tiffQuality(80),
tiffCompression(VIPS_FOREIGN_TIFF_COMPRESSION_JPEG),
tiffPredictor(VIPS_FOREIGN_TIFF_PREDICTOR_HORIZONTAL),
tiffPyramid(false),
tiffSquash(false),
tiffTile(false),
tiffTileHeight(256),
tiffTileWidth(256),
tiffXres(1.0),
tiffYres(1.0),
withMetadata(false),

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -22,7 +22,7 @@ const median = function (values) {
// List of files
fs.readdirSync(userDataDir).forEach(function (file) {
// Contents of file
const lines = fs.readFileSync(path.join(userDataDir, file), {encoding: 'utf-8'}).split(/\r\n/);
const lines = fs.readFileSync(path.join(userDataDir, file), { encoding: 'utf-8' }).split(/\r\n/);
// First line = number of entries
const entries = parseInt(lines[0], 10);
// Verify number of entries

View File

@@ -8,7 +8,7 @@ describe('Deprecated background', function () {
it('Flatten to RGB orange', function (done) {
sharp(fixtures.inputPngWithTransparency)
.flatten()
.background({r: 255, g: 102, b: 0})
.background({ r: 255, g: 102, b: 0 })
.resize(400, 300)
.toBuffer(function (err, data, info) {
if (err) throw err;
@@ -35,7 +35,7 @@ describe('Deprecated background', function () {
const output = fixtures.path('output.flatten-rgb16-orange.jpg');
sharp(fixtures.inputPngWithTransparency16bit)
.flatten()
.background({r: 255, g: 102, b: 0})
.background({ r: 255, g: 102, b: 0 })
.toFile(output, function (err, info) {
if (err) throw err;
assert.strictEqual(true, info.size > 0);
@@ -61,7 +61,7 @@ describe('Deprecated background', function () {
it('extend all sides equally with RGB', function (done) {
sharp(fixtures.inputJpg)
.resize(120)
.background({r: 255, g: 0, b: 0})
.background({ r: 255, g: 0, b: 0 })
.extend(10)
.toBuffer(function (err, data, info) {
if (err) throw err;

View File

@@ -38,7 +38,7 @@ describe('Deprecated embed', function () {
it('JPEG within WebP, to include alpha channel', function (done) {
sharp(fixtures.inputJpg)
.resize(320, 240)
.background({r: 0, g: 0, b: 0, alpha: 0})
.background({ r: 0, g: 0, b: 0, alpha: 0 })
.embed()
.webp()
.toBuffer(function (err, data, info) {
@@ -86,7 +86,7 @@ describe('Deprecated embed', function () {
sharp(fixtures.inputPngWithTransparency16bit)
.resize(32, 16)
.embed()
.background({r: 0, g: 0, b: 0, alpha: 0})
.background({ r: 0, g: 0, b: 0, alpha: 0 })
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(true, data.length > 0);
@@ -102,7 +102,7 @@ describe('Deprecated embed', function () {
sharp(fixtures.inputPngWithGreyAlpha)
.resize(32, 16)
.embed()
.background({r: 0, g: 0, b: 0, alpha: 0})
.background({ r: 0, g: 0, b: 0, alpha: 0 })
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(true, data.length > 0);
@@ -153,7 +153,7 @@ describe('Deprecated embed', function () {
it('Embed gravity horizontal northwest', function (done) {
sharp(fixtures.inputPngEmbed)
.resize(200, 100)
.background({r: 0, g: 0, b: 0, alpha: 0})
.background({ r: 0, g: 0, b: 0, alpha: 0 })
.embed(sharp.gravity.northwest)
.toBuffer(function (err, data, info) {
if (err) throw err;
@@ -169,7 +169,7 @@ describe('Deprecated embed', function () {
it('Embed gravity horizontal north', function (done) {
sharp(fixtures.inputPngEmbed)
.resize(200, 100)
.background({r: 0, g: 0, b: 0, alpha: 0})
.background({ r: 0, g: 0, b: 0, alpha: 0 })
.embed(sharp.gravity.north)
.toBuffer(function (err, data, info) {
if (err) throw err;
@@ -185,7 +185,7 @@ describe('Deprecated embed', function () {
it('Embed gravity horizontal northeast', function (done) {
sharp(fixtures.inputPngEmbed)
.resize(200, 100)
.background({r: 0, g: 0, b: 0, alpha: 0})
.background({ r: 0, g: 0, b: 0, alpha: 0 })
.embed(sharp.gravity.northeast)
.toBuffer(function (err, data, info) {
if (err) throw err;
@@ -201,7 +201,7 @@ describe('Deprecated embed', function () {
it('Embed gravity horizontal east', function (done) {
sharp(fixtures.inputPngEmbed)
.resize(200, 100)
.background({r: 0, g: 0, b: 0, alpha: 0})
.background({ r: 0, g: 0, b: 0, alpha: 0 })
.embed(sharp.gravity.east)
.toBuffer(function (err, data, info) {
if (err) throw err;
@@ -217,7 +217,7 @@ describe('Deprecated embed', function () {
it('Embed gravity horizontal southeast', function (done) {
sharp(fixtures.inputPngEmbed)
.resize(200, 100)
.background({r: 0, g: 0, b: 0, alpha: 0})
.background({ r: 0, g: 0, b: 0, alpha: 0 })
.embed(sharp.gravity.southeast)
.toBuffer(function (err, data, info) {
if (err) throw err;
@@ -233,7 +233,7 @@ describe('Deprecated embed', function () {
it('Embed gravity horizontal south', function (done) {
sharp(fixtures.inputPngEmbed)
.resize(200, 100)
.background({r: 0, g: 0, b: 0, alpha: 0})
.background({ r: 0, g: 0, b: 0, alpha: 0 })
.embed(sharp.gravity.south)
.toBuffer(function (err, data, info) {
if (err) throw err;
@@ -249,7 +249,7 @@ describe('Deprecated embed', function () {
it('Embed gravity horizontal southwest', function (done) {
sharp(fixtures.inputPngEmbed)
.resize(200, 100)
.background({r: 0, g: 0, b: 0, alpha: 0})
.background({ r: 0, g: 0, b: 0, alpha: 0 })
.embed(sharp.gravity.southwest)
.toBuffer(function (err, data, info) {
if (err) throw err;
@@ -265,7 +265,7 @@ describe('Deprecated embed', function () {
it('Embed gravity horizontal west', function (done) {
sharp(fixtures.inputPngEmbed)
.resize(200, 100)
.background({r: 0, g: 0, b: 0, alpha: 0})
.background({ r: 0, g: 0, b: 0, alpha: 0 })
.embed(sharp.gravity.west)
.toBuffer(function (err, data, info) {
if (err) throw err;
@@ -281,7 +281,7 @@ describe('Deprecated embed', function () {
it('Embed gravity horizontal center', function (done) {
sharp(fixtures.inputPngEmbed)
.resize(200, 100)
.background({r: 0, g: 0, b: 0, alpha: 0})
.background({ r: 0, g: 0, b: 0, alpha: 0 })
.embed(sharp.gravity.center)
.toBuffer(function (err, data, info) {
if (err) throw err;
@@ -297,7 +297,7 @@ describe('Deprecated embed', function () {
it('Embed gravity vertical northwest', function (done) {
sharp(fixtures.inputPngEmbed)
.resize(200, 200)
.background({r: 0, g: 0, b: 0, alpha: 0})
.background({ r: 0, g: 0, b: 0, alpha: 0 })
.embed(sharp.gravity.northwest)
.toBuffer(function (err, data, info) {
if (err) throw err;
@@ -313,7 +313,7 @@ describe('Deprecated embed', function () {
it('Embed gravity vertical north', function (done) {
sharp(fixtures.inputPngEmbed)
.resize(200, 200)
.background({r: 0, g: 0, b: 0, alpha: 0})
.background({ r: 0, g: 0, b: 0, alpha: 0 })
.embed(sharp.gravity.north)
.toBuffer(function (err, data, info) {
if (err) throw err;
@@ -329,7 +329,7 @@ describe('Deprecated embed', function () {
it('Embed gravity vertical northeast', function (done) {
sharp(fixtures.inputPngEmbed)
.resize(200, 200)
.background({r: 0, g: 0, b: 0, alpha: 0})
.background({ r: 0, g: 0, b: 0, alpha: 0 })
.embed(sharp.gravity.northeast)
.toBuffer(function (err, data, info) {
if (err) throw err;
@@ -345,7 +345,7 @@ describe('Deprecated embed', function () {
it('Embed gravity vertical east', function (done) {
sharp(fixtures.inputPngEmbed)
.resize(200, 200)
.background({r: 0, g: 0, b: 0, alpha: 0})
.background({ r: 0, g: 0, b: 0, alpha: 0 })
.embed(sharp.gravity.east)
.toBuffer(function (err, data, info) {
if (err) throw err;
@@ -361,7 +361,7 @@ describe('Deprecated embed', function () {
it('Embed gravity vertical southeast', function (done) {
sharp(fixtures.inputPngEmbed)
.resize(200, 200)
.background({r: 0, g: 0, b: 0, alpha: 0})
.background({ r: 0, g: 0, b: 0, alpha: 0 })
.embed(sharp.gravity.southeast)
.toBuffer(function (err, data, info) {
if (err) throw err;
@@ -377,7 +377,7 @@ describe('Deprecated embed', function () {
it('Embed gravity vertical south', function (done) {
sharp(fixtures.inputPngEmbed)
.resize(200, 200)
.background({r: 0, g: 0, b: 0, alpha: 0})
.background({ r: 0, g: 0, b: 0, alpha: 0 })
.embed(sharp.gravity.south)
.toBuffer(function (err, data, info) {
if (err) throw err;
@@ -393,7 +393,7 @@ describe('Deprecated embed', function () {
it('Embed gravity vertical southwest', function (done) {
sharp(fixtures.inputPngEmbed)
.resize(200, 200)
.background({r: 0, g: 0, b: 0, alpha: 0})
.background({ r: 0, g: 0, b: 0, alpha: 0 })
.embed(sharp.gravity.southwest)
.toBuffer(function (err, data, info) {
if (err) throw err;
@@ -409,7 +409,7 @@ describe('Deprecated embed', function () {
it('Embed gravity vertical west', function (done) {
sharp(fixtures.inputPngEmbed)
.resize(200, 200)
.background({r: 0, g: 0, b: 0, alpha: 0})
.background({ r: 0, g: 0, b: 0, alpha: 0 })
.embed(sharp.gravity.west)
.toBuffer(function (err, data, info) {
if (err) throw err;
@@ -425,7 +425,7 @@ describe('Deprecated embed', function () {
it('Embed gravity vertical center', function (done) {
sharp(fixtures.inputPngEmbed)
.resize(200, 200)
.background({r: 0, g: 0, b: 0, alpha: 0})
.background({ r: 0, g: 0, b: 0, alpha: 0 })
.embed(sharp.gravity.center)
.toBuffer(function (err, data, info) {
if (err) throw err;

View File

@@ -54,7 +54,7 @@ describe('Extend', function () {
});
it('partial object fails', function () {
assert.throws(function () {
sharp().extend({top: 1});
sharp().extend({ top: 1 });
});
});

View File

@@ -49,8 +49,8 @@ describe('failOnError', function () {
it('returns errors to callback for truncated JPEG when failOnError is set', function (done) {
sharp(fixtures.inputJpgTruncated, { failOnError: true }).toBuffer(function (err, data, info) {
assert.ok(err.message.includes('VipsJpeg: Premature end of JPEG file'), err);
assert.equal(data, null);
assert.equal(info, null);
assert.strictEqual(data, null);
assert.strictEqual(info, null);
done();
});
});
@@ -58,8 +58,8 @@ describe('failOnError', function () {
it('returns errors to callback for truncated PNG when failOnError is set', function (done) {
sharp(fixtures.inputPngTruncated, { failOnError: true }).toBuffer(function (err, data, info) {
assert.ok(err.message.includes('vipspng: libpng read error'), err);
assert.equal(data, null);
assert.equal(info, null);
assert.strictEqual(data, null);
assert.strictEqual(info, null);
done();
});
});

View File

@@ -44,6 +44,19 @@ describe('Gamma correction', function () {
});
});
it('input value of 2.2, output value of 3.0', function (done) {
sharp(fixtures.inputJpgWithGammaHoliness)
.resize(129, 111)
.gamma(2.2, 3.0)
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('jpeg', info.format);
assert.strictEqual(129, info.width);
assert.strictEqual(111, info.height);
fixtures.assertSimilar(fixtures.expected('gamma-in-2.2-out-3.0.jpg'), data, { threshold: 6 }, done);
});
});
it('alpha transparency', function (done) {
sharp(fixtures.inputPngOverlayLayer1)
.resize(320)
@@ -57,9 +70,15 @@ describe('Gamma correction', function () {
});
});
it('invalid value', function () {
it('invalid first parameter value', function () {
assert.throws(function () {
sharp(fixtures.inputJpgWithGammaHoliness).gamma(4);
});
});
it('invalid second parameter value', function () {
assert.throws(function () {
sharp(fixtures.inputJpgWithGammaHoliness).gamma(2.2, 4);
});
});
});

View File

@@ -79,7 +79,7 @@ describe('Input/output', function () {
const pipeline = sharp().resize(1, 1);
fs.createReadStream(fixtures.inputJpg).pipe(pipeline);
return pipeline
.toBuffer({resolveWithObject: false})
.toBuffer({ resolveWithObject: false })
.then(function (data) {
assert.strictEqual(true, data instanceof Buffer);
assert.strictEqual(true, data.length > 0);
@@ -90,7 +90,7 @@ describe('Input/output', function () {
const pipeline = sharp().resize(1, 1);
fs.createReadStream(fixtures.inputJpg).pipe(pipeline);
return pipeline
.toBuffer({resolveWithObject: true})
.toBuffer({ resolveWithObject: true })
.then(function (object) {
assert.strictEqual('object', typeof object);
assert.strictEqual('object', typeof object.info);
@@ -106,7 +106,7 @@ describe('Input/output', function () {
it('Read from File and write to Buffer via Promise resolved with Buffer', function () {
return sharp(fixtures.inputJpg)
.resize(1, 1)
.toBuffer({resolveWithObject: false})
.toBuffer({ resolveWithObject: false })
.then(function (data) {
assert.strictEqual(true, data instanceof Buffer);
assert.strictEqual(true, data.length > 0);
@@ -116,7 +116,7 @@ describe('Input/output', function () {
it('Read from File and write to Buffer via Promise resolved with Object', function () {
return sharp(fixtures.inputJpg)
.resize(1, 1)
.toBuffer({resolveWithObject: true})
.toBuffer({ resolveWithObject: true })
.then(function (object) {
assert.strictEqual('object', typeof object);
assert.strictEqual('object', typeof object.info);
@@ -462,7 +462,7 @@ describe('Input/output', function () {
it('should work for webp alpha quality', function (done) {
sharp(fixtures.inputPngAlphaPremultiplicationSmall)
.webp({alphaQuality: 80})
.webp({ alphaQuality: 80 })
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(true, data.length > 0);
@@ -473,7 +473,7 @@ describe('Input/output', function () {
it('should work for webp lossless', function (done) {
sharp(fixtures.inputPngAlphaPremultiplicationSmall)
.webp({lossless: true})
.webp({ lossless: true })
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(true, data.length > 0);
@@ -484,7 +484,7 @@ describe('Input/output', function () {
it('should work for webp near-lossless', function (done) {
sharp(fixtures.inputPngAlphaPremultiplicationSmall)
.webp({nearLossless: true, quality: 50})
.webp({ nearLossless: true, quality: 50 })
.toBuffer(function (err50, data50, info50) {
if (err50) throw err50;
assert.strictEqual(true, data50.length > 0);
@@ -495,7 +495,7 @@ describe('Input/output', function () {
it('should use near-lossless when both lossless and nearLossless are specified', function (done) {
sharp(fixtures.inputPngAlphaPremultiplicationSmall)
.webp({nearLossless: true, quality: 50, lossless: true})
.webp({ nearLossless: true, quality: 50, lossless: true })
.toBuffer(function (err50, data50, info50) {
if (err50) throw err50;
assert.strictEqual(true, data50.length > 0);
@@ -817,7 +817,7 @@ describe('Input/output', function () {
assert.strictEqual(320, withInfo.width);
assert.strictEqual(240, withInfo.height);
// Verify image is of a different size (progressive output even without mozjpeg)
assert.notEqual(withData.length, withoutData.length);
assert.notStrictEqual(withData.length, withoutData.length);
done();
});
});
@@ -887,7 +887,7 @@ describe('Input/output', function () {
it('Convert SVG to PNG at default 72DPI', function (done) {
sharp(fixtures.inputSvg)
.resize(1024)
.extract({left: 290, top: 760, width: 40, height: 40})
.extract({ left: 290, top: 760, width: 40, height: 40 })
.toFormat('png')
.toBuffer(function (err, data, info) {
if (err) throw err;
@@ -908,7 +908,7 @@ describe('Input/output', function () {
it('Convert SVG to PNG at 1200DPI', function (done) {
sharp(fixtures.inputSvg, { density: 1200 })
.resize(1024)
.extract({left: 290, top: 760, width: 40, height: 40})
.extract({ left: 290, top: 760, width: 40, height: 40 })
.toFormat('png')
.toBuffer(function (err, data, info) {
if (err) throw err;
@@ -1285,6 +1285,84 @@ describe('Input/output', function () {
});
});
it('TIFF tiled pyramid image without compression enlarges test file', function (done) {
const startSize = fs.statSync(fixtures.inputTiffUncompressed).size;
sharp(fixtures.inputTiffUncompressed)
.tiff({
compression: 'none',
pyramid: true,
tile: true,
tileHeight: 256,
tileWidth: 256
})
.toFile(fixtures.outputTiff, (err, info) => {
if (err) throw err;
assert.strictEqual('tiff', info.format);
assert(info.size > startSize);
rimraf(fixtures.outputTiff, done);
});
});
it('TIFF pyramid true value does not throw error', function () {
assert.doesNotThrow(function () {
sharp().tiff({ pyramid: true });
});
});
it('Invalid TIFF pyramid value throws error', function () {
assert.throws(function () {
sharp().tiff({ pyramid: 'true' });
});
});
it('Invalid TIFF tile value throws error', function () {
assert.throws(function () {
sharp().tiff({ tile: 'true' });
});
});
it('TIFF tile true value does not throw error', function () {
assert.doesNotThrow(function () {
sharp().tiff({ tile: true });
});
});
it('Valid TIFF tileHeight value does not throw error', function () {
assert.doesNotThrow(function () {
sharp().tiff({ tileHeight: 512 });
});
});
it('Valid TIFF tileWidth value does not throw error', function () {
assert.doesNotThrow(function () {
sharp().tiff({ tileWidth: 512 });
});
});
it('Invalid TIFF tileHeight value throws error', function () {
assert.throws(function () {
sharp().tiff({ tileHeight: '256' });
});
});
it('Invalid TIFF tileWidth value throws error', function () {
assert.throws(function () {
sharp().tiff({ tileWidth: '256' });
});
});
it('Invalid TIFF tileHeight value throws error', function () {
assert.throws(function () {
sharp().tiff({ tileHeight: 0 });
});
});
it('Invalid TIFF tileWidth value throws error', function () {
assert.throws(function () {
sharp().tiff({ tileWidth: 0 });
});
});
it('Input and output formats match when not forcing', function (done) {
sharp(fixtures.inputJpg)
.resize(320, 240)
@@ -1364,7 +1442,7 @@ describe('Input/output', function () {
it('Save Vips V file', function (done) {
sharp(fixtures.inputJpg)
.extract({left: 910, top: 1105, width: 70, height: 60})
.extract({ left: 910, top: 1105, width: 70, height: 60 })
.toFile(fixtures.outputV, function (err, info) {
if (err) throw err;
assert.strictEqual(true, info.size > 0);
@@ -1388,6 +1466,7 @@ describe('Input/output', function () {
assert.strictEqual('raw', info.format);
assert.strictEqual(32, info.width);
assert.strictEqual(24, info.height);
assert.strictEqual(1, info.channels);
done();
});
});
@@ -1554,7 +1633,7 @@ describe('Input/output', function () {
width: info.width,
height: info.height,
channels: info.channels
}})
} })
.jpeg()
.toBuffer(function (err, data, info) {
if (err) throw err;
@@ -1581,7 +1660,7 @@ describe('Input/output', function () {
width: info.width,
height: info.height,
channels: info.channels
}})
} })
.png()
.toBuffer(function (err, data, info) {
if (err) throw err;
@@ -1683,7 +1762,7 @@ describe('Input/output', function () {
assert.strictEqual(472, info.height);
assert.strictEqual(3, info.channels);
});
const badPipeline = sharp(null, {raw: {width: 840, height: 500, channels: 3}})
const badPipeline = sharp(null, { raw: { width: 840, height: 500, channels: 3 } })
.toFormat('jpeg')
.toBuffer(function (err, data, info) {
assert.strictEqual(err.message.indexOf('memory area too small') > 0, true);
@@ -1691,7 +1770,7 @@ describe('Input/output', function () {
const inPipeline = sharp()
.resize(840, 472)
.raw();
const goodPipeline = sharp(null, {raw: {width: 840, height: 472, channels: 3}})
const goodPipeline = sharp(null, { raw: { width: 840, height: 472, channels: 3 } })
.toFormat('jpeg')
.toBuffer(function (err, data, info) {
if (err) throw err;

View File

@@ -138,7 +138,7 @@ describe('Image channel insertion', function () {
it('Invalid raw buffer description', function () {
assert.throws(function () {
sharp().joinChannel(fs.readFileSync(fixtures.inputPng), {raw: {}});
sharp().joinChannel(fs.readFileSync(fixtures.inputPng), { raw: {} });
});
});

View File

@@ -449,12 +449,12 @@ describe('Image metadata', function () {
describe('Invalid withMetadata parameters', function () {
it('String orientation', function () {
assert.throws(function () {
sharp().withMetadata({orientation: 'zoinks'});
sharp().withMetadata({ orientation: 'zoinks' });
});
});
it('Negative orientation', function () {
assert.throws(function () {
sharp().withMetadata({orientation: -1});
sharp().withMetadata({ orientation: -1 });
});
});
it('Zero orientation', function () {
@@ -464,7 +464,7 @@ describe('Image metadata', function () {
});
it('Too large orientation', function () {
assert.throws(function () {
sharp().withMetadata({orientation: 9});
sharp().withMetadata({ orientation: 9 });
});
});
});

135
test/unit/recomb.js Normal file
View File

@@ -0,0 +1,135 @@
'use strict';
const assert = require('assert');
const sharp = require('../../');
const fixtures = require('../fixtures');
describe('Recomb', function () {
it('applies a sepia filter using recomb', function (done) {
const output = fixtures.path('output.recomb-sepia.jpg');
sharp(fixtures.inputJpgWithLandscapeExif1)
.recomb([
[0.3588, 0.7044, 0.1368],
[0.299, 0.587, 0.114],
[0.2392, 0.4696, 0.0912]
])
.toFile(output, function (err, info) {
if (err) throw err;
assert.strictEqual('jpeg', info.format);
assert.strictEqual(600, info.width);
assert.strictEqual(450, info.height);
fixtures.assertMaxColourDistance(
output,
fixtures.expected('Landscape_1-recomb-sepia.jpg'),
17
);
done();
});
});
it('applies a sepia filter using recomb to an PNG with Alpha', function (done) {
const output = fixtures.path('output.recomb-sepia.png');
sharp(fixtures.inputPngAlphaPremultiplicationSmall)
.recomb([
[0.3588, 0.7044, 0.1368],
[0.299, 0.587, 0.114],
[0.2392, 0.4696, 0.0912]
])
.toFile(output, function (err, info) {
if (err) throw err;
assert.strictEqual('png', info.format);
assert.strictEqual(1024, info.width);
assert.strictEqual(768, info.height);
fixtures.assertMaxColourDistance(
output,
fixtures.expected('alpha-recomb-sepia.png'),
17
);
done();
});
});
it('applies a different sepia filter using recomb', function (done) {
const output = fixtures.path('output.recomb-sepia2.jpg');
sharp(fixtures.inputJpgWithLandscapeExif1)
.recomb([
[0.393, 0.769, 0.189],
[0.349, 0.686, 0.168],
[0.272, 0.534, 0.131]
])
.toFile(output, function (err, info) {
if (err) throw err;
assert.strictEqual('jpeg', info.format);
assert.strictEqual(600, info.width);
assert.strictEqual(450, info.height);
fixtures.assertMaxColourDistance(
output,
fixtures.expected('Landscape_1-recomb-sepia2.jpg'),
17
);
done();
});
});
it('increases the saturation of the image', function (done) {
const saturationLevel = 1;
const output = fixtures.path('output.recomb-saturation.jpg');
sharp(fixtures.inputJpgWithLandscapeExif1)
.recomb([
[
saturationLevel + 1 - 0.2989,
-0.587 * saturationLevel,
-0.114 * saturationLevel
],
[
-0.2989 * saturationLevel,
saturationLevel + 1 - 0.587,
-0.114 * saturationLevel
],
[
-0.2989 * saturationLevel,
-0.587 * saturationLevel,
saturationLevel + 1 - 0.114
]
])
.toFile(output, function (err, info) {
if (err) throw err;
assert.strictEqual('jpeg', info.format);
assert.strictEqual(600, info.width);
assert.strictEqual(450, info.height);
fixtures.assertMaxColourDistance(
output,
fixtures.expected('Landscape_1-recomb-saturation.jpg'),
37
);
done();
});
});
describe('invalid matrix specification', function () {
it('missing', function () {
assert.throws(function () {
sharp(fixtures.inputJpg).recomb();
});
});
it('incorrect flat data', function () {
assert.throws(function () {
sharp(fixtures.inputJpg).recomb([1, 2, 3, 4, 5, 6, 7, 8, 9]);
});
});
it('incorrect sub size', function () {
assert.throws(function () {
sharp(fixtures.inputJpg).recomb([
[1, 2, 3, 4],
[5, 6, 7, 8],
[1, 2, 9, 6]
]);
});
});
it('incorrect top size', function () {
assert.throws(function () {
sharp(fixtures.inputJpg).recomb([[1, 2, 3, 4], [5, 6, 7, 8]]);
});
});
});
});

View File

@@ -497,6 +497,7 @@ describe('Resize dimensions', function () {
[
sharp.kernel.nearest,
sharp.kernel.cubic,
sharp.kernel.mitchell,
sharp.kernel.lanczos2,
sharp.kernel.lanczos3
].forEach(function (kernel) {

View File

@@ -25,7 +25,7 @@ describe('Rotation', function () {
it('Rotate by 30 degrees with semi-transparent background', function (done) {
sharp(fixtures.inputJpg)
.rotate(30, {background: { r: 255, g: 0, b: 0, alpha: 0.5 }})
.rotate(30, { background: { r: 255, g: 0, b: 0, alpha: 0.5 } })
.resize(320)
.png()
.toBuffer(function (err, data, info) {
@@ -39,7 +39,7 @@ describe('Rotation', function () {
it('Rotate by 30 degrees with solid background', function (done) {
sharp(fixtures.inputJpg)
.rotate(30, {background: { r: 255, g: 0, b: 0, alpha: 0.5 }})
.rotate(30, { background: { r: 255, g: 0, b: 0, alpha: 0.5 } })
.resize(320)
.toBuffer(function (err, data, info) {
if (err) throw err;
@@ -208,7 +208,7 @@ describe('Rotation', function () {
sharp(fixtures.inputJpgWithExif)
.rotate()
.resize(320)
.withMetadata({orientation: 3})
.withMetadata({ orientation: 3 })
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('jpeg', info.format);

View File

@@ -132,7 +132,7 @@ describe('Threshold', function () {
it('color threshold', function (done) {
sharp(fixtures.inputJpg)
.resize(320, 240)
.threshold(128, {'grayscale': false})
.threshold(128, { grayscale: false })
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('jpeg', info.format);