Compare commits

...

18 Commits

Author SHA1 Message Date
Lovell Fuller
142c431745 Release v0.17.2 2017-02-11 10:35:34 +00:00
Lovell Fuller
81f5589411 Add use of 'cc' to improve C++ code style linting 2017-02-11 09:59:23 +00:00
Mark van Seventer
04f5c884a4 Add CLI tools section to installation guide (#691) 2017-01-25 21:34:23 +00:00
Lovell Fuller
d8df503404 Ensure Readable can start flowing after Writable finish #671 2017-01-22 14:03:06 +00:00
Lovell Fuller
d241efcdbe Add changelog entry and credit for #685 2017-01-22 13:58:11 +00:00
Rahul Nanwani
a1b8efe721 Expose WebP alpha quality, lossless and near-lossless output options (#685) 2017-01-19 13:45:32 +00:00
Lovell Fuller
815d076b35 Release v0.17.1 2017-01-15 15:23:49 +00:00
Lovell Fuller
86b4816b3f Allow HTTP-over-HTTPS proxy when d/l pre-compiled deps #679 2017-01-14 11:23:13 +00:00
Lovell Fuller
473055468a Docs: ensure alpha attribute is used for transparency 2017-01-13 21:24:57 +00:00
Brandon Aaron
c6a28db8b1 Packaging: bump zlib to 1.2.10 and png16 to 1.6.28 (#676) 2017-01-10 18:19:23 +00:00
子龙山人
971f567571 Docs: correct alpha attribute in extend background example (#675) 2017-01-09 10:47:02 +00:00
Lovell Fuller
7e2eca3d1e Credit recent new contributors, thank you! 2017-01-05 22:27:30 +00:00
Lovell Fuller
86b0053bf0 Removed preinstall.sh script 2017-01-05 22:21:41 +00:00
Lovell Fuller
cfc4b282f0 Doc refresh for d9b667e 2017-01-05 22:20:33 +00:00
Lovell Fuller
b85d2aa565 Merge branch 'master' of https://github.com/lovell/sharp 2017-01-05 22:17:16 +00:00
Lovell Fuller
70a3d4fb5e Improve error messages for invalid resize parameters
Dependency version bumps and doc refresh
2017-01-05 22:17:04 +00:00
Adam Coyne
d9b667e346 Docs: remove parentheses from sharp.format (#663) 2016-12-31 19:32:18 +00:00
Jérémy Lal
3a1db53d5a Simpler expression for finding vips-cpp libdir (#656)
Fixes: #655
2016-12-18 08:57:50 +00:00
42 changed files with 633 additions and 622 deletions

View File

@@ -74,7 +74,7 @@ covers reporting bugs, requesting features and submitting code changes.
### Licence ### Licence
Copyright 2013, 2014, 2015, 2016 Lovell Fuller and contributors. Copyright 2013, 2014, 2015, 2016, 2017 Lovell Fuller and contributors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@@ -107,7 +107,7 @@
['OS == "linux"', { ['OS == "linux"', {
'defines': [ 'defines': [
# Inspect libvips-cpp.so to determine which C++11 ABI version was used and set _GLIBCXX_USE_CXX11_ABI accordingly. This is quite horrible. # Inspect libvips-cpp.so to determine which C++11 ABI version was used and set _GLIBCXX_USE_CXX11_ABI accordingly. This is quite horrible.
'_GLIBCXX_USE_CXX11_ABI=<!(if readelf -Ws "$(PKG_CONFIG_PATH="<(pkg_config_path)" pkg-config --libs-only-L vips-cpp | cut -c 3- | sed -e "s/[[:space:]]*$//" | sed -e "s/^$/\/usr\/lib/")/libvips-cpp.so" | c++filt | grep -qF __cxx11;then echo "1";else echo "0";fi)' '_GLIBCXX_USE_CXX11_ABI=<!(if readelf -Ws "$(PKG_CONFIG_PATH="<(pkg_config_path)" pkg-config --variable libdir vips-cpp)/libvips-cpp.so" | c++filt | grep -qF __cxx11;then echo "1";else echo "0";fi)'
] ]
}] }]
] ]

View File

@@ -98,11 +98,11 @@ module.exports.download_vips = function () {
} catch (err) {} } catch (err) {}
}); });
}); });
const gotOpt = {}; const gotOpt = {
if (process.env.npm_config_https_proxy) { agent: caw(null, {
// Use the NPM-configured HTTPS proxy protocol: 'https'
gotOpt.agent = caw(process.env.npm_config_https_proxy); })
} };
const url = distBaseUrl + tarFilename; const url = distBaseUrl + tarFilename;
got.stream(url, gotOpt).on('response', function (response) { got.stream(url, gotOpt).on('response', function (response) {
if (response.statusCode !== 200) { if (response.statusCode !== 200) {

View File

@@ -1,6 +1,12 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. --> <!-- Generated by documentation.js. Update this documentation by updating the source code. -->
# extractChannel ### Table of Contents
- [extractChannel](#extractchannel)
- [joinChannel](#joinchannel)
- [bandbool](#bandbool)
## extractChannel
Extract a single channel from a multi-channel image. Extract a single channel from a multi-channel image.
@@ -23,7 +29,7 @@ sharp(input)
Returns **Sharp** Returns **Sharp**
# joinChannel ## joinChannel
Join one or more channels to the image. Join one or more channels to the image.
The meaning of the added channels depends on the output colourspace, set with `toColourspace()`. The meaning of the added channels depends on the output colourspace, set with `toColourspace()`.
@@ -46,7 +52,7 @@ For raw pixel input, the `options` object should contain a `raw` attribute, whic
Returns **Sharp** Returns **Sharp**
# bandbool ## bandbool
Perform a bitwise boolean operation on all input image channels (bands) to produce a single channel output image. Perform a bitwise boolean operation on all input image channels (bands) to produce a single channel output image.

View File

@@ -1,6 +1,14 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. --> <!-- Generated by documentation.js. Update this documentation by updating the source code. -->
# background ### Table of Contents
- [background](#background)
- [greyscale](#greyscale)
- [grayscale](#grayscale)
- [toColourspace](#tocolourspace)
- [toColorspace](#tocolorspace)
## background
Set the background for the `embed`, `flatten` and `extend` operations. Set the background for the `embed`, `flatten` and `extend` operations.
The default background is `{r: 0, g: 0, b: 0, alpha: 1}`, black without transparency. The default background is `{r: 0, g: 0, b: 0, alpha: 1}`, black without transparency.
@@ -18,7 +26,7 @@ The alpha value is a float between `0` (transparent) and `1` (opaque).
Returns **Sharp** Returns **Sharp**
# greyscale ## greyscale
Convert to 8-bit greyscale; 256 shades of grey. Convert to 8-bit greyscale; 256 shades of grey.
This is a linear operation. If the input image is in a non-linear colour space such as sRGB, use `gamma()` with `greyscale()` for the best results. This is a linear operation. If the input image is in a non-linear colour space such as sRGB, use `gamma()` with `greyscale()` for the best results.
@@ -33,7 +41,7 @@ An alpha channel may be present, and will be unchanged by the operation.
Returns **Sharp** Returns **Sharp**
# grayscale ## grayscale
Alternative spelling of `greyscale`. Alternative spelling of `greyscale`.
@@ -43,7 +51,7 @@ Alternative spelling of `greyscale`.
Returns **Sharp** Returns **Sharp**
# toColourspace ## toColourspace
Set the output colourspace. Set the output colourspace.
By default output image will be web-friendly sRGB, with additional channels interpreted as alpha channels. By default output image will be web-friendly sRGB, with additional channels interpreted as alpha channels.
@@ -57,7 +65,7 @@ By default output image will be web-friendly sRGB, with additional channels inte
Returns **Sharp** Returns **Sharp**
# toColorspace ## toColorspace
Alternative spelling of `toColourspace`. Alternative spelling of `toColourspace`.

View File

@@ -1,6 +1,10 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. --> <!-- Generated by documentation.js. Update this documentation by updating the source code. -->
# overlayWith ### Table of Contents
- [overlayWith](#overlaywith)
## overlayWith
Overlay (composite) an image over the processed (resized, extracted etc.) image. Overlay (composite) an image over the processed (resized, extracted etc.) image.

View File

@@ -1,6 +1,13 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. --> <!-- Generated by documentation.js. Update this documentation by updating the source code. -->
# Sharp ### Table of Contents
- [Sharp](#sharp)
- [format](#format)
- [versions](#versions)
- [queue](#queue)
## Sharp
**Parameters** **Parameters**
@@ -43,7 +50,7 @@ readableStream.pipe(transformer).pipe(writableStream);
Returns **[Sharp](#sharp)** Returns **[Sharp](#sharp)**
## format ### format
An Object containing nested boolean values representing the available input and output formats/methods. An Object containing nested boolean values representing the available input and output formats/methods.
@@ -55,7 +62,7 @@ console.log(sharp.format());
Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)**
## versions ### versions
An Object containing the version numbers of libvips and its dependencies. An Object containing the version numbers of libvips and its dependencies.
@@ -65,7 +72,7 @@ An Object containing the version numbers of libvips and its dependencies.
console.log(sharp.versions); console.log(sharp.versions);
``` ```
# queue ## queue
An EventEmitter that emits a `change` event when a task is either: An EventEmitter that emits a `change` event when a task is either:

View File

@@ -1,6 +1,13 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. --> <!-- Generated by documentation.js. Update this documentation by updating the source code. -->
# clone ### Table of Contents
- [clone](#clone)
- [metadata](#metadata)
- [limitInputPixels](#limitinputpixels)
- [sequentialRead](#sequentialread)
## clone
Take a "snapshot" of the Sharp instance, returning a new instance. Take a "snapshot" of the Sharp instance, returning a new instance.
Cloned instances inherit the input of their parent instance. Cloned instances inherit the input of their parent instance.
@@ -19,7 +26,7 @@ readableStream.pipe(pipeline);
Returns **Sharp** Returns **Sharp**
# metadata ## metadata
Fast access to image metadata without decoding any compressed image data. Fast access to image metadata without decoding any compressed image data.
A Promises/A+ promise is returned when `callback` is not provided. A Promises/A+ promise is returned when `callback` is not provided.
@@ -59,7 +66,7 @@ image
Returns **([Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)&lt;[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)> | Sharp)** Returns **([Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)&lt;[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)> | Sharp)**
# limitInputPixels ## limitInputPixels
Do not process input images where the number of pixels (width _ height) exceeds this limit. Do not process input images where the number of pixels (width _ height) exceeds this limit.
Assumes image dimensions contained in the input metadata can be trusted. Assumes image dimensions contained in the input metadata can be trusted.
@@ -74,7 +81,7 @@ The default limit is 268402689 (0x3FFF _ 0x3FFF) pixels.
Returns **Sharp** Returns **Sharp**
# sequentialRead ## sequentialRead
An advanced setting that switches the libvips access method to `VIPS_ACCESS_SEQUENTIAL`. An advanced setting that switches the libvips access method to `VIPS_ACCESS_SEQUENTIAL`.
This will reduce memory usage and can improve performance on some systems. This will reduce memory usage and can improve performance on some systems.

View File

@@ -1,6 +1,25 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. --> <!-- Generated by documentation.js. Update this documentation by updating the source code. -->
# rotate ### Table of Contents
- [rotate](#rotate)
- [extract](#extract)
- [flip](#flip)
- [flop](#flop)
- [sharpen](#sharpen)
- [blur](#blur)
- [extend](#extend)
- [flatten](#flatten)
- [trim](#trim)
- [gamma](#gamma)
- [negate](#negate)
- [normalise](#normalise)
- [normalize](#normalize)
- [convolve](#convolve)
- [threshold](#threshold)
- [boolean](#boolean)
## rotate
Rotate the output image by either an explicit angle Rotate the output image by either an explicit angle
or auto-orient based on the EXIF `Orientation` tag. or auto-orient based on the EXIF `Orientation` tag.
@@ -35,7 +54,7 @@ readableStream.pipe(pipeline);
Returns **Sharp** Returns **Sharp**
# extract ## extract
Extract a region of the image. Extract a region of the image.
@@ -75,7 +94,7 @@ sharp(input)
Returns **Sharp** Returns **Sharp**
# flip ## flip
Flip the image about the vertical Y axis. This always occurs after rotation, if any. Flip the image about the vertical Y axis. This always occurs after rotation, if any.
The use of `flip` implies the removal of the EXIF `Orientation` tag, if any. The use of `flip` implies the removal of the EXIF `Orientation` tag, if any.
@@ -86,7 +105,7 @@ The use of `flip` implies the removal of the EXIF `Orientation` tag, if any.
Returns **Sharp** Returns **Sharp**
# flop ## flop
Flop the image about the horizontal X axis. This always occurs after rotation, if any. Flop the image about the horizontal X axis. This always occurs after rotation, if any.
The use of `flop` implies the removal of the EXIF `Orientation` tag, if any. The use of `flop` implies the removal of the EXIF `Orientation` tag, if any.
@@ -97,7 +116,7 @@ The use of `flop` implies the removal of the EXIF `Orientation` tag, if any.
Returns **Sharp** Returns **Sharp**
# sharpen ## sharpen
Sharpen the image. Sharpen the image.
When used without parameters, performs a fast, mild sharpen of the output image. When used without parameters, performs a fast, mild sharpen of the output image.
@@ -115,7 +134,7 @@ Separate control over the level of sharpening in "flat" and "jagged" areas is av
Returns **Sharp** Returns **Sharp**
# blur ## blur
Blur the image. Blur the image.
When used without parameters, performs a fast, mild blur of the output image. When used without parameters, performs a fast, mild blur of the output image.
@@ -130,7 +149,7 @@ When a `sigma` is provided, performs a slower, more accurate Gaussian blur.
Returns **Sharp** Returns **Sharp**
# extend ## extend
Extends/pads the edges of the image with the colour provided to the `background` method. Extends/pads the edges of the image with the colour provided to the `background` method.
This operation will always occur after resizing and extraction, if any. This operation will always occur after resizing and extraction, if any.
@@ -150,7 +169,7 @@ This operation will always occur after resizing and extraction, if any.
// to the top, left and right edges and 20 to the bottom edge // to the top, left and right edges and 20 to the bottom edge
sharp(input) sharp(input)
.resize(140) .resize(140)
.background({r: 0, g: 0, b: 0, a: 0}) .background({r: 0, g: 0, b: 0, alpha: 0})
.extend({top: 10, bottom: 20, left: 10, right: 10}) .extend({top: 10, bottom: 20, left: 10, right: 10})
... ...
``` ```
@@ -159,7 +178,7 @@ sharp(input)
Returns **Sharp** Returns **Sharp**
# flatten ## flatten
Merge alpha transparency channel, if any, with `background`. Merge alpha transparency channel, if any, with `background`.
@@ -169,7 +188,7 @@ Merge alpha transparency channel, if any, with `background`.
Returns **Sharp** Returns **Sharp**
# trim ## trim
Trim "boring" pixels from all edges that contain values within a percentage similarity of the top-left pixel. Trim "boring" pixels from all edges that contain values within a percentage similarity of the top-left pixel.
@@ -182,7 +201,7 @@ Trim "boring" pixels from all edges that contain values within a percentage simi
Returns **Sharp** Returns **Sharp**
# gamma ## gamma
Apply a gamma correction by reducing the encoding (darken) pre-resize at a factor of `1/gamma` Apply a gamma correction by reducing the encoding (darken) pre-resize at a factor of `1/gamma`
then increasing the encoding (brighten) post-resize at a factor of `gamma`. then increasing the encoding (brighten) post-resize at a factor of `gamma`.
@@ -199,7 +218,7 @@ when applying a gamma correction.
Returns **Sharp** Returns **Sharp**
# negate ## negate
Produce the "negative" of the image. Produce the "negative" of the image.
@@ -209,7 +228,7 @@ Produce the "negative" of the image.
Returns **Sharp** Returns **Sharp**
# normalise ## normalise
Enhance output image contrast by stretching its luminance to cover the full dynamic range. Enhance output image contrast by stretching its luminance to cover the full dynamic range.
@@ -219,7 +238,7 @@ Enhance output image contrast by stretching its luminance to cover the full dyna
Returns **Sharp** Returns **Sharp**
# normalize ## normalize
Alternative spelling of normalise. Alternative spelling of normalise.
@@ -229,7 +248,7 @@ Alternative spelling of normalise.
Returns **Sharp** Returns **Sharp**
# convolve ## convolve
Convolve the image with the specified kernel. Convolve the image with the specified kernel.
@@ -262,7 +281,7 @@ sharp(input)
Returns **Sharp** Returns **Sharp**
# threshold ## threshold
Any pixel value greather than or equal to the threshold value will be set to 255, otherwise it will be set to 0. Any pixel value greather than or equal to the threshold value will be set to 255, otherwise it will be set to 0.
@@ -278,7 +297,7 @@ Any pixel value greather than or equal to the threshold value will be set to 255
Returns **Sharp** Returns **Sharp**
# boolean ## boolean
Perform a bitwise boolean operation with operand image. Perform a bitwise boolean operation with operand image.

View File

@@ -1,6 +1,19 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. --> <!-- Generated by documentation.js. Update this documentation by updating the source code. -->
# toFile ### Table of Contents
- [toFile](#tofile)
- [toBuffer](#tobuffer)
- [withMetadata](#withmetadata)
- [jpeg](#jpeg)
- [png](#png)
- [webp](#webp)
- [tiff](#tiff)
- [raw](#raw)
- [toFormat](#toformat)
- [tile](#tile)
## toFile
Write output image data to a file. Write output image data to a file.
@@ -21,7 +34,7 @@ A Promises/A+ promise is returned when `callback` is not provided.
Returns **[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)&lt;[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)>** when no callback is provided Returns **[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)&lt;[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)>** when no callback is provided
# toBuffer ## toBuffer
Write output to a Buffer. Write output to a Buffer.
JPEG, PNG, WebP, and RAW output are supported. JPEG, PNG, WebP, and RAW output are supported.
@@ -40,7 +53,7 @@ By default, the format will match the input image, except GIF and SVG input whic
Returns **[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)&lt;[Buffer](https://nodejs.org/api/buffer.html)>** when no callback is provided Returns **[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)&lt;[Buffer](https://nodejs.org/api/buffer.html)>** when no callback is provided
# withMetadata ## withMetadata
Include all metadata (EXIF, XMP, IPTC) from the input image in the output image. Include all metadata (EXIF, XMP, IPTC) from the input image in the output image.
The default behaviour, when `withMetadata` is not used, is to strip all metadata and convert to the device-independent sRGB colour space. The default behaviour, when `withMetadata` is not used, is to strip all metadata and convert to the device-independent sRGB colour space.
@@ -56,7 +69,7 @@ This will also convert to and add a web-friendly sRGB ICC profile.
Returns **Sharp** Returns **Sharp**
# jpeg ## jpeg
Use these JPEG options for output image. Use these JPEG options for output image.
@@ -77,7 +90,7 @@ Use these JPEG options for output image.
Returns **Sharp** Returns **Sharp**
# png ## png
Use these PNG options for output image. Use these PNG options for output image.
@@ -94,7 +107,7 @@ Use these PNG options for output image.
Returns **Sharp** Returns **Sharp**
# webp ## webp
Use these WebP options for output image. Use these WebP options for output image.
@@ -102,6 +115,9 @@ Use these WebP options for output image.
- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)?** output options - `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)?** output options
- `options.quality` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** quality, integer 1-100 (optional, default `80`) - `options.quality` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** quality, integer 1-100 (optional, default `80`)
- `options.alphaQuality` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** quality of alpha layer, integer 0-100 (optional, default `100`)
- `options.lossless` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** use lossless compression mode (optional, default `false`)
- `options.nearLossless` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** use near_lossless compression mode (optional, default `false`)
- `options.force` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** force WebP output, otherwise attempt to use input format (optional, default `true`) - `options.force` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** force WebP output, otherwise attempt to use input format (optional, default `true`)
@@ -109,7 +125,7 @@ Use these WebP options for output image.
Returns **Sharp** Returns **Sharp**
# tiff ## tiff
Use these TIFF options for output image. Use these TIFF options for output image.
@@ -124,13 +140,13 @@ Use these TIFF options for output image.
Returns **Sharp** Returns **Sharp**
# raw ## raw
Force output to be raw, uncompressed uint8 pixel data. Force output to be raw, uncompressed uint8 pixel data.
Returns **Sharp** Returns **Sharp**
# toFormat ## toFormat
Force output to a given format. Force output to a given format.
@@ -144,7 +160,7 @@ Force output to a given format.
Returns **Sharp** Returns **Sharp**
# tile ## tile
Use tile-based deep zoom (image pyramid) output. Use tile-based deep zoom (image pyramid) output.
Set the format and options for tile images via the `toFormat`, `jpeg`, `png` or `webp` functions. Set the format and options for tile images via the `toFormat`, `jpeg`, `png` or `webp` functions.

View File

@@ -1,6 +1,16 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. --> <!-- Generated by documentation.js. Update this documentation by updating the source code. -->
# resize ### Table of Contents
- [resize](#resize)
- [crop](#crop)
- [embed](#embed)
- [max](#max)
- [min](#min)
- [ignoreAspectRatio](#ignoreaspectratio)
- [withoutEnlargement](#withoutenlargement)
## resize
Resize image to `width` x `height`. Resize image to `width` x `height`.
By default, the resized image is centre cropped to the exact size specified. By default, the resized image is centre cropped to the exact size specified.
@@ -52,7 +62,7 @@ sharp(inputBuffer)
Returns **Sharp** Returns **Sharp**
# crop ## crop
Crop the resized image to the exact size specified, the default behaviour. Crop the resized image to the exact size specified, the default behaviour.
@@ -87,7 +97,7 @@ readableStream.pipe(transformer).pipe(writableStream);
Returns **Sharp** Returns **Sharp**
# embed ## embed
Preserving aspect ratio, resize the image to the maximum `width` or `height` specified Preserving aspect ratio, resize the image to the maximum `width` or `height` specified
then embed on a background of the exact `width` and `height` specified. then embed on a background of the exact `width` and `height` specified.
@@ -100,7 +110,7 @@ contain an alpha channel, even when the input image does not.
```javascript ```javascript
sharp('input.gif') sharp('input.gif')
.resize(200, 300) .resize(200, 300)
.background({r: 0, g: 0, b: 0, a: 0}) .background({r: 0, g: 0, b: 0, alpha: 0})
.embed() .embed()
.toFormat(sharp.format.webp) .toFormat(sharp.format.webp)
.toBuffer(function(err, outputBuffer) { .toBuffer(function(err, outputBuffer) {
@@ -114,7 +124,7 @@ sharp('input.gif')
Returns **Sharp** Returns **Sharp**
# max ## max
Preserving aspect ratio, resize the image to be as large as possible Preserving aspect ratio, resize the image to be as large as possible
while ensuring its dimensions are less than or equal to the `width` and `height` specified. while ensuring its dimensions are less than or equal to the `width` and `height` specified.
@@ -137,7 +147,7 @@ sharp(inputBuffer)
Returns **Sharp** Returns **Sharp**
# min ## min
Preserving aspect ratio, resize the image to be as small as possible Preserving aspect ratio, resize the image to be as small as possible
while ensuring its dimensions are greater than or equal to the `width` and `height` specified. while ensuring its dimensions are greater than or equal to the `width` and `height` specified.
@@ -146,14 +156,14 @@ Both `width` and `height` must be provided via `resize` otherwise the behaviour
Returns **Sharp** Returns **Sharp**
# ignoreAspectRatio ## ignoreAspectRatio
Ignoring the aspect ratio of the input, stretch the image to Ignoring the aspect ratio of the input, stretch the image to
the exact `width` and/or `height` provided via `resize`. the exact `width` and/or `height` provided via `resize`.
Returns **Sharp** Returns **Sharp**
# withoutEnlargement ## withoutEnlargement
Do not enlarge the output image if the input image width _or_ height are already less than the required dimensions. Do not enlarge the output image if the input image width _or_ height are already less than the required dimensions.
This is equivalent to GraphicsMagick's `>` geometry option: This is equivalent to GraphicsMagick's `>` geometry option:

View File

@@ -1,6 +1,13 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. --> <!-- Generated by documentation.js. Update this documentation by updating the source code. -->
# cache ### Table of Contents
- [cache](#cache)
- [concurrency](#concurrency)
- [counters](#counters)
- [simd](#simd)
## cache
Gets, or when options are provided sets, the limits of _libvips'_ operation cache. Gets, or when options are provided sets, the limits of _libvips'_ operation cache.
Existing entries in the cache will be trimmed after any change in limits. Existing entries in the cache will be trimmed after any change in limits.
@@ -28,7 +35,7 @@ sharp.cache(false);
Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)**
# concurrency ## concurrency
Gets, or when a concurrency is provided sets, Gets, or when a concurrency is provided sets,
the number of threads _libvips'_ should create to process each image. the number of threads _libvips'_ should create to process each image.
@@ -54,7 +61,7 @@ sharp.concurrency(0); // 4
Returns **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** concurrency Returns **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** concurrency
# counters ## counters
Provides access to internal task counters. Provides access to internal task counters.
@@ -69,7 +76,7 @@ const counters = sharp.counters(); // { queue: 2, process: 4 }
Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)**
# simd ## simd
Get and set use of SIMD vector unit instructions. Get and set use of SIMD vector unit instructions.
Requires libvips to have been compiled with liborc support. Requires libvips to have been compiled with liborc support.

View File

@@ -4,6 +4,29 @@
Requires libvips v8.4.2. Requires libvips v8.4.2.
#### v0.17.2 - 11<sup>th</sup> February 2017
* Ensure Readable side of Stream can start flowing after Writable side has finished.
[#671](https://github.com/lovell/sharp/issues/671)
[@danhaller](https://github.com/danhaller)
* Expose WebP alpha quality, lossless and near-lossless output options.
[#685](https://github.com/lovell/sharp/pull/685)
[@rnanwani](https://github.com/rnanwani)
#### v0.17.1 - 15<sup>th</sup> January 2017
* Improve error messages for invalid parameters.
[@spikeon](https://github.com/spikeon)
[#644](https://github.com/lovell/sharp/pull/644)
* Simplify expression for finding vips-cpp libdir.
[#656](https://github.com/lovell/sharp/pull/656)
* Allow HTTPS-over-HTTP proxy when downloading pre-compiled dependencies.
[@wangzhiwei1888](https://github.com/wangzhiwei1888)
[#679](https://github.com/lovell/sharp/issues/679)
#### v0.17.0 - 11<sup>th</sup> December 2016 #### v0.17.0 - 11<sup>th</sup> December 2016
* Drop support for versions of Node prior to v4. * Drop support for versions of Node prior to v4.

View File

@@ -94,12 +94,15 @@ the help and code contributions of the following people:
* [Kleis Auke Wolthuizen](https://github.com/kleisauke) * [Kleis Auke Wolthuizen](https://github.com/kleisauke)
* [Matt Hirsch](https://github.com/mhirsch) * [Matt Hirsch](https://github.com/mhirsch)
* [Rahul Nanwani](https://github.com/rnanwani) * [Rahul Nanwani](https://github.com/rnanwani)
* [Matthias Thoemmes](https://github.com/cmtt)
* [Patrick Paskaris](https://github.com/ppaskaris)
* [Jérémy Lal](https://github.com/kapouer)
Thank you! Thank you!
### Licence ### Licence
Copyright 2013, 2014, 2015, 2016 Lovell Fuller and contributors. Copyright 2013, 2014, 2015, 2016, 2017 Lovell Fuller and contributors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@@ -135,6 +135,11 @@ You can now download your deployment ZIP using `scp` and upload it to Lambda. Be
* [gulp-responsive](https://www.npmjs.com/package/gulp-responsive) * [gulp-responsive](https://www.npmjs.com/package/gulp-responsive)
* [grunt-sharp](https://www.npmjs.com/package/grunt-sharp) * [grunt-sharp](https://www.npmjs.com/package/grunt-sharp)
### CLI tools
* [sharp-cli](https://www.npmjs.com/package/sharp-cli)
### Security ### Security
Many users of this module process untrusted, user-supplied images, Many users of this module process untrusted, user-supplied images,

View File

@@ -145,6 +145,9 @@ const Sharp = function (input, options) {
pngCompressionLevel: 6, pngCompressionLevel: 6,
pngAdaptiveFiltering: true, pngAdaptiveFiltering: true,
webpQuality: 80, webpQuality: 80,
webpAlphaQuality: 100,
webpLossless: false,
webpNearLossless: false,
tiffQuality: 80, tiffQuality: 80,
tileSize: 256, tileSize: 256,
tileOverlap: 0, tileOverlap: 0,

View File

@@ -64,6 +64,12 @@ const _write = function _write (chunk, encoding, callback) {
if (Array.isArray(this.options.input.buffer)) { if (Array.isArray(this.options.input.buffer)) {
/* istanbul ignore else */ /* istanbul ignore else */
if (is.buffer(chunk)) { if (is.buffer(chunk)) {
if (this.options.input.buffer.length === 0) {
const that = this;
this.on('finish', function () {
that.streamInFinished = true;
});
}
this.options.input.buffer.push(chunk); this.options.input.buffer.push(chunk);
callback(); callback();
} else { } else {

View File

@@ -80,6 +80,21 @@ const inArray = function (val, list) {
return list.indexOf(val) !== -1; return list.indexOf(val) !== -1;
}; };
/**
* Create an Error with a message relating to an invalid parameter.
*
* @param {String} name - parameter name.
* @param {String} expected - description of the type/value/range expected.
* @param {*} actual - the value received.
* @returns {Error} Containing the formatted message.
* @private
*/
const invalidParameterError = function (name, expected, actual) {
return new Error(
`Expected ${expected} for ${name} but received ${actual} of type ${typeof actual}`
);
};
module.exports = { module.exports = {
defined: defined, defined: defined,
object: object, object: object,
@@ -90,5 +105,6 @@ module.exports = {
number: number, number: number,
integer: integer, integer: integer,
inRange: inRange, inRange: inRange,
inArray: inArray inArray: inArray,
invalidParameterError: invalidParameterError
}; };

View File

@@ -186,7 +186,7 @@ const blur = function blur (sigma) {
* // to the top, left and right edges and 20 to the bottom edge * // to the top, left and right edges and 20 to the bottom edge
* sharp(input) * sharp(input)
* .resize(140) * .resize(140)
* .background({r: 0, g: 0, b: 0, a: 0}) * .background({r: 0, g: 0, b: 0, alpha: 0})
* .extend({top: 10, bottom: 20, left: 10, right: 10}) * .extend({top: 10, bottom: 20, left: 10, right: 10})
* ... * ...
* *

View File

@@ -168,6 +168,9 @@ const png = function png (options) {
* Use these WebP options for output image. * Use these WebP options for output image.
* @param {Object} [options] - output options * @param {Object} [options] - output options
* @param {Number} [options.quality=80] - quality, integer 1-100 * @param {Number} [options.quality=80] - quality, integer 1-100
* @param {Number} [options.alphaQuality=100] - quality of alpha layer, integer 0-100
* @param {Boolean} [options.lossless=false] - use lossless compression mode
* @param {Boolean} [options.nearLossless=false] - use near_lossless compression mode
* @param {Boolean} [options.force=true] - force WebP output, otherwise attempt to use input format * @param {Boolean} [options.force=true] - force WebP output, otherwise attempt to use input format
* @returns {Sharp} * @returns {Sharp}
* @throws {Error} Invalid options * @throws {Error} Invalid options
@@ -180,6 +183,19 @@ const webp = function webp (options) {
throw new Error('Invalid quality (integer, 1-100) ' + options.quality); throw new Error('Invalid quality (integer, 1-100) ' + options.quality);
} }
} }
if (is.object(options) && is.defined(options.alphaQuality)) {
if (is.integer(options.alphaQuality) && is.inRange(options.alphaQuality, 1, 100)) {
this.options.webpAlphaQuality = options.alphaQuality;
} else {
throw new Error('Invalid webp alpha quality (integer, 1-100) ' + options.alphaQuality);
}
}
if (is.object(options) && is.defined(options.lossless)) {
this._setBooleanOption('webpLossless', options.lossless);
}
if (is.object(options) && is.defined(options.nearLossless)) {
this._setBooleanOption('webpNearLossless', options.nearLossless);
}
return this._updateFormatOut('webp', options); return this._updateFormatOut('webp', options);
}; };
@@ -362,9 +378,9 @@ const _pipeline = function _pipeline (callback) {
// output=stream // output=stream
if (this._isStreamInput()) { if (this._isStreamInput()) {
// output=stream, input=stream // output=stream, input=stream
this.on('finish', function () { if (this.streamInFinished) {
that._flattenBufferIn(); this._flattenBufferIn();
sharp.pipeline(that.options, function (err, data, info) { sharp.pipeline(this.options, function (err, data, info) {
if (err) { if (err) {
that.emit('error', err); that.emit('error', err);
} else { } else {
@@ -373,7 +389,20 @@ const _pipeline = function _pipeline (callback) {
} }
that.push(null); that.push(null);
}); });
}); } else {
this.on('finish', function () {
that._flattenBufferIn();
sharp.pipeline(that.options, function (err, data, info) {
if (err) {
that.emit('error', err);
} else {
that.emit('info', info);
that.push(data);
}
that.push(null);
});
});
}
} else { } else {
// output=stream, input=file/buffer // output=stream, input=file/buffer
sharp.pipeline(this.options, function (err, data, info) { sharp.pipeline(this.options, function (err, data, info) {

View File

@@ -104,7 +104,7 @@ const resize = function resize (width, height, options) {
if (is.integer(width) && is.inRange(width, 1, this.constructor.maximum.width)) { if (is.integer(width) && is.inRange(width, 1, this.constructor.maximum.width)) {
this.options.width = width; this.options.width = width;
} else { } else {
throw new Error('Invalid width (1 to ' + this.constructor.maximum.width + ') ' + width); throw is.invalidParameterError('width', `integer between 1 and ${this.constructor.maximum.width}`, width);
} }
} else { } else {
this.options.width = -1; this.options.width = -1;
@@ -113,7 +113,7 @@ const resize = function resize (width, height, options) {
if (is.integer(height) && is.inRange(height, 1, this.constructor.maximum.height)) { if (is.integer(height) && is.inRange(height, 1, this.constructor.maximum.height)) {
this.options.height = height; this.options.height = height;
} else { } else {
throw new Error('Invalid height (1 to ' + this.constructor.maximum.height + ') ' + height); throw is.invalidParameterError('height', `integer between 1 and ${this.constructor.maximum.height}`, height);
} }
} else { } else {
this.options.height = -1; this.options.height = -1;
@@ -124,7 +124,7 @@ const resize = function resize (width, height, options) {
if (is.string(kernel[options.kernel])) { if (is.string(kernel[options.kernel])) {
this.options.kernel = kernel[options.kernel]; this.options.kernel = kernel[options.kernel];
} else { } else {
throw new Error('Invalid kernel ' + options.kernel); throw is.invalidParameterError('kernel', 'valid kernel name', options.kernel);
} }
} }
// Interpolator // Interpolator
@@ -132,7 +132,7 @@ const resize = function resize (width, height, options) {
if (is.string(interpolator[options.interpolator])) { if (is.string(interpolator[options.interpolator])) {
this.options.interpolator = interpolator[options.interpolator]; this.options.interpolator = interpolator[options.interpolator];
} else { } else {
throw new Error('Invalid interpolator ' + options.interpolator); throw is.invalidParameterError('interpolator', 'valid interpolator name', options.interpolator);
} }
} }
// Centre sampling // Centre sampling
@@ -185,7 +185,7 @@ const crop = function crop (crop) {
// Strategy // Strategy
this.options.crop = crop; this.options.crop = crop;
} else { } else {
throw new Error('Unsupported crop ' + crop); throw is.invalidParameterError('crop', 'valid crop id/name/strategy', crop);
} }
return this; return this;
}; };
@@ -200,7 +200,7 @@ const crop = function crop (crop) {
* @example * @example
* sharp('input.gif') * sharp('input.gif')
* .resize(200, 300) * .resize(200, 300)
* .background({r: 0, g: 0, b: 0, a: 0}) * .background({r: 0, g: 0, b: 0, alpha: 0})
* .embed() * .embed()
* .toFormat(sharp.format.webp) * .toFormat(sharp.format.webp)
* .toBuffer(function(err, outputBuffer) { * .toBuffer(function(err, outputBuffer) {

View File

@@ -1,8 +1,9 @@
{ {
"name": "sharp", "name": "sharp",
"description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP and TIFF images", "description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP and TIFF images",
"version": "0.17.0", "version": "0.17.2",
"author": "Lovell Fuller <npm@lovell.info>", "author": "Lovell Fuller <npm@lovell.info>",
"homepage": "https://github.com/lovell/sharp",
"contributors": [ "contributors": [
"Pierre Inglebert <pierre.inglebert@gmail.com>", "Pierre Inglebert <pierre.inglebert@gmail.com>",
"Jonathan Ong <jonathanrichardong@gmail.com>", "Jonathan Ong <jonathanrichardong@gmail.com>",
@@ -29,11 +30,13 @@
"Kleis Auke Wolthuizen <info@kleisauke.nl>", "Kleis Auke Wolthuizen <info@kleisauke.nl>",
"Matt Hirsch <mhirsch@media.mit.edu>", "Matt Hirsch <mhirsch@media.mit.edu>",
"Matthias Thoemmes <thoemmes@gmail.com>", "Matthias Thoemmes <thoemmes@gmail.com>",
"Patrick Paskaris <patrick@paskaris.gr>" "Patrick Paskaris <patrick@paskaris.gr>",
"Jérémy Lal <kapouer@melix.org>",
"Rahul Nanwani <r.nanwani@gmail.com>"
], ],
"scripts": { "scripts": {
"clean": "rm -rf node_modules/ build/ vendor/ coverage/ test/fixtures/output.*", "clean": "rm -rf node_modules/ build/ vendor/ coverage/ test/fixtures/output.*",
"test": "semistandard && cross-env VIPS_WARNING=0 nyc --reporter=lcov --branches=99 mocha --slow=5000 --timeout=60000 ./test/unit/*.js", "test": "semistandard && cc && cross-env VIPS_WARNING=0 nyc --reporter=lcov --branches=99 mocha --slow=5000 --timeout=60000 ./test/unit/*.js",
"test-leak": "./test/leak/leak.sh", "test-leak": "./test/leak/leak.sh",
"test-packaging": "./packaging/test-linux-x64.sh", "test-packaging": "./packaging/test-linux-x64.sh",
"docs": "for m in constructor input resize composite operation colour channel output utility; do documentation build --shallow --format=md lib/$m.js >docs/api-$m.md; done" "docs": "for m in constructor input resize composite operation colour channel output utility; do documentation build --shallow --format=md lib/$m.js >docs/api-$m.md; done"
@@ -60,22 +63,22 @@
], ],
"dependencies": { "dependencies": {
"caw": "^2.0.0", "caw": "^2.0.0",
"color": "^1.0.2", "color": "^1.0.3",
"got": "^6.6.3", "got": "^6.7.1",
"nan": "^2.4.0", "nan": "^2.5.1",
"semver": "^5.3.0", "semver": "^5.3.0",
"tar": "^2.2.1" "tar": "^2.2.1"
}, },
"devDependencies": { "devDependencies": {
"async": "^2.1.4", "async": "^2.1.4",
"bufferutil": "^1.3.0", "bufferutil": "^2.0.1",
"cross-env": "^3.1.3", "cc": "^1.0.0",
"documentation": "^4.0.0-beta16", "cross-env": "^3.1.4",
"exif-reader": "^1.0.1", "documentation": "^4.0.0-beta.18",
"icc": "^0.0.2", "exif-reader": "^1.0.2",
"icc": "^1.0.0",
"mocha": "^3.2.0", "mocha": "^3.2.0",
"node-cpplint": "^0.4.0", "nyc": "^10.1.2",
"nyc": "^10.0.0",
"rimraf": "^2.5.4", "rimraf": "^2.5.4",
"semistandard": "^9.2.1", "semistandard": "^9.2.1",
"unzip": "^0.1.11" "unzip": "^0.1.11"
@@ -91,5 +94,12 @@
"env": [ "env": [
"mocha" "mocha"
] ]
},
"cc": {
"linelength": "120",
"filter": [
"build/include",
"runtime/indentation_namespace"
]
} }
} }

View File

@@ -16,7 +16,7 @@ export CFLAGS="${FLAGS}"
export CXXFLAGS="${FLAGS}" export CXXFLAGS="${FLAGS}"
# Dependency version numbers # Dependency version numbers
VERSION_ZLIB=1.2.8 VERSION_ZLIB=1.2.10
VERSION_FFI=3.2.1 VERSION_FFI=3.2.1
VERSION_GLIB=2.50.1 VERSION_GLIB=2.50.1
VERSION_XML2=2.9.4 VERSION_XML2=2.9.4
@@ -24,7 +24,7 @@ VERSION_GSF=1.14.40
VERSION_EXIF=0.6.21 VERSION_EXIF=0.6.21
VERSION_LCMS2=2.8 VERSION_LCMS2=2.8
VERSION_JPEG=1.5.1 VERSION_JPEG=1.5.1
VERSION_PNG16=1.6.25 VERSION_PNG16=1.6.28
VERSION_WEBP=0.5.1 VERSION_WEBP=0.5.1
VERSION_TIFF=4.0.6 VERSION_TIFF=4.0.6
VERSION_ORC=0.4.26 VERSION_ORC=0.4.26

View File

@@ -1,316 +0,0 @@
#!/bin/sh
# Use of this script is deprecated
echo
echo "WARNING: THIS SCRIPT WILL STOP WORKING AT THE END OF 2016"
echo
echo "WARNING: THIS SCRIPT IS NO LONGER REQUIRED ON MOST 64-BIT LINUX SYSTEMS WHEN USING SHARP V0.12.0+"
echo
echo "See http://sharp.dimens.io/page/install#linux"
echo
echo "If you really, really need this script, it will attempt"
echo "to globally install libvips if not already available."
echo
sleep 5
vips_version_minimum=8.4.2
vips_version_latest_major_minor=8.4
vips_version_latest_patch=2
openslide_version_minimum=3.4.0
openslide_version_latest_major_minor=3.4
openslide_version_latest_patch=1
install_libvips_from_source() {
echo "Compiling libvips $vips_version_latest_major_minor.$vips_version_latest_patch from source"
curl -O http://www.vips.ecs.soton.ac.uk/supported/$vips_version_latest_major_minor/vips-$vips_version_latest_major_minor.$vips_version_latest_patch.tar.gz
tar zvxf vips-$vips_version_latest_major_minor.$vips_version_latest_patch.tar.gz
cd vips-$vips_version_latest_major_minor.$vips_version_latest_patch
CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=0" ./configure --disable-debug --disable-docs --disable-static --disable-introspection --disable-dependency-tracking --enable-cxx=yes --without-python --without-orc --without-fftw $1
make
make install
cd ..
rm -rf vips-$vips_version_latest_major_minor.$vips_version_latest_patch
rm vips-$vips_version_latest_major_minor.$vips_version_latest_patch.tar.gz
ldconfig
echo "Installed libvips $(PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:/usr/lib/pkgconfig pkg-config --modversion vips)"
}
install_libopenslide_from_source() {
echo "Compiling openslide $openslide_version_latest_major_minor.$openslide_version_latest_patch from source"
curl -O -L https://github.com/openslide/openslide/releases/download/v$openslide_version_latest_major_minor.$openslide_version_latest_patch/openslide-$openslide_version_latest_major_minor.$openslide_version_latest_patch.tar.gz
tar xzvf openslide-$openslide_version_latest_major_minor.$openslide_version_latest_patch.tar.gz
cd openslide-$openslide_version_latest_major_minor.$openslide_version_latest_patch
PKG_CONFIG_PATH=$pkg_config_path ./configure $1
make
make install
cd ..
rm -rf openslide-$openslide_version_latest_major_minor.$openslide_version_latest_patch
rm openslide-$openslide_version_latest_major_minor.$openslide_version_latest_patch.tar.gz
ldconfig
echo "Installed libopenslide $openslide_version_latest_major_minor.$openslide_version_latest_patch"
}
sorry() {
echo "Sorry, I don't yet know how to install lib$1 on $2"
exit 1
}
pkg_config_path="$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:/usr/lib/pkgconfig"
check_if_library_exists() {
PKG_CONFIG_PATH=$pkg_config_path pkg-config --exists $1
if [ $? -eq 0 ]; then
version_found=$(PKG_CONFIG_PATH=$pkg_config_path pkg-config --modversion $1)
PKG_CONFIG_PATH=$pkg_config_path pkg-config --atleast-version=$2 $1
if [ $? -eq 0 ]; then
# Found suitable version of libvips
echo "Found lib$1 $version_found"
return 1
fi
echo "Found lib$1 $version_found but require $2"
else
echo "Could not find lib$1 using a PKG_CONFIG_PATH of '$pkg_config_path'"
fi
return 0
}
enable_openslide=0
# Is libvips already installed, and is it at least the minimum required version?
if [ $# -eq 1 ]; then
if [ "$1" = "--with-openslide" ]; then
echo "Installing vips with openslide support"
enable_openslide=1
else
echo "Sorry, $1 is not supported. Did you mean --with-openslide?"
exit 1
fi
fi
if ! type pkg-config >/dev/null; then
sorry "vips" "a system without pkg-config"
fi
openslide_exists=0
if [ $enable_openslide -eq 1 ]; then
check_if_library_exists "openslide" "$openslide_version_minimum"
openslide_exists=$?
fi
check_if_library_exists "vips" "$vips_version_minimum"
vips_exists=$?
if [ $vips_exists -eq 1 ] && [ $enable_openslide -eq 1 ]; then
if [ $openslide_exists -eq 1 ]; then
# Check if vips compiled with openslide support
vips_with_openslide=`vips list classes | grep -i opensli`
if [ -z $vips_with_openslide ]; then
echo "Vips compiled without openslide support."
else
exit 0
fi
fi
elif [ $vips_exists -eq 1 ] && [ $enable_openslide -eq 0 ]; then
exit 0
fi
# Verify root/sudo access
if [ "$(id -u)" -ne "0" ]; then
echo "Sorry, I need root/sudo access to continue"
exit 1
fi
# Deprecation warning
if [ "$(arch)" == "x86_64" ]; then
echo "This script is no longer required on most 64-bit Linux systems when using sharp v0.12.0+"
fi
# OS-specific installations of libopenslide follows
# Either openslide does not exist, or vips is installed without openslide support
if [ $enable_openslide -eq 1 ] && [ -z $vips_with_openslide ] && [ $openslide_exists -eq 0 ]; then
if [ -f /etc/debian_version ]; then
# Debian Linux
DISTRO=$(lsb_release -c -s)
echo "Detected Debian Linux '$DISTRO'"
case "$DISTRO" in
jessie|vivid|wily|xenial)
# Debian 8, Ubuntu 15
echo "Installing libopenslide via apt-get"
apt-get install -y libopenslide-dev
;;
trusty|utopic|qiana|rebecca|rafaela|freya)
# Ubuntu 14, Mint 17
echo "Installing libopenslide dependencies via apt-get"
apt-get install -y automake build-essential curl zlib1g-dev libopenjpeg-dev libpng12-dev libjpeg-dev libtiff5-dev libgdk-pixbuf2.0-dev libxml2-dev libsqlite3-dev libcairo2-dev libglib2.0-dev sqlite3 libsqlite3-dev
install_libopenslide_from_source
;;
precise|wheezy|maya)
# Debian 7, Ubuntu 12.04, Mint 13
echo "Installing libopenslide dependencies via apt-get"
apt-get install -y automake build-essential curl zlib1g-dev libopenjpeg-dev libpng12-dev libjpeg-dev libtiff5-dev libgdk-pixbuf2.0-dev libxml2-dev libsqlite3-dev libcairo2-dev libglib2.0-dev sqlite3 libsqlite3-dev
install_libopenslide_from_source
;;
*)
# Unsupported Debian-based OS
sorry "openslide" "Debian-based $DISTRO"
;;
esac
elif [ -f /etc/redhat-release ]; then
# Red Hat Linux
RELEASE=$(cat /etc/redhat-release)
echo "Detected Red Hat Linux '$RELEASE'"
case $RELEASE in
"Red Hat Enterprise Linux release 7."*|"CentOS Linux release 7."*|"Scientific Linux release 7."*)
# RHEL/CentOS 7
echo "Installing libopenslide dependencies via yum"
yum groupinstall -y "Development Tools"
yum install -y tar curl libpng-devel libjpeg-devel libxml2-devel zlib-devel openjpeg-devel libtiff-devel gdk-pixbuf2-devel sqlite-devel cairo-devel glib2-devel
install_libopenslide_from_source "--prefix=/usr"
;;
"Red Hat Enterprise Linux release 6."*|"CentOS release 6."*|"Scientific Linux release 6."*)
# RHEL/CentOS 6
echo "Installing libopenslide dependencies via yum"
yum groupinstall -y "Development Tools"
yum install -y tar curl libpng-devel libjpeg-devel libxml2-devel zlib-devel openjpeg-devel libtiff-devel gdk-pixbuf2-devel sqlite-devel cairo-devel glib2-devel
install_libopenslide_from_source "--prefix=/usr"
;;
"Fedora release 21 "*|"Fedora release 22 "*)
# Fedora 21, 22
echo "Installing libopenslide via yum"
yum install -y openslide-devel
;;
*)
# Unsupported RHEL-based OS
sorry "openslide" "$RELEASE"
;;
esac
elif [ -f /etc/os-release ]; then
RELEASE=$(cat /etc/os-release | grep VERSION)
echo "Detected OpenSuse Linux '$RELEASE'"
case $RELEASE in
*"13.2"*)
echo "Installing libopenslide via zypper"
zypper --gpg-auto-import-keys install -y libopenslide-devel
;;
esac
elif [ -f /etc/SuSE-brand ]; then
RELEASE=$(cat /etc/SuSE-brand | grep VERSION)
echo "Detected OpenSuse Linux '$RELEASE'"
case $RELEASE in
*"13.1")
echo "Installing libopenslide dependencies via zypper"
zypper --gpg-auto-import-keys install -y --type pattern devel_basis
zypper --gpg-auto-import-keys install -y tar curl libpng16-devel libjpeg-turbo libjpeg8-devel libxml2-devel zlib-devel openjpeg-devel libtiff-devel libgdk_pixbuf-2_0-0 sqlite3-devel cairo-devel glib2-devel
install_libopenslide_from_source
;;
esac
else
# Unsupported OS
sorry "openslide" "$(uname -a)"
fi
fi
# OS-specific installations of libvips follows
if [ -f /etc/debian_version ]; then
# Debian Linux
DISTRO=$(lsb_release -c -s)
echo "Detected Debian Linux '$DISTRO'"
case "$DISTRO" in
jessie|trusty|utopic|vivid|wily|xenial|qiana|rebecca|rafaela|freya)
# Debian 8, Ubuntu 14.04+, Mint 17
echo "Installing libvips dependencies via apt-get"
apt-get install -y automake build-essential gobject-introspection gtk-doc-tools libglib2.0-dev libjpeg-dev libpng12-dev libwebp-dev libtiff5-dev libexif-dev libgsf-1-dev liblcms2-dev libxml2-dev swig libmagickcore-dev curl
install_libvips_from_source
;;
precise|wheezy|maya)
# Debian 7, Ubuntu 12.04, Mint 13
echo "Installing libvips dependencies via apt-get"
add-apt-repository -y ppa:lyrasis/precise-backports
apt-get update
apt-get install -y automake build-essential gobject-introspection gtk-doc-tools libglib2.0-dev libjpeg-dev libpng12-dev libwebp-dev libtiff4-dev libexif-dev libgsf-1-dev liblcms2-dev libxml2-dev swig libmagickcore-dev curl
install_libvips_from_source
;;
*)
# Unsupported Debian-based OS
sorry "vips" "Debian-based $DISTRO"
;;
esac
elif [ -f /etc/redhat-release ]; then
# Red Hat Linux
RELEASE=$(cat /etc/redhat-release)
echo "Detected Red Hat Linux '$RELEASE'"
case $RELEASE in
"Red Hat Enterprise Linux release 7."*|"CentOS Linux release 7."*|"Scientific Linux release 7."*)
# RHEL/CentOS 7
echo "Installing libvips dependencies via yum"
yum groupinstall -y "Development Tools"
yum install -y tar curl gtk-doc libxml2-devel libjpeg-turbo-devel libpng-devel libtiff-devel libexif-devel libgsf-devel lcms2-devel ImageMagick-devel gobject-introspection-devel libwebp-devel
install_libvips_from_source "--prefix=/usr"
;;
"Red Hat Enterprise Linux release 6."*|"CentOS release 6."*|"Scientific Linux release 6."*)
# RHEL/CentOS 6
echo "Installing libvips dependencies via yum"
yum groupinstall -y "Development Tools"
yum install -y tar curl gtk-doc libxml2-devel libjpeg-turbo-devel libpng-devel libtiff-devel libexif-devel libgsf-devel lcms-devel ImageMagick-devel
yum install -y http://li.nux.ro/download/nux/dextop/el6/x86_64/nux-dextop-release-0-2.el6.nux.noarch.rpm
yum install -y --enablerepo=nux-dextop gobject-introspection-devel
yum install -y http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
yum install -y --enablerepo=remi libwebp-devel
install_libvips_from_source "--prefix=/usr"
;;
"Fedora"*)
# Fedora 21, 22, 23
echo "Installing libvips dependencies via yum"
yum groupinstall -y "Development Tools"
yum install -y gcc-c++ gtk-doc libxml2-devel libjpeg-turbo-devel libpng-devel libtiff-devel libexif-devel lcms-devel ImageMagick-devel gobject-introspection-devel libwebp-devel curl
install_libvips_from_source "--prefix=/usr"
;;
*)
# Unsupported RHEL-based OS
sorry "vips" "$RELEASE"
;;
esac
elif [ -f /etc/system-release ]; then
# Probably Amazon Linux
RELEASE=$(cat /etc/system-release)
case $RELEASE in
"Amazon Linux AMI release 2015.03"|"Amazon Linux AMI release 2015.09")
# Amazon Linux
echo "Detected '$RELEASE'"
echo "Installing libvips dependencies via yum"
yum groupinstall -y "Development Tools"
yum install -y gtk-doc libxml2-devel libjpeg-turbo-devel libpng-devel libtiff-devel libexif-devel libgsf-devel lcms2-devel ImageMagick-devel gobject-introspection-devel libwebp-devel curl
install_libvips_from_source "--prefix=/usr"
;;
*)
# Unsupported Amazon Linux version
sorry "vips" "$RELEASE"
;;
esac
elif [ -f /etc/os-release ]; then
RELEASE=$(cat /etc/os-release | grep VERSION)
echo "Detected OpenSuse Linux '$RELEASE'"
case $RELEASE in
*"13.2"*)
echo "Installing libvips dependencies via zypper"
zypper --gpg-auto-import-keys install -y --type pattern devel_basis
zypper --gpg-auto-import-keys install -y tar curl gtk-doc libxml2-devel libjpeg-turbo libjpeg8-devel libpng16-devel libtiff-devel libexif-devel liblcms2-devel ImageMagick-devel gobject-introspection-devel libwebp-devel
install_libvips_from_source
;;
esac
elif [ -f /etc/SuSE-brand ]; then
RELEASE=$(cat /etc/SuSE-brand | grep VERSION)
echo "Detected OpenSuse Linux '$RELEASE'"
case $RELEASE in
*"13.1")
echo "Installing libvips dependencies via zypper"
zypper --gpg-auto-import-keys install -y --type pattern devel_basis
zypper --gpg-auto-import-keys install -y tar curl gtk-doc libxml2-devel libjpeg-turbo libjpeg8-devel libpng16-devel libtiff-devel libexif-devel liblcms2-devel ImageMagick-devel gobject-introspection-devel libwebp-devel
install_libvips_from_source
;;
esac
else
# Unsupported OS
sorry "vips" "$(uname -a)"
fi

View File

@@ -1,12 +1,27 @@
// Copyright 2013, 2014, 2015, 2016, 2017 Lovell Fuller and contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cstdlib> #include <cstdlib>
#include <string> #include <string>
#include <string.h> #include <string.h>
#include <vector>
#include <node.h> #include <node.h>
#include <node_buffer.h> #include <node_buffer.h>
#include <nan.h>
#include <vips/vips8> #include <vips/vips8>
#include "nan.h"
#include "common.h" #include "common.h"
using vips::VImage; using vips::VImage;
@@ -254,8 +269,7 @@ namespace sharp {
return ( return (
(bands == 2 && interpretation == VIPS_INTERPRETATION_B_W) || (bands == 2 && interpretation == VIPS_INTERPRETATION_B_W) ||
(bands == 4 && interpretation != VIPS_INTERPRETATION_CMYK) || (bands == 4 && interpretation != VIPS_INTERPRETATION_CMYK) ||
(bands == 5 && interpretation == VIPS_INTERPRETATION_CMYK) (bands == 5 && interpretation == VIPS_INTERPRETATION_CMYK));
);
} }
/* /*
@@ -378,23 +392,23 @@ namespace sharp {
int top = 0; int top = 0;
// assign only if valid // assign only if valid
if(x >= 0 && x < (inWidth - outWidth)) { if (x >= 0 && x < (inWidth - outWidth)) {
left = x; left = x;
} else if(x >= (inWidth - outWidth)) { } else if (x >= (inWidth - outWidth)) {
left = inWidth - outWidth; left = inWidth - outWidth;
} }
if(y >= 0 && y < (inHeight - outHeight)) { if (y >= 0 && y < (inHeight - outHeight)) {
top = y; top = y;
} else if(y >= (inHeight - outHeight)) { } else if (y >= (inHeight - outHeight)) {
top = inHeight - outHeight; top = inHeight - outHeight;
} }
// the resulting left and top could have been outside the image after calculation from bottom/right edges // the resulting left and top could have been outside the image after calculation from bottom/right edges
if(left < 0) { if (left < 0) {
left = 0; left = 0;
} }
if(top < 0) { if (top < 0) {
top = 0; top = 0;
} }
@@ -421,8 +435,7 @@ namespace sharp {
*/ */
VipsOperationBoolean GetBooleanOperation(std::string const opStr) { VipsOperationBoolean GetBooleanOperation(std::string const opStr) {
return static_cast<VipsOperationBoolean>( return static_cast<VipsOperationBoolean>(
vips_enum_from_nick(nullptr, VIPS_TYPE_OPERATION_BOOLEAN, opStr.data()) vips_enum_from_nick(nullptr, VIPS_TYPE_OPERATION_BOOLEAN, opStr.data()));
);
} }
/* /*
@@ -430,8 +443,7 @@ namespace sharp {
*/ */
VipsInterpretation GetInterpretation(std::string const typeStr) { VipsInterpretation GetInterpretation(std::string const typeStr) {
return static_cast<VipsInterpretation>( return static_cast<VipsInterpretation>(
vips_enum_from_nick(nullptr, VIPS_TYPE_INTERPRETATION, typeStr.data()) vips_enum_from_nick(nullptr, VIPS_TYPE_INTERPRETATION, typeStr.data()));
);
} }
/* /*

View File

@@ -1,14 +1,28 @@
// Copyright 2013, 2014, 2015, 2016, 2017 Lovell Fuller and contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_COMMON_H_ #ifndef SRC_COMMON_H_
#define SRC_COMMON_H_ #define SRC_COMMON_H_
#include <string> #include <string>
#include <tuple> #include <tuple>
#include <vector>
#include <node.h> #include <node.h>
#include <nan.h>
#include <vips/vips8> #include <vips/vips8>
#include "nan.h"
// Verify platform and compiler compatibility // Verify platform and compiler compatibility
#if (VIPS_MAJOR_VERSION < 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 4)) #if (VIPS_MAJOR_VERSION < 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 4))
@@ -63,8 +77,7 @@ namespace sharp {
// Create an InputDescriptor instance from a v8::Object describing an input image // Create an InputDescriptor instance from a v8::Object describing an input image
InputDescriptor* CreateInputDescriptor( InputDescriptor* CreateInputDescriptor(
v8::Handle<v8::Object> input, std::vector<v8::Local<v8::Object>> buffersToPersist v8::Handle<v8::Object> input, std::vector<v8::Local<v8::Object>> buffersToPersist);
);
enum class ImageType { enum class ImageType {
JPEG, JPEG,

View File

@@ -1,9 +1,24 @@
// Copyright 2013, 2014, 2015, 2016, 2017 Lovell Fuller and contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <numeric> #include <numeric>
#include <vector>
#include <node.h> #include <node.h>
#include <nan.h>
#include <vips/vips8> #include <vips/vips8>
#include "nan.h"
#include "common.h" #include "common.h"
#include "metadata.h" #include "metadata.h"
@@ -11,15 +26,14 @@ class MetadataWorker : public Nan::AsyncWorker {
public: public:
MetadataWorker( MetadataWorker(
Nan::Callback *callback, MetadataBaton *baton, Nan::Callback *callback, MetadataBaton *baton,
std::vector<v8::Local<v8::Object>> const buffersToPersist std::vector<v8::Local<v8::Object>> const buffersToPersist)
) : Nan::AsyncWorker(callback), baton(baton), buffersToPersist(buffersToPersist) { : Nan::AsyncWorker(callback), baton(baton), buffersToPersist(buffersToPersist) {
// Protect Buffer objects from GC, keyed on index // Protect Buffer objects from GC, keyed on index
std::accumulate(buffersToPersist.begin(), buffersToPersist.end(), 0, std::accumulate(buffersToPersist.begin(), buffersToPersist.end(), 0,
[this](uint32_t index, v8::Local<v8::Object> const buffer) -> uint32_t { [this](uint32_t index, v8::Local<v8::Object> const buffer) -> uint32_t {
SaveToPersistent(index, buffer); SaveToPersistent(index, buffer);
return index + 1; return index + 1;
} });
);
} }
~MetadataWorker() {} ~MetadataWorker() {}
@@ -72,7 +86,7 @@ class MetadataWorker : public Nan::AsyncWorker {
vips_thread_shutdown(); vips_thread_shutdown();
} }
void HandleOKCallback () { void HandleOKCallback() {
using Nan::New; using Nan::New;
using Nan::Set; using Nan::Set;
Nan::HandleScope(); Nan::HandleScope();
@@ -99,14 +113,12 @@ class MetadataWorker : public Nan::AsyncWorker {
if (baton->exifLength > 0) { if (baton->exifLength > 0) {
Set(info, Set(info,
New("exif").ToLocalChecked(), New("exif").ToLocalChecked(),
Nan::NewBuffer(baton->exif, baton->exifLength, sharp::FreeCallback, nullptr).ToLocalChecked() Nan::NewBuffer(baton->exif, baton->exifLength, sharp::FreeCallback, nullptr).ToLocalChecked());
);
} }
if (baton->iccLength > 0) { if (baton->iccLength > 0) {
Set(info, Set(info,
New("icc").ToLocalChecked(), New("icc").ToLocalChecked(),
Nan::NewBuffer(baton->icc, baton->iccLength, sharp::FreeCallback, nullptr).ToLocalChecked() Nan::NewBuffer(baton->icc, baton->iccLength, sharp::FreeCallback, nullptr).ToLocalChecked());
);
} }
argv[1] = info; argv[1] = info;
} }
@@ -116,8 +128,7 @@ class MetadataWorker : public Nan::AsyncWorker {
[this](uint32_t index, v8::Local<v8::Object> const buffer) -> uint32_t { [this](uint32_t index, v8::Local<v8::Object> const buffer) -> uint32_t {
GetFromPersistent(index); GetFromPersistent(index);
return index + 1; return index + 1;
} });
);
delete baton->input; delete baton->input;
delete baton; delete baton;

View File

@@ -1,8 +1,24 @@
// Copyright 2013, 2014, 2015, 2016, 2017 Lovell Fuller and contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_METADATA_H_ #ifndef SRC_METADATA_H_
#define SRC_METADATA_H_ #define SRC_METADATA_H_
#include "nan.h" #include <string>
#include "common.h" #include <nan.h>
#include "./common.h"
struct MetadataBaton { struct MetadataBaton {
// Input // Input

View File

@@ -1,7 +1,23 @@
// Copyright 2013, 2014, 2015, 2016, 2017 Lovell Fuller and contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <tuple> #include <tuple>
#include <vector>
#include <vips/vips8> #include <vips/vips8>
#include "common.h" #include "common.h"
@@ -17,7 +33,7 @@ namespace sharp {
Assumes alpha channels are already premultiplied and will be unpremultiplied after. Assumes alpha channels are already premultiplied and will be unpremultiplied after.
*/ */
VImage Composite(VImage src, VImage dst, const int gravity) { VImage Composite(VImage src, VImage dst, const int gravity) {
if(IsInputValidForComposition(src, dst)) { if (IsInputValidForComposition(src, dst)) {
// Enlarge overlay src, if required // Enlarge overlay src, if required
if (src.width() < dst.width() || src.height() < dst.height()) { if (src.width() < dst.width() || src.height() < dst.height()) {
// Calculate the (left, top) coordinates of the output image within the input image, applying the given gravity. // Calculate the (left, top) coordinates of the output image within the input image, applying the given gravity.
@@ -28,8 +44,7 @@ namespace sharp {
std::vector<double> background { 0.0, 0.0, 0.0, 0.0 }; std::vector<double> background { 0.0, 0.0, 0.0, 0.0 };
src = src.embed(left, top, dst.width(), dst.height(), VImage::option() src = src.embed(left, top, dst.width(), dst.height(), VImage::option()
->set("extend", VIPS_EXTEND_BACKGROUND) ->set("extend", VIPS_EXTEND_BACKGROUND)
->set("background", background) ->set("background", background));
);
} }
return CompositeImage(src, dst); return CompositeImage(src, dst);
} }
@@ -38,7 +53,7 @@ namespace sharp {
} }
VImage Composite(VImage src, VImage dst, const int x, const int y) { VImage Composite(VImage src, VImage dst, const int x, const int y) {
if(IsInputValidForComposition(src, dst)) { if (IsInputValidForComposition(src, dst)) {
// Enlarge overlay src, if required // Enlarge overlay src, if required
if (src.width() < dst.width() || src.height() < dst.height()) { if (src.width() < dst.width() || src.height() < dst.height()) {
// Calculate the (left, top) coordinates of the output image within the input image, applying the given gravity. // Calculate the (left, top) coordinates of the output image within the input image, applying the given gravity.
@@ -49,8 +64,7 @@ namespace sharp {
std::vector<double> background { 0.0, 0.0, 0.0, 0.0 }; std::vector<double> background { 0.0, 0.0, 0.0, 0.0 };
src = src.embed(left, top, dst.width(), dst.height(), VImage::option() src = src.embed(left, top, dst.width(), dst.height(), VImage::option()
->set("extend", VIPS_EXTEND_BACKGROUND) ->set("extend", VIPS_EXTEND_BACKGROUND)
->set("background", background) ->set("background", background));
);
} }
return CompositeImage(src, dst); return CompositeImage(src, dst);
} }
@@ -145,12 +159,11 @@ namespace sharp {
std::vector<double> background { 0.0, 0.0, 0.0, 0.0 }; std::vector<double> background { 0.0, 0.0, 0.0, 0.0 };
mask = mask.embed(left, top, dst.width(), dst.height(), VImage::option() mask = mask.embed(left, top, dst.width(), dst.height(), VImage::option()
->set("extend", VIPS_EXTEND_BACKGROUND) ->set("extend", VIPS_EXTEND_BACKGROUND)
->set("background", background) ->set("background", background));
);
} }
// we use the mask alpha if it has alpha // we use the mask alpha if it has alpha
if(maskHasAlpha) { if (maskHasAlpha) {
mask = mask.extract_band(mask.bands() - 1, VImage::option()->set("n", 1));; mask = mask.extract_band(mask.bands() - 1, VImage::option()->set("n", 1));;
} }
@@ -284,8 +297,8 @@ namespace sharp {
colourspaceBeforeSharpen = VIPS_INTERPRETATION_sRGB; colourspaceBeforeSharpen = VIPS_INTERPRETATION_sRGB;
} }
return image.sharpen( return image.sharpen(
VImage::option()->set("sigma", sigma)->set("m1", flat)->set("m2", jagged) VImage::option()->set("sigma", sigma)->set("m1", flat)->set("m2", jagged))
).colourspace(colourspaceBeforeSharpen); .colourspace(colourspaceBeforeSharpen);
} }
} }
@@ -415,12 +428,11 @@ namespace sharp {
->set("tile_height", 10) ->set("tile_height", 10)
->set("max_tiles", static_cast<int>(round(1.0 + need_lines / 10.0))) ->set("max_tiles", static_cast<int>(round(1.0 + need_lines / 10.0)))
->set("access", VIPS_ACCESS_SEQUENTIAL) ->set("access", VIPS_ACCESS_SEQUENTIAL)
->set("threaded", TRUE) ->set("threaded", TRUE));
);
} }
VImage Threshold(VImage image, double const threshold, bool const thresholdGrayscale) { VImage Threshold(VImage image, double const threshold, bool const thresholdGrayscale) {
if(!thresholdGrayscale) { if (!thresholdGrayscale) {
return image >= threshold; return image >= threshold;
} }
return image.colourspace(VIPS_INTERPRETATION_B_W) >= threshold; return image.colourspace(VIPS_INTERPRETATION_B_W) >= threshold;
@@ -485,7 +497,7 @@ namespace sharp {
int width = right - left; int width = right - left;
int height = bottom - top; int height = bottom - top;
if(width <= 0 || height <= 0) { if (width <= 0 || height <= 0) {
throw VError("Unexpected error while trimming. Try to lower the tolerance"); throw VError("Unexpected error while trimming. Try to lower the tolerance");
} }

View File

@@ -1,3 +1,17 @@
// Copyright 2013, 2014, 2015, 2016, 2017 Lovell Fuller and contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_OPERATIONS_H_ #ifndef SRC_OPERATIONS_H_
#define SRC_OPERATIONS_H_ #define SRC_OPERATIONS_H_
@@ -78,8 +92,7 @@ namespace sharp {
Calculate crop area based on given strategy (Entropy, Attention) Calculate crop area based on given strategy (Entropy, Attention)
*/ */
std::tuple<int, int> Crop( std::tuple<int, int> Crop(
VImage image, int const outWidth, int const outHeight, std::function<double(VImage)> strategy VImage image, int const outWidth, int const outHeight, std::function<double(VImage)> strategy);
);
/* /*
Insert a tile cache to prevent over-computation of any previous operations in the pipeline Insert a tile cache to prevent over-computation of any previous operations in the pipeline

View File

@@ -1,15 +1,31 @@
// Copyright 2013, 2014, 2015, 2016, 2017 Lovell Fuller and contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
#include <tuple> #include <map>
#include <utility>
#include <memory> #include <memory>
#include <numeric> #include <numeric>
#include <map> #include <string>
#include <tuple>
#include <utility>
#include <vector>
#include <vips/vips8> #include <vips/vips8>
#include <node.h> #include <node.h>
#include <nan.h>
#include "nan.h"
#include "common.h" #include "common.h"
#include "operations.h" #include "operations.h"
#include "pipeline.h" #include "pipeline.h"
@@ -18,15 +34,14 @@ class PipelineWorker : public Nan::AsyncWorker {
public: public:
PipelineWorker( PipelineWorker(
Nan::Callback *callback, PipelineBaton *baton, Nan::Callback *queueListener, Nan::Callback *callback, PipelineBaton *baton, Nan::Callback *queueListener,
std::vector<v8::Local<v8::Object>> const buffersToPersist std::vector<v8::Local<v8::Object>> const buffersToPersist)
) : Nan::AsyncWorker(callback), baton(baton), queueListener(queueListener), buffersToPersist(buffersToPersist) { : Nan::AsyncWorker(callback), baton(baton), queueListener(queueListener), buffersToPersist(buffersToPersist) {
// Protect Buffer objects from GC, keyed on index // Protect Buffer objects from GC, keyed on index
std::accumulate(buffersToPersist.begin(), buffersToPersist.end(), 0, std::accumulate(buffersToPersist.begin(), buffersToPersist.end(), 0,
[this](uint32_t index, v8::Local<v8::Object> const buffer) -> uint32_t { [this](uint32_t index, v8::Local<v8::Object> const buffer) -> uint32_t {
SaveToPersistent(index, buffer); SaveToPersistent(index, buffer);
return index + 1; return index + 1;
} });
);
} }
~PipelineWorker() {} ~PipelineWorker() {}
@@ -84,7 +99,7 @@ class PipelineWorker : public Nan::AsyncWorker {
} }
// Trim // Trim
if(baton->trimTolerance != 0) { if (baton->trimTolerance != 0) {
image = sharp::Trim(image, baton->trimTolerance); image = sharp::Trim(image, baton->trimTolerance);
} }
@@ -277,8 +292,7 @@ class PipelineWorker : public Nan::AsyncWorker {
image = image.icc_transform( image = image.icc_transform(
const_cast<char*>(profileMap[VIPS_INTERPRETATION_sRGB].data()), VImage::option() const_cast<char*>(profileMap[VIPS_INTERPRETATION_sRGB].data()), VImage::option()
->set("embedded", TRUE) ->set("embedded", TRUE)
->set("intent", VIPS_INTENT_PERCEPTUAL) ->set("intent", VIPS_INTENT_PERCEPTUAL));
);
} catch(...) { } catch(...) {
// Ignore failure of embedded profile // Ignore failure of embedded profile
} }
@@ -286,8 +300,7 @@ class PipelineWorker : public Nan::AsyncWorker {
image = image.icc_transform( image = image.icc_transform(
const_cast<char*>(profileMap[VIPS_INTERPRETATION_sRGB].data()), VImage::option() const_cast<char*>(profileMap[VIPS_INTERPRETATION_sRGB].data()), VImage::option()
->set("input_profile", profileMap[VIPS_INTERPRETATION_CMYK].data()) ->set("input_profile", profileMap[VIPS_INTERPRETATION_CMYK].data())
->set("intent", VIPS_INTENT_PERCEPTUAL) ->set("intent", VIPS_INTENT_PERCEPTUAL));
);
} }
// Flatten image to remove alpha channel // Flatten image to remove alpha channel
@@ -301,8 +314,7 @@ class PipelineWorker : public Nan::AsyncWorker {
baton->background[2] * multiplier baton->background[2] * multiplier
}; };
image = image.flatten(VImage::option() image = image.flatten(VImage::option()
->set("background", background) ->set("background", background));
);
} }
// Negate the colours in the image // Negate the colours in the image
@@ -325,8 +337,7 @@ class PipelineWorker : public Nan::AsyncWorker {
if (hasOverlay && !HasAlpha(image)) { if (hasOverlay && !HasAlpha(image)) {
double const multiplier = sharp::Is16Bit(image.interpretation()) ? 256.0 : 1.0; double const multiplier = sharp::Is16Bit(image.interpretation()) ? 256.0 : 1.0;
image = image.bandjoin( image = image.bandjoin(
VImage::new_matrix(image.width(), image.height()).new_from_image(255 * multiplier) VImage::new_matrix(image.width(), image.height()).new_from_image(255 * multiplier));
);
} }
bool const shouldShrink = xshrink > 1 || yshrink > 1; bool const shouldShrink = xshrink > 1 || yshrink > 1;
@@ -380,22 +391,19 @@ class PipelineWorker : public Nan::AsyncWorker {
// Perform kernel-based reduction // Perform kernel-based reduction
if (yresidual < 1.0 || xresidual < 1.0) { if (yresidual < 1.0 || xresidual < 1.0) {
VipsKernel kernel = static_cast<VipsKernel>( VipsKernel kernel = static_cast<VipsKernel>(
vips_enum_from_nick(nullptr, VIPS_TYPE_KERNEL, baton->kernel.data()) vips_enum_from_nick(nullptr, VIPS_TYPE_KERNEL, baton->kernel.data()));
);
if (kernel != VIPS_KERNEL_CUBIC && kernel != VIPS_KERNEL_LANCZOS2 && kernel != VIPS_KERNEL_LANCZOS3) { if (kernel != VIPS_KERNEL_CUBIC && kernel != VIPS_KERNEL_LANCZOS2 && kernel != VIPS_KERNEL_LANCZOS3) {
throw vips::VError("Unknown kernel"); throw vips::VError("Unknown kernel");
} }
if (yresidual < 1.0) { if (yresidual < 1.0) {
image = image.reducev(1.0 / yresidual, VImage::option() image = image.reducev(1.0 / yresidual, VImage::option()
->set("kernel", kernel) ->set("kernel", kernel)
->set("centre", baton->centreSampling) ->set("centre", baton->centreSampling));
);
} }
if (xresidual < 1.0) { if (xresidual < 1.0) {
image = image.reduceh(1.0 / xresidual, VImage::option() image = image.reduceh(1.0 / xresidual, VImage::option()
->set("kernel", kernel) ->set("kernel", kernel)
->set("centre", baton->centreSampling) ->set("centre", baton->centreSampling));
);
} }
} }
// Perform affine enlargement // Perform affine enlargement
@@ -403,13 +411,11 @@ class PipelineWorker : public Nan::AsyncWorker {
vips::VInterpolate interpolator = vips::VInterpolate::new_from_name(baton->interpolator.data()); vips::VInterpolate interpolator = vips::VInterpolate::new_from_name(baton->interpolator.data());
if (yresidual > 1.0) { if (yresidual > 1.0) {
image = image.affine({1.0, 0.0, 0.0, yresidual}, VImage::option() image = image.affine({1.0, 0.0, 0.0, yresidual}, VImage::option()
->set("interpolate", interpolator) ->set("interpolate", interpolator));
);
} }
if (xresidual > 1.0) { if (xresidual > 1.0) {
image = image.affine({xresidual, 0.0, 0.0, 1.0}, VImage::option() image = image.affine({xresidual, 0.0, 0.0, 1.0}, VImage::option()
->set("interpolate", interpolator) ->set("interpolate", interpolator));
);
} }
} }
} }
@@ -433,13 +439,12 @@ class PipelineWorker : public Nan::AsyncWorker {
} }
// Join additional color channels to the image // Join additional color channels to the image
if(baton->joinChannelIn.size() > 0) { if (baton->joinChannelIn.size() > 0) {
VImage joinImage; VImage joinImage;
ImageType joinImageType = ImageType::UNKNOWN; ImageType joinImageType = ImageType::UNKNOWN;
for(unsigned int i = 0; i < baton->joinChannelIn.size(); i++) { for (unsigned int i = 0; i < baton->joinChannelIn.size(); i++) {
std::tie(joinImage, joinImageType) = sharp::OpenInput(baton->joinChannelIn[i], baton->accessMethod); std::tie(joinImage, joinImageType) = sharp::OpenInput(baton->joinChannelIn[i], baton->accessMethod);
image = image.bandjoin(joinImage); image = image.bandjoin(joinImage);
} }
image = image.copy(VImage::option()->set("interpretation", baton->colourspace)); image = image.copy(VImage::option()->set("interpretation", baton->colourspace));
@@ -463,8 +468,8 @@ class PipelineWorker : public Nan::AsyncWorker {
background = { multiplier * ( background = { multiplier * (
0.2126 * baton->background[0] + 0.2126 * baton->background[0] +
0.7152 * baton->background[1] + 0.7152 * baton->background[1] +
0.0722 * baton->background[2] 0.0722 * baton->background[2])
)}; };
} }
// Add alpha channel to background colour // Add alpha channel to background colour
if (baton->background[3] < 255.0 || HasAlpha(image)) { if (baton->background[3] < 255.0 || HasAlpha(image)) {
@@ -475,16 +480,14 @@ class PipelineWorker : public Nan::AsyncWorker {
// Add non-transparent alpha channel, if required // Add non-transparent alpha channel, if required
if (baton->background[3] < 255.0 && !HasAlpha(image)) { if (baton->background[3] < 255.0 && !HasAlpha(image)) {
image = image.bandjoin( image = image.bandjoin(
VImage::new_matrix(image.width(), image.height()).new_from_image(255 * multiplier) VImage::new_matrix(image.width(), image.height()).new_from_image(255 * multiplier));
);
} }
// Embed // Embed
int left = static_cast<int>(round((baton->width - image.width()) / 2)); int left = static_cast<int>(round((baton->width - image.width()) / 2));
int top = static_cast<int>(round((baton->height - image.height()) / 2)); int top = static_cast<int>(round((baton->height - image.height()) / 2));
image = image.embed(left, top, baton->width, baton->height, VImage::option() image = image.embed(left, top, baton->width, baton->height, VImage::option()
->set("extend", VIPS_EXTEND_BACKGROUND) ->set("extend", VIPS_EXTEND_BACKGROUND)
->set("background", background) ->set("background", background));
);
} else if (baton->canvas != Canvas::IGNORE_ASPECT) { } else if (baton->canvas != Canvas::IGNORE_ASPECT) {
// Crop/max/min // Crop/max/min
int left; int left;
@@ -492,8 +495,7 @@ class PipelineWorker : public Nan::AsyncWorker {
if (baton->crop < 9) { if (baton->crop < 9) {
// Gravity-based crop // Gravity-based crop
std::tie(left, top) = sharp::CalculateCrop( std::tie(left, top) = sharp::CalculateCrop(
image.width(), image.height(), baton->width, baton->height, baton->crop image.width(), image.height(), baton->width, baton->height, baton->crop);
);
} else if (baton->crop == 16) { } else if (baton->crop == 16) {
// Entropy-based crop // Entropy-based crop
std::tie(left, top) = sharp::Crop(image, baton->width, baton->height, sharp::EntropyStrategy()); std::tie(left, top) = sharp::Crop(image, baton->width, baton->height, sharp::EntropyStrategy());
@@ -512,8 +514,7 @@ class PipelineWorker : public Nan::AsyncWorker {
// Post extraction // Post extraction
if (baton->topOffsetPost != -1) { if (baton->topOffsetPost != -1) {
image = image.extract_area( image = image.extract_area(
baton->leftOffsetPost, baton->topOffsetPost, baton->widthPost, baton->heightPost baton->leftOffsetPost, baton->topOffsetPost, baton->widthPost, baton->heightPost);
);
} }
// Extend edges // Extend edges
@@ -533,8 +534,8 @@ class PipelineWorker : public Nan::AsyncWorker {
background = { multiplier * ( background = { multiplier * (
0.2126 * baton->background[0] + 0.2126 * baton->background[0] +
0.7152 * baton->background[1] + 0.7152 * baton->background[1] +
0.0722 * baton->background[2] 0.0722 * baton->background[2])
)}; };
} }
// Add alpha channel to background colour // Add alpha channel to background colour
if (baton->background[3] < 255.0 || HasAlpha(image)) { if (baton->background[3] < 255.0 || HasAlpha(image)) {
@@ -545,8 +546,7 @@ class PipelineWorker : public Nan::AsyncWorker {
// Add non-transparent alpha channel, if required // Add non-transparent alpha channel, if required
if (baton->background[3] < 255.0 && !HasAlpha(image)) { if (baton->background[3] < 255.0 && !HasAlpha(image)) {
image = image.bandjoin( image = image.bandjoin(
VImage::new_matrix(image.width(), image.height()).new_from_image(255 * multiplier) VImage::new_matrix(image.width(), image.height()).new_from_image(255 * multiplier));
);
} }
// Embed // Embed
baton->width = image.width() + baton->extendLeft + baton->extendRight; baton->width = image.width() + baton->extendLeft + baton->extendRight;
@@ -571,8 +571,7 @@ class PipelineWorker : public Nan::AsyncWorker {
image = sharp::Convolve(image, image = sharp::Convolve(image,
baton->convKernelWidth, baton->convKernelHeight, baton->convKernelWidth, baton->convKernelHeight,
baton->convKernelScale, baton->convKernelOffset, baton->convKernelScale, baton->convKernelOffset,
baton->convKernel baton->convKernel);
);
} }
// Sharpen // Sharpen
@@ -606,17 +605,13 @@ class PipelineWorker : public Nan::AsyncWorker {
// the overlayX/YOffsets will now be used to CalculateCrop for extract_area // the overlayX/YOffsets will now be used to CalculateCrop for extract_area
std::tie(left, top) = sharp::CalculateCrop( std::tie(left, top) = sharp::CalculateCrop(
overlayImage.width(), overlayImage.height(), image.width(), image.height(), overlayImage.width(), overlayImage.height(), image.width(), image.height(),
baton->overlayXOffset, baton->overlayYOffset baton->overlayXOffset, baton->overlayYOffset);
);
} else { } else {
// the overlayGravity will now be used to CalculateCrop for extract_area // the overlayGravity will now be used to CalculateCrop for extract_area
std::tie(left, top) = sharp::CalculateCrop( std::tie(left, top) = sharp::CalculateCrop(
overlayImage.width(), overlayImage.height(), image.width(), image.height(), baton->overlayGravity overlayImage.width(), overlayImage.height(), image.width(), image.height(), baton->overlayGravity);
);
} }
overlayImage = overlayImage.extract_area( overlayImage = overlayImage.extract_area(left, top, image.width(), image.height());
left, top, image.width(), image.height()
);
} }
// the overlayGravity was used for extract_area, therefore set it back to its default value of 0 // the overlayGravity was used for extract_area, therefore set it back to its default value of 0
baton->overlayGravity = 0; baton->overlayGravity = 0;
@@ -629,15 +624,13 @@ class PipelineWorker : public Nan::AsyncWorker {
if (!HasAlpha(overlayImage)) { if (!HasAlpha(overlayImage)) {
double const multiplier = sharp::Is16Bit(overlayImage.interpretation()) ? 256.0 : 1.0; double const multiplier = sharp::Is16Bit(overlayImage.interpretation()) ? 256.0 : 1.0;
overlayImage = overlayImage.bandjoin( overlayImage = overlayImage.bandjoin(
VImage::new_matrix(overlayImage.width(), overlayImage.height()).new_from_image(255 * multiplier) VImage::new_matrix(overlayImage.width(), overlayImage.height()).new_from_image(255 * multiplier));
);
} }
// Ensure image has alpha channel // Ensure image has alpha channel
if (!HasAlpha(image)) { if (!HasAlpha(image)) {
double const multiplier = sharp::Is16Bit(image.interpretation()) ? 256.0 : 1.0; double const multiplier = sharp::Is16Bit(image.interpretation()) ? 256.0 : 1.0;
image = image.bandjoin( image = image.bandjoin(
VImage::new_matrix(image.width(), image.height()).new_from_image(255 * multiplier) VImage::new_matrix(image.width(), image.height()).new_from_image(255 * multiplier));
);
} }
// Ensure overlay is premultiplied sRGB // Ensure overlay is premultiplied sRGB
overlayImage = overlayImage.colourspace(VIPS_INTERPRETATION_sRGB).premultiply(); overlayImage = overlayImage.colourspace(VIPS_INTERPRETATION_sRGB).premultiply();
@@ -686,8 +679,8 @@ class PipelineWorker : public Nan::AsyncWorker {
} }
// Extract an image channel (aka vips band) // Extract an image channel (aka vips band)
if(baton->extractChannel > -1) { if (baton->extractChannel > -1) {
if(baton->extractChannel >= image.bands()) { if (baton->extractChannel >= image.bands()) {
(baton->err).append("Cannot extract channel from image. Too few channels in image."); (baton->err).append("Cannot extract channel from image. Too few channels in image.");
return Error(); return Error();
} }
@@ -701,12 +694,9 @@ class PipelineWorker : public Nan::AsyncWorker {
// Convert colourspace, pass the current known interpretation so libvips doesn't have to guess // Convert colourspace, pass the current known interpretation so libvips doesn't have to guess
image = image.colourspace(baton->colourspace, VImage::option()->set("source_space", image.interpretation())); image = image.colourspace(baton->colourspace, VImage::option()->set("source_space", image.interpretation()));
// Transform colours from embedded profile to output profile // Transform colours from embedded profile to output profile
if (baton->withMetadata && if (baton->withMetadata && sharp::HasProfile(image) && profileMap[baton->colourspace] != std::string()) {
sharp::HasProfile(image) &&
profileMap[baton->colourspace] != std::string()) {
image = image.icc_transform(const_cast<char*>(profileMap[baton->colourspace].data()), image = image.icc_transform(const_cast<char*>(profileMap[baton->colourspace].data()),
VImage::option()->set("embedded", TRUE) VImage::option()->set("embedded", TRUE));
);
} }
} }
@@ -732,14 +722,13 @@ class PipelineWorker : public Nan::AsyncWorker {
->set("trellis_quant", baton->jpegTrellisQuantisation) ->set("trellis_quant", baton->jpegTrellisQuantisation)
->set("overshoot_deringing", baton->jpegOvershootDeringing) ->set("overshoot_deringing", baton->jpegOvershootDeringing)
->set("optimize_scans", baton->jpegOptimiseScans) ->set("optimize_scans", baton->jpegOptimiseScans)
->set("optimize_coding", TRUE) ->set("optimize_coding", TRUE)));
));
baton->bufferOut = static_cast<char*>(area->data); baton->bufferOut = static_cast<char*>(area->data);
baton->bufferOutLength = area->length; baton->bufferOutLength = area->length;
area->free_fn = nullptr; area->free_fn = nullptr;
vips_area_unref(area); vips_area_unref(area);
baton->formatOut = "jpeg"; baton->formatOut = "jpeg";
if(baton->colourspace == VIPS_INTERPRETATION_CMYK) { if (baton->colourspace == VIPS_INTERPRETATION_CMYK) {
baton->channels = std::min(baton->channels, 4); baton->channels = std::min(baton->channels, 4);
} else { } else {
baton->channels = std::min(baton->channels, 3); baton->channels = std::min(baton->channels, 3);
@@ -754,9 +743,7 @@ class PipelineWorker : public Nan::AsyncWorker {
VipsArea *area = VIPS_AREA(image.pngsave_buffer(VImage::option() VipsArea *area = VIPS_AREA(image.pngsave_buffer(VImage::option()
->set("interlace", baton->pngProgressive) ->set("interlace", baton->pngProgressive)
->set("compression", baton->pngCompressionLevel) ->set("compression", baton->pngCompressionLevel)
->set("filter", baton->pngAdaptiveFiltering ? ->set("filter", baton->pngAdaptiveFiltering ? VIPS_FOREIGN_PNG_FILTER_ALL : VIPS_FOREIGN_PNG_FILTER_NONE)));
VIPS_FOREIGN_PNG_FILTER_ALL : VIPS_FOREIGN_PNG_FILTER_NONE )
));
baton->bufferOut = static_cast<char*>(area->data); baton->bufferOut = static_cast<char*>(area->data);
baton->bufferOutLength = area->length; baton->bufferOutLength = area->length;
area->free_fn = nullptr; area->free_fn = nullptr;
@@ -767,7 +754,9 @@ class PipelineWorker : public Nan::AsyncWorker {
VipsArea *area = VIPS_AREA(image.webpsave_buffer(VImage::option() VipsArea *area = VIPS_AREA(image.webpsave_buffer(VImage::option()
->set("strip", !baton->withMetadata) ->set("strip", !baton->withMetadata)
->set("Q", baton->webpQuality) ->set("Q", baton->webpQuality)
)); ->set("lossless", baton->webpLossless)
->set("near_lossless", baton->webpNearLossless)
->set("alpha_q", baton->webpAlphaQuality)));
baton->bufferOut = static_cast<char*>(area->data); baton->bufferOut = static_cast<char*>(area->data);
baton->bufferOutLength = area->length; baton->bufferOutLength = area->length;
area->free_fn = nullptr; area->free_fn = nullptr;
@@ -821,8 +810,7 @@ class PipelineWorker : public Nan::AsyncWorker {
->set("trellis_quant", baton->jpegTrellisQuantisation) ->set("trellis_quant", baton->jpegTrellisQuantisation)
->set("overshoot_deringing", baton->jpegOvershootDeringing) ->set("overshoot_deringing", baton->jpegOvershootDeringing)
->set("optimize_scans", baton->jpegOptimiseScans) ->set("optimize_scans", baton->jpegOptimiseScans)
->set("optimize_coding", TRUE) ->set("optimize_coding", TRUE));
);
baton->formatOut = "jpeg"; baton->formatOut = "jpeg";
baton->channels = std::min(baton->channels, 3); baton->channels = std::min(baton->channels, 3);
} else if (baton->formatOut == "png" || isPng || (matchInput && } else if (baton->formatOut == "png" || isPng || (matchInput &&
@@ -835,24 +823,23 @@ class PipelineWorker : public Nan::AsyncWorker {
image.pngsave(const_cast<char*>(baton->fileOut.data()), VImage::option() image.pngsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
->set("interlace", baton->pngProgressive) ->set("interlace", baton->pngProgressive)
->set("compression", baton->pngCompressionLevel) ->set("compression", baton->pngCompressionLevel)
->set("filter", baton->pngAdaptiveFiltering ? ->set("filter", baton->pngAdaptiveFiltering ? VIPS_FOREIGN_PNG_FILTER_ALL : VIPS_FOREIGN_PNG_FILTER_NONE));
VIPS_FOREIGN_PNG_FILTER_ALL : VIPS_FOREIGN_PNG_FILTER_NONE )
);
baton->formatOut = "png"; baton->formatOut = "png";
} else if (baton->formatOut == "webp" || isWebp || (matchInput && inputImageType == ImageType::WEBP)) { } else if (baton->formatOut == "webp" || isWebp || (matchInput && inputImageType == ImageType::WEBP)) {
// Write WEBP to file // Write WEBP to file
image.webpsave(const_cast<char*>(baton->fileOut.data()), VImage::option() image.webpsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
->set("strip", !baton->withMetadata) ->set("strip", !baton->withMetadata)
->set("Q", baton->webpQuality) ->set("Q", baton->webpQuality)
); ->set("lossless", baton->webpLossless)
->set("near_lossless", baton->webpNearLossless)
->set("alpha_q", baton->webpAlphaQuality));
baton->formatOut = "webp"; baton->formatOut = "webp";
} else if (baton->formatOut == "tiff" || isTiff || (matchInput && inputImageType == ImageType::TIFF)) { } else if (baton->formatOut == "tiff" || isTiff || (matchInput && inputImageType == ImageType::TIFF)) {
// Write TIFF to file // Write TIFF to file
image.tiffsave(const_cast<char*>(baton->fileOut.data()), VImage::option() image.tiffsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
->set("strip", !baton->withMetadata) ->set("strip", !baton->withMetadata)
->set("Q", baton->tiffQuality) ->set("Q", baton->tiffQuality)
->set("compression", VIPS_FOREIGN_TIFF_COMPRESSION_JPEG) ->set("compression", VIPS_FOREIGN_TIFF_COMPRESSION_JPEG));
);
baton->formatOut = "tiff"; baton->formatOut = "tiff";
baton->channels = std::min(baton->channels, 3); baton->channels = std::min(baton->channels, 3);
} else if (baton->formatOut == "dz" || isDz || isDzZip) { } else if (baton->formatOut == "dz" || isDz || isDzZip) {
@@ -870,7 +857,10 @@ class PipelineWorker : public Nan::AsyncWorker {
suffix = AssembleSuffixString(".png", options); suffix = AssembleSuffixString(".png", options);
} else if (baton->tileFormat == "webp") { } else if (baton->tileFormat == "webp") {
std::vector<std::pair<std::string, std::string>> options { std::vector<std::pair<std::string, std::string>> options {
{"Q", std::to_string(baton->webpQuality)} {"Q", std::to_string(baton->webpQuality)},
{"alpha_q", std::to_string(baton->webpAlphaQuality)},
{"lossless", baton->webpLossless ? "TRUE" : "FALSE"},
{"near_lossless", baton->webpNearLossless ? "TRUE" : "FALSE"}
}; };
suffix = AssembleSuffixString(".webp", options); suffix = AssembleSuffixString(".webp", options);
} else { } else {
@@ -895,14 +885,12 @@ class PipelineWorker : public Nan::AsyncWorker {
->set("overlap", baton->tileOverlap) ->set("overlap", baton->tileOverlap)
->set("container", baton->tileContainer) ->set("container", baton->tileContainer)
->set("layout", baton->tileLayout) ->set("layout", baton->tileLayout)
->set("suffix", const_cast<char*>(suffix.data())) ->set("suffix", const_cast<char*>(suffix.data())));
);
baton->formatOut = "dz"; baton->formatOut = "dz";
} else if (baton->formatOut == "v" || isV || (matchInput && inputImageType == ImageType::VIPS)) { } else if (baton->formatOut == "v" || isV || (matchInput && inputImageType == ImageType::VIPS)) {
// Write V to file // Write V to file
image.vipssave(const_cast<char*>(baton->fileOut.data()), VImage::option() image.vipssave(const_cast<char*>(baton->fileOut.data()), VImage::option()
->set("strip", !baton->withMetadata) ->set("strip", !baton->withMetadata));
);
baton->formatOut = "v"; baton->formatOut = "v";
} else { } else {
// Unsupported output format // Unsupported output format
@@ -918,7 +906,7 @@ class PipelineWorker : public Nan::AsyncWorker {
vips_thread_shutdown(); vips_thread_shutdown();
} }
void HandleOKCallback () { void HandleOKCallback() {
using Nan::New; using Nan::New;
using Nan::Set; using Nan::Set;
Nan::HandleScope(); Nan::HandleScope();
@@ -952,8 +940,8 @@ class PipelineWorker : public Nan::AsyncWorker {
if (baton->bufferOutLength > 0) { if (baton->bufferOutLength > 0) {
// Pass ownership of output data to Buffer instance // Pass ownership of output data to Buffer instance
argv[1] = Nan::NewBuffer( argv[1] = Nan::NewBuffer(
static_cast<char*>(baton->bufferOut), baton->bufferOutLength, sharp::FreeCallback, nullptr static_cast<char*>(baton->bufferOut), baton->bufferOutLength, sharp::FreeCallback, nullptr)
).ToLocalChecked(); .ToLocalChecked();
// Add buffer size to info // Add buffer size to info
Set(info, New("size").ToLocalChecked(), New<v8::Uint32>(static_cast<uint32_t>(baton->bufferOutLength))); Set(info, New("size").ToLocalChecked(), New<v8::Uint32>(static_cast<uint32_t>(baton->bufferOutLength)));
argv[2] = info; argv[2] = info;
@@ -972,16 +960,14 @@ class PipelineWorker : public Nan::AsyncWorker {
[this](uint32_t index, v8::Local<v8::Object> const buffer) -> uint32_t { [this](uint32_t index, v8::Local<v8::Object> const buffer) -> uint32_t {
GetFromPersistent(index); GetFromPersistent(index);
return index + 1; return index + 1;
} });
);
delete baton->input; delete baton->input;
delete baton->overlay; delete baton->overlay;
delete baton->boolean; delete baton->boolean;
for_each(baton->joinChannelIn.begin(), baton->joinChannelIn.end(), for_each(baton->joinChannelIn.begin(), baton->joinChannelIn.end(),
[this](sharp::InputDescriptor *joinChannelIn) { [this](sharp::InputDescriptor *joinChannelIn) {
delete joinChannelIn; delete joinChannelIn;
} });
);
delete baton; delete baton;
// Decrement processing task counter // Decrement processing task counter
@@ -1012,7 +998,7 @@ class PipelineWorker : public Nan::AsyncWorker {
bool flip = FALSE; bool flip = FALSE;
bool flop = FALSE; bool flop = FALSE;
if (angle == -1) { if (angle == -1) {
switch(sharp::ExifOrientation(image)) { switch (sharp::ExifOrientation(image)) {
case 6: rotate = VIPS_ANGLE_D90; break; case 6: rotate = VIPS_ANGLE_D90; break;
case 3: rotate = VIPS_ANGLE_D180; break; case 3: rotate = VIPS_ANGLE_D180; break;
case 8: rotate = VIPS_ANGLE_D270; break; case 8: rotate = VIPS_ANGLE_D270; break;
@@ -1132,12 +1118,12 @@ NAN_METHOD(pipeline) {
baton->interpolator = AttrAsStr(options, "interpolator"); baton->interpolator = AttrAsStr(options, "interpolator");
baton->centreSampling = AttrTo<bool>(options, "centreSampling"); baton->centreSampling = AttrTo<bool>(options, "centreSampling");
// Join Channel Options // Join Channel Options
if(HasAttr(options, "joinChannelIn")) { if (HasAttr(options, "joinChannelIn")) {
v8::Local<v8::Object> joinChannelObject = Nan::Get(options, Nan::New("joinChannelIn").ToLocalChecked()) v8::Local<v8::Object> joinChannelObject = Nan::Get(options, Nan::New("joinChannelIn").ToLocalChecked())
.ToLocalChecked().As<v8::Object>(); .ToLocalChecked().As<v8::Object>();
v8::Local<v8::Array> joinChannelArray = joinChannelObject.As<v8::Array>(); v8::Local<v8::Array> joinChannelArray = joinChannelObject.As<v8::Array>();
int joinChannelArrayLength = AttrTo<int32_t>(joinChannelObject, "length"); int joinChannelArrayLength = AttrTo<int32_t>(joinChannelObject, "length");
for(int i = 0; i < joinChannelArrayLength; i++) { for (int i = 0; i < joinChannelArrayLength; i++) {
baton->joinChannelIn.push_back( baton->joinChannelIn.push_back(
CreateInputDescriptor( CreateInputDescriptor(
Nan::Get(joinChannelArray, i).ToLocalChecked().As<v8::Object>(), Nan::Get(joinChannelArray, i).ToLocalChecked().As<v8::Object>(),
@@ -1154,7 +1140,7 @@ NAN_METHOD(pipeline) {
baton->threshold = AttrTo<int32_t>(options, "threshold"); baton->threshold = AttrTo<int32_t>(options, "threshold");
baton->thresholdGrayscale = AttrTo<bool>(options, "thresholdGrayscale"); baton->thresholdGrayscale = AttrTo<bool>(options, "thresholdGrayscale");
baton->trimTolerance = AttrTo<int32_t>(options, "trimTolerance"); baton->trimTolerance = AttrTo<int32_t>(options, "trimTolerance");
if(baton->accessMethod == VIPS_ACCESS_SEQUENTIAL && baton->trimTolerance != 0) { if (baton->accessMethod == VIPS_ACCESS_SEQUENTIAL && baton->trimTolerance != 0) {
baton->accessMethod = VIPS_ACCESS_RANDOM; baton->accessMethod = VIPS_ACCESS_RANDOM;
} }
baton->gamma = AttrTo<double>(options, "gamma"); baton->gamma = AttrTo<double>(options, "gamma");
@@ -1209,6 +1195,9 @@ NAN_METHOD(pipeline) {
baton->pngCompressionLevel = AttrTo<uint32_t>(options, "pngCompressionLevel"); baton->pngCompressionLevel = AttrTo<uint32_t>(options, "pngCompressionLevel");
baton->pngAdaptiveFiltering = AttrTo<bool>(options, "pngAdaptiveFiltering"); baton->pngAdaptiveFiltering = AttrTo<bool>(options, "pngAdaptiveFiltering");
baton->webpQuality = AttrTo<uint32_t>(options, "webpQuality"); baton->webpQuality = AttrTo<uint32_t>(options, "webpQuality");
baton->webpAlphaQuality = AttrTo<uint32_t>(options, "webpAlphaQuality");
baton->webpLossless = AttrTo<bool>(options, "webpLossless");
baton->webpNearLossless = AttrTo<bool>(options, "webpNearLossless");
baton->tiffQuality = AttrTo<uint32_t>(options, "tiffQuality"); baton->tiffQuality = AttrTo<uint32_t>(options, "tiffQuality");
// Tile output // Tile output
baton->tileSize = AttrTo<uint32_t>(options, "tileSize"); baton->tileSize = AttrTo<uint32_t>(options, "tileSize");

View File

@@ -1,12 +1,28 @@
// Copyright 2013, 2014, 2015, 2016, 2017 Lovell Fuller and contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_PIPELINE_H_ #ifndef SRC_PIPELINE_H_
#define SRC_PIPELINE_H_ #define SRC_PIPELINE_H_
#include <memory> #include <memory>
#include <string>
#include <vector>
#include <nan.h>
#include <vips/vips8> #include <vips/vips8>
#include "nan.h" #include "./common.h"
#include "common.h"
NAN_METHOD(pipeline); NAN_METHOD(pipeline);
@@ -84,6 +100,9 @@ struct PipelineBaton {
int pngCompressionLevel; int pngCompressionLevel;
bool pngAdaptiveFiltering; bool pngAdaptiveFiltering;
int webpQuality; int webpQuality;
int webpAlphaQuality;
bool webpNearLossless;
bool webpLossless;
int tiffQuality; int tiffQuality;
std::string err; std::string err;
bool withMetadata; bool withMetadata;

View File

@@ -1,7 +1,20 @@
#include <node.h> // Copyright 2013, 2014, 2015, 2016, 2017 Lovell Fuller and contributors.
#include <vips/vips8> //
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "nan.h" #include <node.h>
#include <nan.h>
#include <vips/vips8>
#include "common.h" #include "common.h"
#include "metadata.h" #include "metadata.h"

View File

@@ -1,10 +1,25 @@
// Copyright 2013, 2014, 2015, 2016, 2017 Lovell Fuller and contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cmath> #include <cmath>
#include <string>
#include <node.h> #include <node.h>
#include <nan.h>
#include <vips/vips8> #include <vips/vips8>
#include <vips/vector.h> #include <vips/vector.h>
#include "nan.h"
#include "common.h" #include "common.h"
#include "operations.h" #include "operations.h"
#include "utilities.h" #include "utilities.h"
@@ -45,14 +60,11 @@ NAN_METHOD(cache) {
// Get memory stats // Get memory stats
Local<Object> memory = New<Object>(); Local<Object> memory = New<Object>();
Set(memory, New("current").ToLocalChecked(), Set(memory, New("current").ToLocalChecked(),
New<Integer>(static_cast<int>(round(vips_tracked_get_mem() / 1048576))) New<Integer>(static_cast<int>(round(vips_tracked_get_mem() / 1048576))));
);
Set(memory, New("high").ToLocalChecked(), Set(memory, New("high").ToLocalChecked(),
New<Integer>(static_cast<int>(round(vips_tracked_get_mem_highwater() / 1048576))) New<Integer>(static_cast<int>(round(vips_tracked_get_mem_highwater() / 1048576))));
);
Set(memory, New("max").ToLocalChecked(), Set(memory, New("max").ToLocalChecked(),
New<Integer>(static_cast<int>(round(vips_cache_get_max_mem() / 1048576))) New<Integer>(static_cast<int>(round(vips_cache_get_max_mem() / 1048576))));
);
// Get file stats // Get file stats
Local<Object> files = New<Object>(); Local<Object> files = New<Object>();
Set(files, New("current").ToLocalChecked(), New<Integer>(vips_tracked_get_files())); Set(files, New("current").ToLocalChecked(), New<Integer>(vips_tracked_get_files()));

View File

@@ -1,7 +1,21 @@
// Copyright 2013, 2014, 2015, 2016, 2017 Lovell Fuller and contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_UTILITIES_H_ #ifndef SRC_UTILITIES_H_
#define SRC_UTILITIES_H_ #define SRC_UTILITIES_H_
#include "nan.h" #include <nan.h>
NAN_METHOD(cache); NAN_METHOD(cache);
NAN_METHOD(concurrency); NAN_METHOD(concurrency);

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

View File

@@ -1,48 +0,0 @@
'use strict';
const fs = require('fs');
const path = require('path');
const assert = require('assert');
const cpplint = require('node-cpplint/lib/');
describe('cpplint', function () {
// Ignore cpplint failures, possibly newline-related, on Windows
if (process.platform !== 'win32') {
// List C++ source files
fs.readdirSync(path.join(__dirname, '..', '..', 'src')).filter(function (source) {
return source !== 'libvips';
}).forEach(function (source) {
const file = path.join('src', source);
it(file, function (done) {
// Lint each source file
cpplint({
files: [file],
linelength: 120,
filters: {
legal: {
copyright: false
},
build: {
include: false
},
whitespace: {
parens: false
},
runtime: {
indentation_namespace: false
}
}
}, function (err, report) {
if (err) {
throw err;
}
const expected = {};
expected[file] = [];
assert.deepEqual(expected, report);
done();
});
});
});
}
});

View File

@@ -141,16 +141,16 @@ describe('Crop', function () {
it('Invalid values fail', function () { it('Invalid values fail', function () {
assert.throws(function () { assert.throws(function () {
sharp().crop(9); sharp().crop(9);
}); }, /Expected valid crop id\/name\/strategy for crop but received 9 of type number/);
assert.throws(function () { assert.throws(function () {
sharp().crop(1.1); sharp().crop(1.1);
}); }, /Expected valid crop id\/name\/strategy for crop but received 1.1 of type number/);
assert.throws(function () { assert.throws(function () {
sharp().crop(-1); sharp().crop(-1);
}); }, /Expected valid crop id\/name\/strategy for crop but received -1 of type number/);
assert.throws(function () { assert.throws(function () {
sharp().crop('zoinks'); sharp().crop('zoinks');
}); }, /Expected valid crop id\/name\/strategy for crop but received zoinks of type string/);
}); });
it('Uses default value when none specified', function () { it('Uses default value when none specified', function () {

View File

@@ -157,6 +157,28 @@ describe('Input/output', function () {
readableButNotAnImage.pipe(writable); readableButNotAnImage.pipe(writable);
}); });
it('Readable side of Stream can start flowing after Writable side has finished', function (done) {
const readable = fs.createReadStream(fixtures.inputJpg);
const writable = fs.createWriteStream(fixtures.outputJpg);
writable.on('finish', function () {
sharp(fixtures.outputJpg).toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(true, data.length > 0);
assert.strictEqual(data.length, info.size);
assert.strictEqual('jpeg', info.format);
assert.strictEqual(320, info.width);
assert.strictEqual(240, info.height);
fs.unlinkSync(fixtures.outputJpg);
done();
});
});
const pipeline = sharp().resize(320, 240);
readable.pipe(pipeline);
pipeline.on('finish', function () {
pipeline.pipe(writable);
});
});
it('Sequential read, force JPEG', function (done) { it('Sequential read, force JPEG', function (done) {
sharp(fixtures.inputJpg) sharp(fixtures.inputJpg)
.sequentialRead() .sequentialRead()
@@ -372,6 +394,50 @@ describe('Input/output', function () {
done(); done();
}); });
}); });
it('should work for webp alpha quality', function (done) {
sharp(fixtures.inputPngAlphaPremultiplicationSmall)
.webp({alphaQuality: 80})
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(true, data.length > 0);
assert.strictEqual('webp', info.format);
fixtures.assertSimilar(fixtures.expected('webp-alpha-80.webp'), data, done);
});
});
it('should work for webp lossless', function (done) {
sharp(fixtures.inputPngAlphaPremultiplicationSmall)
.webp({lossless: true})
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(true, data.length > 0);
assert.strictEqual('webp', info.format);
fixtures.assertSimilar(fixtures.expected('webp-lossless.webp'), data, done);
});
});
it('should work for webp near-lossless', function (done) {
sharp(fixtures.inputPngAlphaPremultiplicationSmall)
.webp({nearLossless: true, quality: 50})
.toBuffer(function (err50, data50, info50) {
if (err50) throw err50;
assert.strictEqual(true, data50.length > 0);
assert.strictEqual('webp', info50.format);
fixtures.assertSimilar(fixtures.expected('webp-near-lossless-50.webp'), data50, done);
});
});
it('should use near-lossless when both lossless and nearLossless are specified', function (done) {
sharp(fixtures.inputPngAlphaPremultiplicationSmall)
.webp({nearLossless: true, quality: 50, lossless: true})
.toBuffer(function (err50, data50, info50) {
if (err50) throw err50;
assert.strictEqual(true, data50.length > 0);
assert.strictEqual('webp', info50.format);
fixtures.assertSimilar(fixtures.expected('webp-near-lossless-50.webp'), data50, done);
});
});
} }
it('Invalid output format', function (done) { it('Invalid output format', function (done) {
@@ -735,6 +801,12 @@ describe('Input/output', function () {
}); });
}); });
it('Invalid WebP alpha quality throws error', function () {
assert.throws(function () {
sharp().webp({ alphaQuality: 101 });
});
});
it('Invalid TIFF quality throws error', function () { it('Invalid TIFF quality throws error', function () {
assert.throws(function () { assert.throws(function () {
sharp().tiff({ quality: 101 }); sharp().tiff({ quality: 101 });

View File

@@ -66,37 +66,37 @@ describe('Resize dimensions', function () {
it('Invalid width - NaN', function () { it('Invalid width - NaN', function () {
assert.throws(function () { assert.throws(function () {
sharp().resize('spoons', 240); sharp().resize('spoons', 240);
}); }, /Expected integer between 1 and 16383 for width but received spoons of type string/);
}); });
it('Invalid height - NaN', function () { it('Invalid height - NaN', function () {
assert.throws(function () { assert.throws(function () {
sharp().resize(320, 'spoons'); sharp().resize(320, 'spoons');
}); }, /Expected integer between 1 and 16383 for height but received spoons of type string/);
}); });
it('Invalid width - float', function () { it('Invalid width - float', function () {
assert.throws(function () { assert.throws(function () {
sharp().resize(1.5, 240); sharp().resize(1.5, 240);
}); }, /Expected integer between 1 and 16383 for width but received 1.5 of type number/);
}); });
it('Invalid height - float', function () { it('Invalid height - float', function () {
assert.throws(function () { assert.throws(function () {
sharp().resize(320, 1.5); sharp().resize(320, 1.5);
}); }, /Expected integer between 1 and 16383 for height but received 1.5 of type number/);
}); });
it('Invalid width - too large', function () { it('Invalid width - too large', function () {
assert.throws(function () { assert.throws(function () {
sharp().resize(0x4000, 240); sharp().resize(0x4000, 240);
}); }, /Expected integer between 1 and 16383 for width but received 16384 of type number/);
}); });
it('Invalid height - too large', function () { it('Invalid height - too large', function () {
assert.throws(function () { assert.throws(function () {
sharp().resize(320, 0x4000); sharp().resize(320, 0x4000);
}); }, /Expected integer between 1 and 16383 for height but received 16384 of type number/);
}); });
it('WebP shrink-on-load rounds to zero, ensure recalculation is correct', function (done) { it('WebP shrink-on-load rounds to zero, ensure recalculation is correct', function (done) {