mirror of
https://github.com/lovell/sharp.git
synced 2025-07-09 18:40:16 +02:00
Modularise JS source in 'lib' subdirectory.
Generate public API documention via jsdoc comments.
This commit is contained in:
parent
552cfd6ff1
commit
8717ecc429
@ -62,6 +62,17 @@ A method to be removed should be deprecated in the next major version then remov
|
|||||||
|
|
||||||
By way of example, the [bilinearInterpolation method](https://github.com/lovell/sharp/blob/v0.6.0/index.js#L155) present in v0.5.0 was deprecated in v0.6.0 and removed in v0.7.0.
|
By way of example, the [bilinearInterpolation method](https://github.com/lovell/sharp/blob/v0.6.0/index.js#L155) present in v0.5.0 was deprecated in v0.6.0 and removed in v0.7.0.
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
The public API is documented with [JSDoc](http://usejsdoc.org/) annotated comments.
|
||||||
|
These can be converted to Markdown by running:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm run docs
|
||||||
|
```
|
||||||
|
|
||||||
|
Please include documentation updates in any Pull Request that modifies the public API.
|
||||||
|
|
||||||
## Run the tests
|
## Run the tests
|
||||||
|
|
||||||
### Functional tests and static code analysis
|
### Functional tests and static code analysis
|
||||||
|
72
docs/api-channel.md
Normal file
72
docs/api-channel.md
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
|
||||||
|
|
||||||
|
# extractChannel
|
||||||
|
|
||||||
|
Extract a single channel from a multi-channel image.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `channel` **([Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number) \| [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String))** zero-indexed band number to extract, or `red`, `green` or `blue` as alternative to `0`, `1` or `2` respectively.
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
sharp(input)
|
||||||
|
.extractChannel('green')
|
||||||
|
.toFile('input_green.jpg', function(err, info) {
|
||||||
|
// info.channels === 1
|
||||||
|
// input_green.jpg contains the green channel of the input image
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid channel
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# joinChannel
|
||||||
|
|
||||||
|
Join one or more channels to the image.
|
||||||
|
The meaning of the added channels depends on the output colourspace, set with `toColourspace()`.
|
||||||
|
By default the output image will be web-friendly sRGB, with additional channels interpreted as alpha channels.
|
||||||
|
Channel ordering follows vips convention:
|
||||||
|
|
||||||
|
- sRGB: 0: Red, 1: Green, 2: Blue, 3: Alpha.
|
||||||
|
- CMYK: 0: Magenta, 1: Cyan, 2: Yellow, 3: Black, 4: Alpha.
|
||||||
|
|
||||||
|
Buffers may be any of the image formats supported by sharp: JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data.
|
||||||
|
For raw pixel input, the `options` object should contain a `raw` attribute, which follows the format of the attribute of the same name in the `sharp()` constructor.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `images` **([Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) \| [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Buffer](https://nodejs.org/api/buffer.html))** one or more images (file paths, Buffers).
|
||||||
|
- `Object` image options, see `sharp()` constructor.
|
||||||
|
- `options`
|
||||||
|
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# bandbool
|
||||||
|
|
||||||
|
Perform a bitwise boolean operation on all input image channels (bands) to produce a single channel output image.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `boolOp` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** one of `and`, `or` or `eor` to perform that bitwise operation, like the C logic operators `&`, `|` and `^` respectively.
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
sharp('3-channel-rgb-input.png')
|
||||||
|
.bandbool(sharp.bool.and)
|
||||||
|
.toFile('1-channel-output.png', function (err, info) {
|
||||||
|
// The output will be a single channel image where each pixel `P = R & G & B`.
|
||||||
|
// If `I(1,1) = [247, 170, 14] = [0b11110111, 0b10101010, 0b00001111]`
|
||||||
|
// then `O(1,1) = 0b11110111 & 0b10101010 & 0b00001111 = 0b00000010 = 2`.
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
|
||||||
|
|
||||||
|
Returns **Sharp**
|
71
docs/api-colour.md
Normal file
71
docs/api-colour.md
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
|
||||||
|
|
||||||
|
# background
|
||||||
|
|
||||||
|
Set the background for the `embed`, `flatten` and `extend` operations.
|
||||||
|
The default background is `{r: 0, g: 0, b: 0, a: 1}`, black without transparency.
|
||||||
|
|
||||||
|
Delegates to the _color_ module, which can throw an Error
|
||||||
|
but is liberal in what it accepts, clipping values to sensible min/max.
|
||||||
|
The alpha value is a float between `0` (transparent) and `1` (opaque).
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `rgba` **([String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object))** parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha.
|
||||||
|
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameter
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# greyscale
|
||||||
|
|
||||||
|
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.
|
||||||
|
By default the output image will be web-friendly sRGB and contain three (identical) color channels.
|
||||||
|
This may be overridden by other sharp operations such as `toColourspace('b-w')`,
|
||||||
|
which will produce an output image containing one color channel.
|
||||||
|
An alpha channel may be present, and will be unchanged by the operation.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `greyscale` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** (optional, default `true`)
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# grayscale
|
||||||
|
|
||||||
|
Alternative spelling of `greyscale`.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `grayscale` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** (optional, default `true`)
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# toColourspace
|
||||||
|
|
||||||
|
Set the output colourspace.
|
||||||
|
By default output image will be web-friendly sRGB, with additional channels interpreted as alpha channels.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `colourspace` **\[[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)]** output colourspace e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://github.com/jcupitt/libvips/blob/master/libvips/iofuncs/enumtypes.c#L568)
|
||||||
|
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# toColorspace
|
||||||
|
|
||||||
|
Alternative spelling of `toColourspace`.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `colorspace` **\[[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)]** output colorspace.
|
||||||
|
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
|
||||||
|
|
||||||
|
Returns **Sharp**
|
47
docs/api-composite.md
Normal file
47
docs/api-composite.md
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
|
||||||
|
|
||||||
|
# overlayWith
|
||||||
|
|
||||||
|
Overlay (composite) an image over the processed (resized, extracted etc.) image.
|
||||||
|
|
||||||
|
The overlay image must be the same size or smaller than the processed image.
|
||||||
|
If both `top` and `left` options are provided, they take precedence over `gravity`.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `overlay` **([Buffer](https://nodejs.org/api/buffer.html) \| [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String))** Buffer containing image data or String containing the path to an image file.
|
||||||
|
- `options` **\[[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)]**
|
||||||
|
- `options.gravity` **\[[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)]** gravity at which to place the overlay. (optional, default `'centre'`)
|
||||||
|
- `options.top` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** the pixel offset from the top edge.
|
||||||
|
- `options.left` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** the pixel offset from the left edge.
|
||||||
|
- `options.tile` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** set to true to repeat the overlay image across the entire image with the given `gravity`. (optional, default `false`)
|
||||||
|
- `options.cutout` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** set to true to apply only the alpha channel of the overlay image to the input image, giving the appearance of one image being cut out of another. (optional, default `false`)
|
||||||
|
- `options.raw` **\[[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)]** describes overlay when using raw pixel data.
|
||||||
|
- `options.raw.width` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]**
|
||||||
|
- `options.raw.height` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]**
|
||||||
|
- `options.raw.channels` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]**
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
sharp('input.png')
|
||||||
|
.rotate(180)
|
||||||
|
.resize(300)
|
||||||
|
.flatten()
|
||||||
|
.background('#ff6600')
|
||||||
|
.overlayWith('overlay.png', { gravity: sharp.gravity.southeast } )
|
||||||
|
.sharpen()
|
||||||
|
.withMetadata()
|
||||||
|
.quality(90)
|
||||||
|
.webp()
|
||||||
|
.toBuffer()
|
||||||
|
.then(function(outputBuffer) {
|
||||||
|
// outputBuffer contains upside down, 300px wide, alpha channel flattened
|
||||||
|
// onto orange background, composited with overlay.png with SE gravity,
|
||||||
|
// sharpened, with metadata, 90% quality WebP image data. Phew!
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
|
||||||
|
|
||||||
|
Returns **Sharp**
|
81
docs/api-constructor.md
Normal file
81
docs/api-constructor.md
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
|
||||||
|
|
||||||
|
#
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `input` **\[([Buffer](https://nodejs.org/api/buffer.html) \| [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String))]** if present, can be
|
||||||
|
a Buffer containing JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data, or
|
||||||
|
a String containing the path to an JPEG, PNG, WebP, GIF, SVG or TIFF image file.
|
||||||
|
JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data can be streamed into the object when null or undefined.
|
||||||
|
- `options` **\[[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)]** if present, is an Object with optional attributes.
|
||||||
|
- `options.density` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** integral number representing the DPI for vector images. (optional, default `72`)
|
||||||
|
- `options.raw` **\[[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)]** describes raw pixel image data. See `raw()` for pixel ordering.
|
||||||
|
- `options.raw.width` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]**
|
||||||
|
- `options.raw.height` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]**
|
||||||
|
- `options.raw.channels` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]**
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
sharp('input.jpg')
|
||||||
|
.resize(300, 200)
|
||||||
|
.toFile('output.jpg', function(err) {
|
||||||
|
// output.jpg is a 300 pixels wide and 200 pixels high image
|
||||||
|
// containing a scaled and cropped version of input.jpg
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Read image data from readableStream,
|
||||||
|
// resize to 300 pixels wide,
|
||||||
|
// emit an 'info' event with calculated dimensions
|
||||||
|
// and finally write image data to writableStream
|
||||||
|
var transformer = sharp()
|
||||||
|
.resize(300)
|
||||||
|
.on('info', function(info) {
|
||||||
|
console.log('Image height is ' + info.height);
|
||||||
|
});
|
||||||
|
readableStream.pipe(transformer).pipe(writableStream);
|
||||||
|
```
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# queue
|
||||||
|
|
||||||
|
An EventEmitter that emits a `change` event when a task is either:
|
||||||
|
|
||||||
|
- queued, waiting for _libuv_ to provide a worker thread
|
||||||
|
- complete
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
sharp.queue.on('change', function(queueLength) {
|
||||||
|
console.log('Queue contains ' + queueLength + ' task(s)');
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
# format
|
||||||
|
|
||||||
|
An Object containing nested boolean values representing the available input and output formats/methods.
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
console.log(sharp.format());
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)**
|
||||||
|
|
||||||
|
# versions
|
||||||
|
|
||||||
|
An Object containing the version numbers of libvips and its dependencies.
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
console.log(sharp.versions);
|
||||||
|
```
|
86
docs/api-input.md
Normal file
86
docs/api-input.md
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
|
||||||
|
|
||||||
|
# clone
|
||||||
|
|
||||||
|
Take a "snapshot" of the Sharp instance, returning a new instance.
|
||||||
|
Cloned instances inherit the input of their parent instance.
|
||||||
|
This allows multiple output Streams and therefore multiple processing pipelines to share a single input Stream.
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const pipeline = sharp().rotate();
|
||||||
|
pipeline.clone().resize(800, 600).pipe(firstWritableStream);
|
||||||
|
pipeline.clone().extract({ left: 20, top: 20, width: 100, height: 100 }).pipe(secondWritableStream);
|
||||||
|
readableStream.pipe(pipeline);
|
||||||
|
// firstWritableStream receives auto-rotated, resized readableStream
|
||||||
|
// secondWritableStream receives auto-rotated, extracted region of readableStream
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# metadata
|
||||||
|
|
||||||
|
Fast access to image metadata without decoding any compressed image data.
|
||||||
|
A Promises/A+ promise is returned when `callback` is not provided.
|
||||||
|
|
||||||
|
- `format`: Name of decoder used to decompress image data e.g. `jpeg`, `png`, `webp`, `gif`, `svg`
|
||||||
|
- `width`: Number of pixels wide
|
||||||
|
- `height`: Number of pixels high
|
||||||
|
- `space`: Name of colour space interpretation e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://github.com/jcupitt/libvips/blob/master/libvips/iofuncs/enumtypes.c#L568)
|
||||||
|
- `channels`: Number of bands e.g. `3` for sRGB, `4` for CMYK
|
||||||
|
- `density`: Number of pixels per inch (DPI), if present
|
||||||
|
- `hasProfile`: Boolean indicating the presence of an embedded ICC profile
|
||||||
|
- `hasAlpha`: Boolean indicating the presence of an alpha transparency channel
|
||||||
|
- `orientation`: Number value of the EXIF Orientation header, if present
|
||||||
|
- `exif`: Buffer containing raw EXIF data, if present
|
||||||
|
- `icc`: Buffer containing raw [ICC](https://www.npmjs.com/package/icc) profile data, if present
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `callback` **\[[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)]** called with the arguments `(err, metadata)`
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const image = sharp(inputJpg);
|
||||||
|
image
|
||||||
|
.metadata()
|
||||||
|
.then(function(metadata) {
|
||||||
|
return image
|
||||||
|
.resize(Math.round(metadata.width / 2))
|
||||||
|
.webp()
|
||||||
|
.toBuffer();
|
||||||
|
})
|
||||||
|
.then(function(data) {
|
||||||
|
// data contains a WebP image half the width and height of the original JPEG
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns **([Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) | Sharp)**
|
||||||
|
|
||||||
|
# limitInputPixels
|
||||||
|
|
||||||
|
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.
|
||||||
|
The default limit is 268402689 (0x3FFF _ 0x3FFF) pixels.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `limit` **([Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number) \| [Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean))** an integral Number of pixels, zero or false to remove limit, true to use default limit.
|
||||||
|
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid limit
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# sequentialRead
|
||||||
|
|
||||||
|
An advanced setting that switches the libvips access method to `VIPS_ACCESS_SEQUENTIAL`.
|
||||||
|
This will reduce memory usage and can improve performance on some systems.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `sequentialRead` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** (optional, default `true`)
|
||||||
|
|
||||||
|
Returns **Sharp**
|
301
docs/api-operation.md
Normal file
301
docs/api-operation.md
Normal file
@ -0,0 +1,301 @@
|
|||||||
|
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
|
||||||
|
|
||||||
|
# rotate
|
||||||
|
|
||||||
|
Rotate the output image by either an explicit angle
|
||||||
|
or auto-orient based on the EXIF `Orientation` tag.
|
||||||
|
|
||||||
|
Use this method without angle to determine the angle from EXIF data.
|
||||||
|
Mirroring is supported and may infer the use of a flip operation.
|
||||||
|
|
||||||
|
The use of `rotate` implies the removal of the EXIF `Orientation` tag, if any.
|
||||||
|
|
||||||
|
Method order is important when both rotating and extracting regions,
|
||||||
|
for example `rotate(x).extract(y)` will produce a different result to `extract(y).rotate(x)`.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `angle` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** 0, 90, 180 or 270. (optional, default `auto`)
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const pipeline = sharp()
|
||||||
|
.rotate()
|
||||||
|
.resize(null, 200)
|
||||||
|
.toBuffer(function (err, outputBuffer, info) {
|
||||||
|
// outputBuffer contains 200px high JPEG image data,
|
||||||
|
// auto-rotated using EXIF Orientation tag
|
||||||
|
// info.width and info.height contain the dimensions of the resized image
|
||||||
|
});
|
||||||
|
readableStream.pipe(pipeline);
|
||||||
|
```
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# extract
|
||||||
|
|
||||||
|
Extract a region of the image.
|
||||||
|
|
||||||
|
- Use `extract` before `resize` for pre-resize extraction.
|
||||||
|
- Use `extract` after `resize` for post-resize extraction.
|
||||||
|
- Use `extract` before and after for both.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)**
|
||||||
|
- `options.left` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** zero-indexed offset from left edge
|
||||||
|
- `options.top` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** zero-indexed offset from top edge
|
||||||
|
- `options.width` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** dimension of extracted image
|
||||||
|
- `options.height` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** dimension of extracted image
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
sharp(input)
|
||||||
|
.extract({ left: left, top: top, width: width, height: height })
|
||||||
|
.toFile(output, function(err) {
|
||||||
|
// Extract a region of the input image, saving in the same format.
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
sharp(input)
|
||||||
|
.extract({ left: leftOffsetPre, top: topOffsetPre, width: widthPre, height: heightPre })
|
||||||
|
.resize(width, height)
|
||||||
|
.extract({ left: leftOffsetPost, top: topOffsetPost, width: widthPost, height: heightPost })
|
||||||
|
.toFile(output, function(err) {
|
||||||
|
// Extract a region, resize, then extract from the resized image
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# flip
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `flip` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** (optional, default `true`)
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# flop
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `flop` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** (optional, default `true`)
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# sharpen
|
||||||
|
|
||||||
|
Sharpen the image.
|
||||||
|
When used without parameters, performs a fast, mild sharpen of the output image.
|
||||||
|
When a `sigma` is provided, performs a slower, more accurate sharpen of the L channel in the LAB colour space.
|
||||||
|
Separate control over the level of sharpening in "flat" and "jagged" areas is available.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `sigma` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`.
|
||||||
|
- `flat` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** the level of sharpening to apply to "flat" areas. (optional, default `1.0`)
|
||||||
|
- `jagged` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** the level of sharpening to apply to "jagged" areas. (optional, default `2.0`)
|
||||||
|
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# blur
|
||||||
|
|
||||||
|
Blur the image.
|
||||||
|
When used without parameters, performs a fast, mild blur of the output image.
|
||||||
|
When a `sigma` is provided, performs a slower, more accurate Gaussian blur.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `sigma` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** a value between 0.3 and 1000 representing the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`.
|
||||||
|
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# extend
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `extend` **([Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number) \| [Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object))** single pixel count to add to all edges or an Object with per-edge counts
|
||||||
|
- `extend.top` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]**
|
||||||
|
- `extend.left` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]**
|
||||||
|
- `extend.bottom` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]**
|
||||||
|
- `extend.right` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]**
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Resize to 140 pixels wide, then add 10 transparent pixels
|
||||||
|
// to the top, left and right edges and 20 to the bottom edge
|
||||||
|
sharp(input)
|
||||||
|
.resize(140)
|
||||||
|
.background({r: 0, g: 0, b: 0, a: 0})
|
||||||
|
.extend({top: 10, bottom: 20, left: 10, right: 10})
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# flatten
|
||||||
|
|
||||||
|
Merge alpha transparency channel, if any, with `background`.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `flatten` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** (optional, default `true`)
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# trim
|
||||||
|
|
||||||
|
Trim "boring" pixels from all edges that contain values within a percentage similarity of the top-left pixel.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `tolerance` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** value between 1 and 99 representing the percentage similarity. (optional, default `10`)
|
||||||
|
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# 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`.
|
||||||
|
This can improve the perceived brightness of a resized image in non-linear colour spaces.
|
||||||
|
JPEG and WebP input images will not take advantage of the shrink-on-load performance optimisation
|
||||||
|
when applying a gamma correction.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `gamma` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** value between 1.0 and 3.0. (optional, default `2.2`)
|
||||||
|
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# negate
|
||||||
|
|
||||||
|
Produce the "negative" of the image.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `negate` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** (optional, default `true`)
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# normalise
|
||||||
|
|
||||||
|
Enhance output image contrast by stretching its luminance to cover the full dynamic range.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `normalise` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** (optional, default `true`)
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# normalize
|
||||||
|
|
||||||
|
Alternative spelling of normalise.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `normalize` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** (optional, default `true`)
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# convolve
|
||||||
|
|
||||||
|
Convolve the image with the specified kernel.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `kernel` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)**
|
||||||
|
- `kernel.width` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** width of the kernel in pixels.
|
||||||
|
- `kernel.height` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** width of the kernel in pixels.
|
||||||
|
- `kernel.kernel` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)** Array of length `width*height` containing the kernel values.
|
||||||
|
- `kernel.scale` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** the scale of the kernel in pixels. (optional, default `sum`)
|
||||||
|
- `kernel.offset` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** the offset of the kernel in pixels. (optional, default `0`)
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
sharp(input)
|
||||||
|
.convolve({
|
||||||
|
width: 3,
|
||||||
|
height: 3,
|
||||||
|
kernel: [-1, 0, 1, -2, 0, 2, -1, 0, 1]
|
||||||
|
})
|
||||||
|
.raw()
|
||||||
|
.toBuffer(function(err, data, info) {
|
||||||
|
// data contains the raw pixel data representing the convolution
|
||||||
|
// of the input image with the horizontal Sobel operator
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# threshold
|
||||||
|
|
||||||
|
Any pixel value greather than or equal to the threshold value will be set to 255, otherwise it will be set to 0.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `threshold` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** a value in the range 0-255 representing the level at which the threshold will be applied. (optional, default `128`)
|
||||||
|
- `options` **\[[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)]**
|
||||||
|
- `options.greyscale` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** convert to single channel greyscale. (optional, default `true`)
|
||||||
|
- `options.grayscale` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** alternative spelling for greyscale. (optional, default `true`)
|
||||||
|
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# boolean
|
||||||
|
|
||||||
|
Perform a bitwise boolean operation with operand image.
|
||||||
|
|
||||||
|
This operation creates an output image where each pixel is the result of
|
||||||
|
the selected bitwise boolean `operation` between the corresponding pixels of the input images.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `operand` **([Buffer](https://nodejs.org/api/buffer.html) \| [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String))** Buffer containing image data or String containing the path to an image file.
|
||||||
|
- `operator` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** one of `and`, `or` or `eor` to perform that bitwise operation, like the C logic operators `&`, `|` and `^` respectively.
|
||||||
|
- `options` **\[[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)]**
|
||||||
|
- `options.raw` **\[[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)]** describes operand when using raw pixel data.
|
||||||
|
- `options.raw.width` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]**
|
||||||
|
- `options.raw.height` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]**
|
||||||
|
- `options.raw.channels` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]**
|
||||||
|
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
|
||||||
|
|
||||||
|
Returns **Sharp**
|
172
docs/api-output.md
Normal file
172
docs/api-output.md
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
|
||||||
|
|
||||||
|
# toFile
|
||||||
|
|
||||||
|
Write output image data to a file.
|
||||||
|
|
||||||
|
If an explicit output format is not selected, it will be inferred from the extension,
|
||||||
|
with JPEG, PNG, WebP, TIFF, DZI, and libvips' V format supported.
|
||||||
|
Note that raw pixel data is only supported for buffer output.
|
||||||
|
|
||||||
|
A Promises/A+ promise is returned when `callback` is not provided.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `fileOut` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** the path to write the image data to.
|
||||||
|
- `callback` **\[[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)]** called on completion with two arguments `(err, info)`.
|
||||||
|
`info` contains the output image `format`, `size` (bytes), `width`, `height` and `channels`.
|
||||||
|
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
|
||||||
|
|
||||||
|
Returns **[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)** when no callback is provided
|
||||||
|
|
||||||
|
# toBuffer
|
||||||
|
|
||||||
|
Write output to a Buffer.
|
||||||
|
By default, the format will match the input image. JPEG, PNG, WebP, and RAW are supported.
|
||||||
|
`callback`, if present, gets three arguments `(err, buffer, info)` where:
|
||||||
|
|
||||||
|
- `err` is an error message, if any.
|
||||||
|
- `buffer` is the output image data.
|
||||||
|
- `info` contains the output image `format`, `size` (bytes), `width`, `height` and `channels`.
|
||||||
|
A Promises/A+ promise is returned when `callback` is not provided.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `callback` **\[[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)]**
|
||||||
|
|
||||||
|
Returns **[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)** when no callback is provided
|
||||||
|
|
||||||
|
# withMetadata
|
||||||
|
|
||||||
|
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.
|
||||||
|
This will also convert to and add a web-friendly sRGB ICC profile.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `withMetadata` **\[[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)]**
|
||||||
|
- `withMetadata.orientation` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** value between 1 and 8, used to update the EXIF `Orientation` tag.
|
||||||
|
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# jpeg
|
||||||
|
|
||||||
|
Use these JPEG options for output image.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `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.progressive` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** use progressive (interlace) scan (optional, default `false`)
|
||||||
|
- `options.chromaSubsampling` **\[[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)]** set to '4:4:4' to prevent chroma subsampling when quality <= 90 (optional, default `'4:2:0'`)
|
||||||
|
- `options.force` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** force JPEG output, otherwise attempt to use input format (optional, default `true`)
|
||||||
|
- `trellisQuantisation` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** apply trellis quantisation, requires mozjpeg (optional, default `false`)
|
||||||
|
- `overshootDeringing` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** apply overshoot deringing, requires mozjpeg (optional, default `false`)
|
||||||
|
- `optimiseScans` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** optimise progressive scans, forces progressive, requires mozjpeg (optional, default `false`)
|
||||||
|
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid options
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# png
|
||||||
|
|
||||||
|
Use these PNG options for output image.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `options` **\[[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)]**
|
||||||
|
- `options.progressive` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** use progressive (interlace) scan (optional, default `false`)
|
||||||
|
- `options.compressionLevel` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** zlib compression level (optional, default `6`)
|
||||||
|
- `options.adaptiveFiltering` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** use adaptive row filtering (optional, default `true`)
|
||||||
|
- `options.force` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** force PNG output, otherwise attempt to use input format (optional, default `true`)
|
||||||
|
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid options
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# webp
|
||||||
|
|
||||||
|
Use these WebP options for output image.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `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.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`)
|
||||||
|
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid options
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# tiff
|
||||||
|
|
||||||
|
Use these TIFF options for output image.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `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.force` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** force TIFF output, otherwise attempt to use input format (optional, default `true`)
|
||||||
|
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid options
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# raw
|
||||||
|
|
||||||
|
Force output to be raw, uncompressed uint8 pixel data.
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# toFormat
|
||||||
|
|
||||||
|
Force output to a given format.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `format` **([String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object))** as a String or an Object with an 'id' attribute
|
||||||
|
- `options` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** output options
|
||||||
|
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** unsupported format or options
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# tile
|
||||||
|
|
||||||
|
Use tile-based deep zoom (image pyramid) output.
|
||||||
|
You can also use a `.zip` or `.szi` file extension with `toFile` to write to a compressed archive file format.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `tile` **\[[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)]**
|
||||||
|
- `tile.size` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** tile size in pixels, a value between 1 and 8192. (optional, default `256`)
|
||||||
|
- `tile.overlap` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** tile overlap in pixels, a value between 0 and 8192. (optional, default `0`)
|
||||||
|
- `tile.container` **\[[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)]** tile container, with value `fs` (filesystem) or `zip` (compressed file). (optional, default `'fs'`)
|
||||||
|
- `tile.layout` **\[[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)]** filesystem layout, possible values are `dz`, `zoomify` or `google`. (optional, default `'dz'`)
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
sharp('input.tiff')
|
||||||
|
.tile({
|
||||||
|
size: 512
|
||||||
|
})
|
||||||
|
.toFile('output.dzi', function(err, info) {
|
||||||
|
// output.dzi is the Deep Zoom XML definition
|
||||||
|
// output_files contains 512x512 tiles grouped by zoom level
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
|
||||||
|
|
||||||
|
Returns **Sharp**
|
164
docs/api-resize.md
Normal file
164
docs/api-resize.md
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
|
||||||
|
|
||||||
|
# resize
|
||||||
|
|
||||||
|
Resize image to `width` x `height`.
|
||||||
|
By default, the resized image is centre cropped to the exact size specified.
|
||||||
|
|
||||||
|
Possible reduction kernels are:
|
||||||
|
|
||||||
|
- `cubic`: Use a [Catmull-Rom spline](https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline).
|
||||||
|
- `lanczos2`: Use a [Lanczos kernel](https://en.wikipedia.org/wiki/Lanczos_resampling#Lanczos_kernel) with `a=2`.
|
||||||
|
- `lanczos3`: Use a Lanczos kernel with `a=3` (the default).
|
||||||
|
|
||||||
|
Possible enlargement interpolators are:
|
||||||
|
|
||||||
|
- `nearest`: Use [nearest neighbour interpolation](http://en.wikipedia.org/wiki/Nearest-neighbor_interpolation).
|
||||||
|
- `bilinear`: Use [bilinear interpolation](http://en.wikipedia.org/wiki/Bilinear_interpolation), faster than bicubic but with less smooth results.
|
||||||
|
- `vertexSplitQuadraticBasisSpline`: Use the smoother [VSQBS interpolation](https://github.com/jcupitt/libvips/blob/master/libvips/resample/vsqbs.cpp#L48) to prevent "staircasing" when enlarging.
|
||||||
|
- `bicubic`: Use [bicubic interpolation](http://en.wikipedia.org/wiki/Bicubic_interpolation) (the default).
|
||||||
|
- `locallyBoundedBicubic`: Use [LBB interpolation](https://github.com/jcupitt/libvips/blob/master/libvips/resample/lbb.cpp#L100), which prevents some "[acutance](http://en.wikipedia.org/wiki/Acutance)" but typically reduces performance by a factor of 2.
|
||||||
|
- `nohalo`: Use [Nohalo interpolation](http://eprints.soton.ac.uk/268086/), which prevents acutance but typically reduces performance by a factor of 3.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `width` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** pixels wide the resultant image should be, between 1 and 16383 (0x3FFF). Use `null` or `undefined` to auto-scale the width to match the height.
|
||||||
|
- `height` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** pixels high the resultant image should be, between 1 and 16383. Use `null` or `undefined` to auto-scale the height to match the width.
|
||||||
|
- `options` **\[[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)]**
|
||||||
|
- `options.kernel` **\[[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)]** the kernel to use for image reduction. (optional, default `'lanczos3'`)
|
||||||
|
- `options.interpolator` **\[[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)]** the interpolator to use for image enlargement. (optional, default `'bicubic'`)
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
sharp(inputBuffer)
|
||||||
|
.resize(200, 300, {
|
||||||
|
kernel: sharp.kernel.lanczos2,
|
||||||
|
interpolator: sharp.interpolator.nohalo
|
||||||
|
})
|
||||||
|
.background('white')
|
||||||
|
.embed()
|
||||||
|
.toFile('output.tiff')
|
||||||
|
.then(function() {
|
||||||
|
// output.tiff is a 200 pixels wide and 300 pixels high image
|
||||||
|
// containing a lanczos2/nohalo scaled version, embedded on a white canvas,
|
||||||
|
// of the image data in inputBuffer
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# crop
|
||||||
|
|
||||||
|
Crop the resized image to the exact size specified, the default behaviour.
|
||||||
|
|
||||||
|
Possible attributes of the optional `sharp.gravity` are `north`, `northeast`, `east`, `southeast`, `south`,
|
||||||
|
`southwest`, `west`, `northwest`, `center` and `centre`.
|
||||||
|
|
||||||
|
The experimental strategy-based approach resizes so one dimension is at its target length
|
||||||
|
then repeatedly ranks edge regions, discarding the edge with the lowest score based on the selected strategy.
|
||||||
|
|
||||||
|
- `entropy`: focus on the region with the highest [Shannon entropy](https://en.wikipedia.org/wiki/Entropy_%28information_theory%29).
|
||||||
|
- `attention`: focus on the region with the highest luminance frequency, colour saturation and presence of skin tones.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `crop` **\[[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)]** A member of `sharp.gravity` to crop to an edge/corner or `sharp.strategy` to crop dynamically. (optional, default `'centre'`)
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const transformer = sharp()
|
||||||
|
.resize(200, 200)
|
||||||
|
.crop(sharp.strategy.entropy)
|
||||||
|
.on('error', function(err) {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
// Read image data from readableStream
|
||||||
|
// Write 200px square auto-cropped image data to writableStream
|
||||||
|
readableStream.pipe(transformer).pipe(writableStream);
|
||||||
|
```
|
||||||
|
|
||||||
|
- Throws **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** Invalid parameters
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# embed
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
If the background contains an alpha value then WebP and PNG format output images will
|
||||||
|
contain an alpha channel, even when the input image does not.
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
sharp('input.gif')
|
||||||
|
.resize(200, 300)
|
||||||
|
.background({r: 0, g: 0, b: 0, a: 0})
|
||||||
|
.embed()
|
||||||
|
.toFormat(sharp.format.webp)
|
||||||
|
.toBuffer(function(err, outputBuffer) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
// outputBuffer contains WebP image data of a 200 pixels wide and 300 pixels high
|
||||||
|
// containing a scaled version, embedded on a transparent canvas, of input.gif
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# max
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Both `width` and `height` must be provided via `resize` otherwise the behaviour will default to `crop`.
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
sharp(inputBuffer)
|
||||||
|
.resize(200, 200)
|
||||||
|
.max()
|
||||||
|
.toFormat('jpeg')
|
||||||
|
.toBuffer()
|
||||||
|
.then(function(outputBuffer) {
|
||||||
|
// outputBuffer contains JPEG image data no wider than 200 pixels and no higher
|
||||||
|
// than 200 pixels regardless of the inputBuffer image dimensions
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# min
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Both `width` and `height` must be provided via `resize` otherwise the behaviour will default to `crop`.
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# ignoreAspectRatio
|
||||||
|
|
||||||
|
Ignoring the aspect ratio of the input, stretch the image to
|
||||||
|
the exact `width` and/or `height` provided via `resize`.
|
||||||
|
|
||||||
|
Returns **Sharp**
|
||||||
|
|
||||||
|
# withoutEnlargement
|
||||||
|
|
||||||
|
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:
|
||||||
|
"_change the dimensions of the image only if its width or height exceeds the geometry specification_".
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `withoutEnlargement` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** (optional, default `true`)
|
||||||
|
|
||||||
|
Returns **Sharp**
|
100
docs/api-utility.md
Normal file
100
docs/api-utility.md
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
This method always returns cache statistics,
|
||||||
|
useful for determining how much working memory is required for a particular task.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `Object` **([Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) \| [Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean))** with the following attributes, or Boolean where true uses default cache settings and false removes all caching.
|
||||||
|
- `options`
|
||||||
|
- `options.memory` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** is the maximum memory in MB to use for this cache (optional, default `50`)
|
||||||
|
- `options.files` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** is the maximum number of files to hold open (optional, default `20`)
|
||||||
|
- `options.items` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** is the maximum number of operations to cache (optional, default `100`)
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const stats = sharp.cache();
|
||||||
|
```
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
sharp.cache( { items: 200 } );
|
||||||
|
sharp.cache( { files: 0 } );
|
||||||
|
sharp.cache(false);
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)**
|
||||||
|
|
||||||
|
# concurrency
|
||||||
|
|
||||||
|
Gets, or when a concurrency is provided sets,
|
||||||
|
the number of threads _libvips'_ should create to process each image.
|
||||||
|
The default value is the number of CPU cores.
|
||||||
|
A value of `0` will reset to this default.
|
||||||
|
|
||||||
|
The maximum number of images that can be processed in parallel
|
||||||
|
is limited by libuv's `UV_THREADPOOL_SIZE` environment variable.
|
||||||
|
|
||||||
|
This method always returns the current concurrency.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `concurrency` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]**
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const threads = sharp.concurrency(); // 4
|
||||||
|
sharp.concurrency(2); // 2
|
||||||
|
sharp.concurrency(0); // 4
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** concurrency
|
||||||
|
|
||||||
|
# counters
|
||||||
|
|
||||||
|
Provides access to internal task counters.
|
||||||
|
|
||||||
|
- queue is the number of tasks this module has queued waiting for _libuv_ to provide a worker thread from its pool.
|
||||||
|
- process is the number of resize tasks currently being processed.
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const counters = sharp.counters(); // { queue: 2, process: 4 }
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)**
|
||||||
|
|
||||||
|
# simd
|
||||||
|
|
||||||
|
Get and set use of SIMD vector unit instructions.
|
||||||
|
Requires libvips to have been compiled with liborc support.
|
||||||
|
|
||||||
|
Improves the performance of `resize`, `blur` and `sharpen` operations
|
||||||
|
by taking advantage of the SIMD vector unit of the CPU, e.g. Intel SSE and ARM NEON.
|
||||||
|
|
||||||
|
This feature is currently off by default but future versions may reverse this.
|
||||||
|
Versions of liborc prior to 0.4.25 are known to segfault under heavy load.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
- `simd` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** (optional, default `false`)
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const simd = sharp.simd();
|
||||||
|
// simd is `true` if SIMD is currently enabled
|
||||||
|
```
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const simd = sharp.simd(true);
|
||||||
|
// attempts to enable the use of SIMD, returning true if available
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)**
|
819
docs/api.md
819
docs/api.md
@ -1,819 +0,0 @@
|
|||||||
# API
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var sharp = require('sharp');
|
|
||||||
```
|
|
||||||
|
|
||||||
### Input
|
|
||||||
|
|
||||||
#### sharp([input], [options])
|
|
||||||
|
|
||||||
Constructor to which further methods are chained.
|
|
||||||
|
|
||||||
`input`, if present, can be one of:
|
|
||||||
|
|
||||||
* Buffer containing JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data, or
|
|
||||||
* String containing the path to an JPEG, PNG, WebP, GIF, SVG or TIFF image file.
|
|
||||||
|
|
||||||
JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data
|
|
||||||
can be streamed into the object when `input` is `null` or `undefined`.
|
|
||||||
|
|
||||||
`options`, if present, is an Object with the following optional attributes:
|
|
||||||
|
|
||||||
* `density` an integral number representing the DPI for vector images, defaulting to 72.
|
|
||||||
* `raw` an Object containing `width`, `height` and `channels` when providing uncompressed data. See `raw()` for pixel ordering.
|
|
||||||
|
|
||||||
The object returned by the constructor implements the
|
|
||||||
[stream.Duplex](http://nodejs.org/api/stream.html#stream_class_stream_duplex) class.
|
|
||||||
|
|
||||||
JPEG, PNG or WebP format image data can be streamed out from this object.
|
|
||||||
When using Stream based output, derived attributes are available from the `info` event.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
sharp('input.jpg')
|
|
||||||
.resize(300, 200)
|
|
||||||
.toFile('output.jpg', function(err) {
|
|
||||||
// output.jpg is a 300 pixels wide and 200 pixels high image
|
|
||||||
// containing a scaled and cropped version of input.jpg
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// Read image data from readableStream,
|
|
||||||
// resize to 300 pixels wide,
|
|
||||||
// emit an 'info' event with calculated dimensions
|
|
||||||
// and finally write image data to writableStream
|
|
||||||
var transformer = sharp()
|
|
||||||
.resize(300)
|
|
||||||
.on('info', function(info) {
|
|
||||||
console.log('Image height is ' + info.height);
|
|
||||||
});
|
|
||||||
readableStream.pipe(transformer).pipe(writableStream);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### metadata([callback])
|
|
||||||
|
|
||||||
Fast access to image metadata without decoding any compressed image data.
|
|
||||||
|
|
||||||
`callback`, if present, gets the arguments `(err, metadata)` where `metadata` has the attributes:
|
|
||||||
|
|
||||||
* `format`: Name of decoder used to decompress image data e.g. `jpeg`, `png`, `webp`, `gif`, `svg`
|
|
||||||
* `width`: Number of pixels wide
|
|
||||||
* `height`: Number of pixels high
|
|
||||||
* `space`: Name of colour space interpretation e.g. `srgb`, `rgb`, `scrgb`, `cmyk`, `lab`, `xyz`, `b-w` [...](https://github.com/jcupitt/libvips/blob/master/libvips/iofuncs/enumtypes.c#L568)
|
|
||||||
* `channels`: Number of bands e.g. `3` for sRGB, `4` for CMYK
|
|
||||||
* `density`: Number of pixels per inch (DPI), if present
|
|
||||||
* `hasProfile`: Boolean indicating the presence of an embedded ICC profile
|
|
||||||
* `hasAlpha`: Boolean indicating the presence of an alpha transparency channel
|
|
||||||
* `orientation`: Number value of the EXIF Orientation header, if present
|
|
||||||
* `exif`: Buffer containing raw EXIF data, if present
|
|
||||||
* `icc`: Buffer containing raw [ICC](https://www.npmjs.com/package/icc) profile data, if present
|
|
||||||
|
|
||||||
A Promises/A+ promise is returned when `callback` is not provided.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var image = sharp(inputJpg);
|
|
||||||
image
|
|
||||||
.metadata()
|
|
||||||
.then(function(metadata) {
|
|
||||||
return image
|
|
||||||
.resize(Math.round(metadata.width / 2))
|
|
||||||
.webp()
|
|
||||||
.toBuffer();
|
|
||||||
})
|
|
||||||
.then(function(data) {
|
|
||||||
// data contains a WebP image half the width and height of the original JPEG
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
#### clone()
|
|
||||||
|
|
||||||
Takes a "snapshot" of the instance, returning a new instance.
|
|
||||||
Cloned instances inherit the input of their parent instance.
|
|
||||||
|
|
||||||
This allows multiple output Streams
|
|
||||||
and therefore multiple processing pipelines
|
|
||||||
to share a single input Stream.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var pipeline = sharp().rotate();
|
|
||||||
pipeline.clone().resize(800, 600).pipe(firstWritableStream);
|
|
||||||
pipeline.clone().extract({ left: 20, top: 20, width: 100, height: 100 }).pipe(secondWritableStream);
|
|
||||||
readableStream.pipe(pipeline);
|
|
||||||
// firstWritableStream receives auto-rotated, resized readableStream
|
|
||||||
// secondWritableStream receives auto-rotated, extracted region of readableStream
|
|
||||||
```
|
|
||||||
|
|
||||||
#### sequentialRead()
|
|
||||||
|
|
||||||
An advanced setting that switches the libvips access method to `VIPS_ACCESS_SEQUENTIAL`.
|
|
||||||
This will reduce memory usage and can improve performance on some systems.
|
|
||||||
|
|
||||||
#### limitInputPixels(pixels)
|
|
||||||
|
|
||||||
Do not process input images where the number of pixels (width * height) exceeds this limit.
|
|
||||||
|
|
||||||
`pixels` is either an integral Number of pixels, with a value between 1 and the default 268402689 (0x3FFF * 0x3FFF) or
|
|
||||||
a boolean. `false` will disable checking while `true` will revert to the default limit.
|
|
||||||
|
|
||||||
### Resizing
|
|
||||||
|
|
||||||
#### resize([width], [height], [options])
|
|
||||||
|
|
||||||
Scale output to `width` x `height`. By default, the resized image is cropped to the exact size specified.
|
|
||||||
|
|
||||||
`width` is the integral Number of pixels wide the resultant image should be, between 1 and 16383 (0x3FFF). Use `null` or `undefined` to auto-scale the width to match the height.
|
|
||||||
|
|
||||||
`height` is the integral Number of pixels high the resultant image should be, between 1 and 16383. Use `null` or `undefined` to auto-scale the height to match the width.
|
|
||||||
|
|
||||||
`options` is an optional Object. If present, it can contain one or more of:
|
|
||||||
|
|
||||||
* `options.kernel`, the kernel to use for image reduction, defaulting to `lanczos3`.
|
|
||||||
* `options.interpolator`, the interpolator to use for image enlargement, defaulting to `bicubic`.
|
|
||||||
|
|
||||||
Possible kernels are:
|
|
||||||
|
|
||||||
* `cubic`: Use a [Catmull-Rom spline](https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline).
|
|
||||||
* `lanczos2`: Use a [Lanczos kernel](https://en.wikipedia.org/wiki/Lanczos_resampling#Lanczos_kernel) with `a=2`.
|
|
||||||
* `lanczos3`: Use a Lanczos kernel with `a=3` (the default).
|
|
||||||
|
|
||||||
Possible interpolators are:
|
|
||||||
|
|
||||||
* `nearest`: Use [nearest neighbour interpolation](http://en.wikipedia.org/wiki/Nearest-neighbor_interpolation).
|
|
||||||
* `bilinear`: Use [bilinear interpolation](http://en.wikipedia.org/wiki/Bilinear_interpolation), faster than bicubic but with less smooth results.
|
|
||||||
* `vertexSplitQuadraticBasisSpline`: Use the smoother [VSQBS interpolation](https://github.com/jcupitt/libvips/blob/master/libvips/resample/vsqbs.cpp#L48) to prevent "staircasing" when enlarging.
|
|
||||||
* `bicubic`: Use [bicubic interpolation](http://en.wikipedia.org/wiki/Bicubic_interpolation) (the default).
|
|
||||||
* `locallyBoundedBicubic`: Use [LBB interpolation](https://github.com/jcupitt/libvips/blob/master/libvips/resample/lbb.cpp#L100), which prevents some "[acutance](http://en.wikipedia.org/wiki/Acutance)" but typically reduces performance by a factor of 2.
|
|
||||||
* `nohalo`: Use [Nohalo interpolation](http://eprints.soton.ac.uk/268086/), which prevents acutance but typically reduces performance by a factor of 3.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
sharp(inputBuffer)
|
|
||||||
.resize(200, 300, {
|
|
||||||
kernel: sharp.kernel.lanczos2,
|
|
||||||
interpolator: sharp.interpolator.nohalo
|
|
||||||
})
|
|
||||||
.background('white')
|
|
||||||
.embed()
|
|
||||||
.toFile('output.tiff')
|
|
||||||
.then(function() {
|
|
||||||
// output.tiff is a 200 pixels wide and 300 pixels high image
|
|
||||||
// containing a lanczos2/nohalo scaled version, embedded on a white canvas,
|
|
||||||
// of the image data in inputBuffer
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
#### crop([option])
|
|
||||||
|
|
||||||
Crop the resized image to the exact size specified, the default behaviour.
|
|
||||||
|
|
||||||
`option`, if present, is an attribute of:
|
|
||||||
|
|
||||||
* `sharp.gravity` e.g. `sharp.gravity.north`, to crop to an edge or corner, or
|
|
||||||
* `sharp.strategy` e.g. `sharp.strategy.entropy`, to crop dynamically.
|
|
||||||
|
|
||||||
Possible attributes of `sharp.gravity` are
|
|
||||||
`north`, `northeast`, `east`, `southeast`, `south`,
|
|
||||||
`southwest`, `west`, `northwest`, `center` and `centre`.
|
|
||||||
|
|
||||||
The experimental strategy-based approach resizes so one dimension is at its target length
|
|
||||||
then repeatedly ranks edge regions, discarding the edge with the lowest score based on the selected strategy.
|
|
||||||
|
|
||||||
* `entropy`: focus on the region with the highest [Shannon entropy](https://en.wikipedia.org/wiki/Entropy_%28information_theory%29).
|
|
||||||
* `attention`: focus on the region with the highest luminance frequency, colour saturation and presence of skin tones.
|
|
||||||
|
|
||||||
The default crop option is a `center`/`centre` gravity.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var transformer = sharp()
|
|
||||||
.resize(200, 200)
|
|
||||||
.crop(sharp.strategy.entropy)
|
|
||||||
.on('error', function(err) {
|
|
||||||
console.log(err);
|
|
||||||
});
|
|
||||||
// Read image data from readableStream
|
|
||||||
// Write 200px square auto-cropped image data to writableStream
|
|
||||||
readableStream.pipe(transformer).pipe(writableStream);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### embed()
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
If the background contains an alpha value
|
|
||||||
then WebP and PNG format output images will
|
|
||||||
contain an alpha channel,
|
|
||||||
even when the input image does not.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
sharp('input.gif')
|
|
||||||
.resize(200, 300)
|
|
||||||
.background({r: 0, g: 0, b: 0, a: 0})
|
|
||||||
.embed()
|
|
||||||
.toFormat(sharp.format.webp)
|
|
||||||
.toBuffer(function(err, outputBuffer) {
|
|
||||||
if (err) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
// outputBuffer contains WebP image data of a 200 pixels wide and 300 pixels high
|
|
||||||
// containing a scaled version, embedded on a transparent canvas, of input.gif
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
#### max()
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Both `width` and `height` must be provided via
|
|
||||||
`resize` otherwise the behaviour will default to `crop`.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
sharp(inputBuffer)
|
|
||||||
.resize(200, 200)
|
|
||||||
.max()
|
|
||||||
.toFormat('jpeg')
|
|
||||||
.toBuffer()
|
|
||||||
.then(function(outputBuffer) {
|
|
||||||
// outputBuffer contains JPEG image data no wider than 200 pixels and no higher
|
|
||||||
// than 200 pixels regardless of the inputBuffer image dimensions
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
#### min()
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Both `width` and `height` must be provided via `resize` otherwise the behaviour will default to `crop`.
|
|
||||||
|
|
||||||
#### withoutEnlargement()
|
|
||||||
|
|
||||||
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:
|
|
||||||
"*change the dimensions of the image only
|
|
||||||
if its width or height exceeds the geometry specification*".
|
|
||||||
|
|
||||||
#### ignoreAspectRatio()
|
|
||||||
|
|
||||||
Ignoring the aspect ratio of the input, stretch the image to the exact `width` and/or `height` provided via `resize`.
|
|
||||||
|
|
||||||
### Operations
|
|
||||||
|
|
||||||
#### extract({ left: left, top: top, width: width, height: height })
|
|
||||||
|
|
||||||
Extract a region of the image. Can be used with or without a `resize` operation.
|
|
||||||
|
|
||||||
`left` and `top` are the offset, in pixels, from the top-left corner.
|
|
||||||
|
|
||||||
`width` and `height` are the dimensions of the extracted image.
|
|
||||||
|
|
||||||
Use `extract` before `resize` for pre-resize extraction. Use `extract` after `resize` for post-resize extraction. Use `extract` before and after for both.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
sharp(input)
|
|
||||||
.extract({ left: left, top: top, width: width, height: height })
|
|
||||||
.toFile(output, function(err) {
|
|
||||||
// Extract a region of the input image, saving in the same format.
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
sharp(input)
|
|
||||||
.extract({ left: leftOffsetPre, top: topOffsetPre, width: widthPre, height: heightPre })
|
|
||||||
.resize(width, height)
|
|
||||||
.extract({ left: leftOffsetPost, top: topOffsetPost, width: widthPost, height: heightPost })
|
|
||||||
.toFile(output, function(err) {
|
|
||||||
// Extract a region, resize, then extract from the resized image
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
#### trim([tolerance])
|
|
||||||
|
|
||||||
Trim "boring" pixels from all edges that contain values within a percentage similarity of the top-left pixel.
|
|
||||||
|
|
||||||
* `tolerance`, if present, is an integral Number between 1 and 99 representing the percentage similarity, defaulting to 10.
|
|
||||||
|
|
||||||
#### background(rgba)
|
|
||||||
|
|
||||||
Set the background for the `embed`, `flatten` and `extend` operations.
|
|
||||||
|
|
||||||
`rgba` is parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha.
|
|
||||||
|
|
||||||
The alpha value is a float between `0` (transparent) and `1` (opaque).
|
|
||||||
|
|
||||||
The default background is `{r: 0, g: 0, b: 0, a: 1}`, black without transparency.
|
|
||||||
|
|
||||||
#### flatten()
|
|
||||||
|
|
||||||
Merge alpha transparency channel, if any, with `background`.
|
|
||||||
|
|
||||||
#### extend(extension)
|
|
||||||
|
|
||||||
Extends/pads the edges of the image with `background`, where `extension` is one of:
|
|
||||||
|
|
||||||
* a Number representing the pixel count to add to each edge, or
|
|
||||||
* an Object containing `top`, `left`, `bottom` and `right` attributes, each a Number of pixels to add to that edge.
|
|
||||||
|
|
||||||
This operation will always occur after resizing and extraction, if any.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// Resize to 140 pixels wide, then add 10 transparent pixels
|
|
||||||
// to the top, left and right edges and 20 to the bottom edge
|
|
||||||
sharp(input)
|
|
||||||
.resize(140)
|
|
||||||
.background({r: 0, g: 0, b: 0, a: 0})
|
|
||||||
.extend({top: 10, bottom: 20, left: 10, right: 10})
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
#### negate()
|
|
||||||
|
|
||||||
Produces the "negative" of the image. White => Black, Black => White, Blue => Yellow, etc.
|
|
||||||
|
|
||||||
#### rotate([angle])
|
|
||||||
|
|
||||||
Rotate the output image by either an explicit angle or auto-orient based on the EXIF `Orientation` tag.
|
|
||||||
|
|
||||||
`angle`, if present, is a Number with a value of `0`, `90`, `180` or `270`.
|
|
||||||
|
|
||||||
Use this method without `angle` to determine the angle from EXIF data. Mirroring is supported and may infer the use of a `flip` operation.
|
|
||||||
|
|
||||||
Method order is important when both rotating and extracting regions, for example `rotate(x).extract(y)` will produce a different result to `extract(y).rotate(x)`.
|
|
||||||
|
|
||||||
The use of `rotate` implies the removal of the EXIF `Orientation` tag, if any.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var pipeline = sharp()
|
|
||||||
.rotate()
|
|
||||||
.resize(null, 200)
|
|
||||||
.progressive()
|
|
||||||
.toBuffer(function(err, outputBuffer, info) {
|
|
||||||
if (err) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
// outputBuffer contains 200px high progressive JPEG image data,
|
|
||||||
// auto-rotated using EXIF Orientation tag
|
|
||||||
// info.width and info.height contain the dimensions of the resized image
|
|
||||||
});
|
|
||||||
readableStream.pipe(pipeline);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### flip()
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
#### flop()
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
#### blur([sigma])
|
|
||||||
|
|
||||||
When used without parameters, performs a fast, mild blur of the output image. This typically reduces performance by 10%.
|
|
||||||
|
|
||||||
When a `sigma` is provided, performs a slower, more accurate Gaussian blur. This typically reduces performance by 25%.
|
|
||||||
|
|
||||||
* `sigma`, if present, is a Number between 0.3 and 1000 representing the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`.
|
|
||||||
|
|
||||||
#### convolve(kernel)
|
|
||||||
|
|
||||||
Convolve the image with the specified `kernel`, an Object with the following attributes:
|
|
||||||
|
|
||||||
* `width` is an integral Number representing the width of the kernel in pixels.
|
|
||||||
* `height` is an integral Number representing the width of the kernel in pixels.
|
|
||||||
* `kernel` is an Array of length `width*height` containing the kernel values.
|
|
||||||
* `scale`, if present, is a Number representing the scale of the kernel in pixels, defaulting to the sum of the kernel's values.
|
|
||||||
* `offset`, if present, is a Number representing the offset of the kernel in pixels, defaulting to 0.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
sharp(input)
|
|
||||||
.convolve({
|
|
||||||
width: 3,
|
|
||||||
height: 3,
|
|
||||||
kernel: [-1, 0, 1, -2, 0, 2, -1, 0, 1]
|
|
||||||
})
|
|
||||||
.raw()
|
|
||||||
.toBuffer(function(err, data, info) {
|
|
||||||
// data contains the raw pixel data representing the convolution
|
|
||||||
// of the input image with the horizontal Sobel operator
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
#### sharpen([sigma], [flat], [jagged])
|
|
||||||
|
|
||||||
When used without parameters, performs a fast, mild sharpen of the output image. This typically reduces performance by 10%.
|
|
||||||
|
|
||||||
When a `sigma` is provided, performs a slower, more accurate sharpen of the L channel in the LAB colour space. Separate control over the level of sharpening in "flat" and "jagged" areas is available. This typically reduces performance by 50%.
|
|
||||||
|
|
||||||
* `sigma`, if present, is a Number representing the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`.
|
|
||||||
* `flat`, if present, is a Number representing the level of sharpening to apply to "flat" areas, defaulting to a value of 1.0.
|
|
||||||
* `jagged`, if present, is a Number representing the level of sharpening to apply to "jagged" areas, defaulting to a value of 2.0.
|
|
||||||
|
|
||||||
#### threshold([threshold], [options])
|
|
||||||
|
|
||||||
Any pixel value greather than or equal to the threshold value will be set to 255, otherwise it will be set to 0.
|
|
||||||
By default, the image will be converted to single channel greyscale before thresholding.
|
|
||||||
|
|
||||||
* `threshold`, if present, is a Number between 0 and 255, representing the level at which the threshold will be applied. The default threshold is 128.
|
|
||||||
* `options`, if present, is an Object containing a Boolean `greyscale` (or `grayscale`). When `false` each channel will have the threshold applied independently.
|
|
||||||
|
|
||||||
#### gamma([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`.
|
|
||||||
|
|
||||||
`gamma`, if present, is a Number between 1 and 3. The default value is `2.2`, a suitable approximation for sRGB images.
|
|
||||||
|
|
||||||
This can improve the perceived brightness of a resized image in non-linear colour spaces.
|
|
||||||
|
|
||||||
JPEG input images will not take advantage of the shrink-on-load performance optimisation when applying a gamma correction.
|
|
||||||
|
|
||||||
#### grayscale() / greyscale()
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
By default the output image will be web-friendly sRGB and contain three (identical) color channels. This may be overridden by other sharp operations such as `toColourspace('b-w')`, which will produce an output image containing one color channel. An alpha channel may be present, and will be unchanged by the operation.
|
|
||||||
|
|
||||||
#### normalize() / normalise()
|
|
||||||
|
|
||||||
Enhance output image contrast by stretching its luminance to cover the full dynamic range. This typically reduces performance by 30%.
|
|
||||||
|
|
||||||
#### overlayWith(image, [options])
|
|
||||||
|
|
||||||
Overlay (composite) a image over the processed (resized, extracted etc.) image.
|
|
||||||
|
|
||||||
`image` is one of the following, and must be the same size or smaller than the processed image:
|
|
||||||
|
|
||||||
* Buffer containing image data, or
|
|
||||||
* String containing the path to an image file
|
|
||||||
|
|
||||||
`options`, if present, is an Object with the following optional attributes:
|
|
||||||
|
|
||||||
* `gravity` is a String or an attribute of the `sharp.gravity` Object e.g. `sharp.gravity.north` at which to place the overlay, defaulting to `center`/`centre`.
|
|
||||||
* `top` is an integral Number representing the pixel offset from the top edge.
|
|
||||||
* `left` is an integral Number representing the pixel offset from the left edge.
|
|
||||||
* `tile` is a Boolean, defaulting to `false`. When set to `true` repeats the overlay image across the entire image with the given `gravity`.
|
|
||||||
* `cutout` is a Boolean, defaulting to `false`. When set to `true` applies only the alpha channel of the overlay image to the image to be overlaid, giving the appearance of one image being cut out of another.
|
|
||||||
* `raw` an Object containing `width`, `height` and `channels` when providing uncompressed data.
|
|
||||||
|
|
||||||
If both `top` and `left` are provided, they take precedence over `gravity`.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
sharp('input.png')
|
|
||||||
.rotate(180)
|
|
||||||
.resize(300)
|
|
||||||
.flatten()
|
|
||||||
.background('#ff6600')
|
|
||||||
.overlayWith('overlay.png', { gravity: sharp.gravity.southeast } )
|
|
||||||
.sharpen()
|
|
||||||
.withMetadata()
|
|
||||||
.quality(90)
|
|
||||||
.webp()
|
|
||||||
.toBuffer()
|
|
||||||
.then(function(outputBuffer) {
|
|
||||||
// outputBuffer contains upside down, 300px wide, alpha channel flattened
|
|
||||||
// onto orange background, composited with overlay.png with SE gravity,
|
|
||||||
// sharpened, with metadata, 90% quality WebP image data. Phew!
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
#### toColourspace(colourspace) / toColorspace(colorspace)
|
|
||||||
|
|
||||||
Set the output colourspace. By default output image will be web-friendly sRGB, with additional channels interpreted as alpha channels.
|
|
||||||
|
|
||||||
`colourspace` is a string or `sharp.colourspace` enum that identifies an output colourspace. String arguments comprise vips colour space interpretation names e.g. `srgb`, `rgb`, `scrgb`, `cmyk`, `lab`, `xyz`, `b-w` [...](https://github.com/jcupitt/libvips/blob/master/libvips/iofuncs/enumtypes.c#L568)
|
|
||||||
|
|
||||||
#### extractChannel(channel)
|
|
||||||
|
|
||||||
Extract a single channel from a multi-channel image.
|
|
||||||
|
|
||||||
`channel` is a zero-indexed integral Number representing the band number to extract. `red`, `green` or `blue` are also accepted as an alternative to `0`, `1` or `2` respectively.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
sharp(input)
|
|
||||||
.extractChannel('green')
|
|
||||||
.toFile('input_green.jpg', function(err, info) {
|
|
||||||
// info.channels === 1
|
|
||||||
// input_green.jpg contains the green channel of the input image
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
#### joinChannel(channels, [options])
|
|
||||||
|
|
||||||
Join a data channel to the image. The meaning of the added channels depends on the output colourspace, set with `toColourspace()`. By default the output image will be web-friendly sRGB, with additional channels interpreted as alpha channels.
|
|
||||||
|
|
||||||
`channels` is one of
|
|
||||||
* a single file path
|
|
||||||
* an array of file paths
|
|
||||||
* a single buffer
|
|
||||||
* an array of buffers
|
|
||||||
|
|
||||||
Note that channel ordering follows vips convention:
|
|
||||||
* sRGB: 0: Red, 1: Green, 2: Blue, 3: Alpha
|
|
||||||
* CMYK: 0: Magenta, 1: Cyan, 2: Yellow, 3: Black, 4: Alpha
|
|
||||||
|
|
||||||
Buffers may be any of the image formats supported by sharp: JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data. In the case of a RAW buffer, the `options` object should contain a `raw` attribute, which follows the format of the attribute of the same name in the `sharp()` constructor. See `sharp()` for details. See `raw()` for pixel ordering.
|
|
||||||
|
|
||||||
#### bandbool(operation)
|
|
||||||
|
|
||||||
Perform a bitwise boolean operation on all input image channels (bands) to produce a single channel output image.
|
|
||||||
|
|
||||||
`operation` is a string containing the name of the bitwise operator to be appled to image channels, which can be one of:
|
|
||||||
|
|
||||||
* `and` performs a bitwise and operation, like the c-operator `&`.
|
|
||||||
* `or` performs a bitwise or operation, like the c-operator `|`.
|
|
||||||
* `eor` performs a bitwise exclusive or operation, like the c-operator `^`.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
sharp('input.png')
|
|
||||||
.bandbool(sharp.bool.and)
|
|
||||||
.toFile('output.png')
|
|
||||||
```
|
|
||||||
|
|
||||||
In the above example if `input.png` is a 3 channel RGB image, `output.png` will be a 1 channel grayscale image where each pixel `P = R & G & B`.
|
|
||||||
For example, if `I(1,1) = [247, 170, 14] = [0b11110111, 0b10101010, 0b00001111]` then `O(1,1) = 0b11110111 & 0b10101010 & 0b00001111 = 0b00000010 = 2`.
|
|
||||||
|
|
||||||
#### boolean(image, operation, [options])
|
|
||||||
|
|
||||||
Perform a bitwise boolean operation with `image`, where `image` is one of the following:
|
|
||||||
|
|
||||||
* Buffer containing JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data, or
|
|
||||||
* String containing the path to an image file
|
|
||||||
|
|
||||||
This operation creates an output image where each pixel is the result of the selected bitwise boolean `operation` between the corresponding pixels of the input images.
|
|
||||||
The boolean operation can be one of the following:
|
|
||||||
|
|
||||||
* `and` performs a bitwise and operation, like the c-operator `&`.
|
|
||||||
* `or` performs a bitwise or operation, like the c-operator `|`.
|
|
||||||
* `eor` performs a bitwise exclusive or operation, like the c-operator `^`.
|
|
||||||
|
|
||||||
`options`, if present, is an Object with the following optional attributes:
|
|
||||||
|
|
||||||
* `raw` an Object containing `width`, `height` and `channels` when providing uncompressed data.
|
|
||||||
|
|
||||||
### Output
|
|
||||||
|
|
||||||
#### toFile(path, [callback])
|
|
||||||
|
|
||||||
`path` is a String containing the path to write the image data to.
|
|
||||||
|
|
||||||
If an explicit output format is not selected, it will be inferred from the extension, with JPEG, PNG, WebP, TIFF, DZI, and VIPS V format supported. Note that RAW format is only supported for buffer output.
|
|
||||||
|
|
||||||
`callback`, if present, is called with two arguments `(err, info)` where:
|
|
||||||
|
|
||||||
* `err` contains an error message, if any.
|
|
||||||
* `info` contains the output image `format`, `size` (bytes), `width`, `height` and `channels`.
|
|
||||||
|
|
||||||
A Promises/A+ promise is returned when `callback` is not provided.
|
|
||||||
|
|
||||||
#### toBuffer([callback])
|
|
||||||
|
|
||||||
Write image data to a Buffer, the format of which will match the input image by default. JPEG, PNG, WebP, and RAW are supported.
|
|
||||||
|
|
||||||
`callback`, if present, gets three arguments `(err, buffer, info)` where:
|
|
||||||
|
|
||||||
* `err` is an error message, if any.
|
|
||||||
* `buffer` is the output image data.
|
|
||||||
* `info` contains the output image `format`, `size` (bytes), `width`, `height` and `channels`.
|
|
||||||
|
|
||||||
A Promises/A+ promise is returned when `callback` is not provided.
|
|
||||||
|
|
||||||
#### jpeg([options])
|
|
||||||
|
|
||||||
Use JPEG format for the output image.
|
|
||||||
|
|
||||||
`options`, if present, is an Object with the following optional attributes:
|
|
||||||
|
|
||||||
* `quality` is an integral Number between 1 and 100, default 80. Using quality >90 forces a `chromaSubsampling` value of '4:4:4'.
|
|
||||||
* `progressive` is a Boolean to control the use of progressive (interlace) scan, default false.
|
|
||||||
* `chromaSubsampling` is a String with the value '4:2:0' (default) or '4:4:4' to control [chroma subsampling](http://en.wikipedia.org/wiki/Chroma_subsampling).
|
|
||||||
* `force` is a Boolean, where true (default) will force the use of JPEG output and false will use the input format.
|
|
||||||
|
|
||||||
The following, additional options require libvips to have been compiled with mozjpeg support:
|
|
||||||
|
|
||||||
* `trellisQuantisation` / `trellisQuantization` is a Boolean, default false, to control the use of [trellis quantisation](http://en.wikipedia.org/wiki/Trellis_quantization).
|
|
||||||
* `overshootDeringing` is a Boolean, default false, to reduce the effects of [ringing](http://en.wikipedia.org/wiki/Ringing_%28signal%29).
|
|
||||||
* `optimiseScans` / `optimizeScans` is a Boolean, default false, when true calculates which spectrum of DCT coefficients uses the fewest bits for each progressive scan.
|
|
||||||
|
|
||||||
#### png([options])
|
|
||||||
|
|
||||||
Use PNG format for the output image.
|
|
||||||
|
|
||||||
`options`, if present, is an Object with the following optional attributes:
|
|
||||||
|
|
||||||
* `progressive` is a Boolean to control the use of progressive (interlace) scan, default false.
|
|
||||||
* `compressionLevel` is an integral Number between 0 and 9, default 6, to set the _zlib_ compression level.
|
|
||||||
* `adaptiveFiltering` is a Boolean to control [adaptive row filtering](https://en.wikipedia.org/wiki/Portable_Network_Graphics#Filtering), true for adaptive (default), false for none.
|
|
||||||
* `force` is a Boolean, where true (default) will force the use of PNG output and false will use the input format.
|
|
||||||
|
|
||||||
#### webp([options])
|
|
||||||
|
|
||||||
Use WebP format for the output image.
|
|
||||||
|
|
||||||
`options`, if present, is an Object with the following optional attributes:
|
|
||||||
|
|
||||||
* `quality` is an integral Number between 1 and 100, default 80.
|
|
||||||
* `force` is a Boolean, where true (default) will force the use of WebP output and false will use the input format.
|
|
||||||
|
|
||||||
#### tiff([options])
|
|
||||||
|
|
||||||
Use TIFF format for the output image.
|
|
||||||
|
|
||||||
`options`, if present, is an Object with the following optional attributes:
|
|
||||||
|
|
||||||
* `quality` is an integral Number between 1 and 100, default 80.
|
|
||||||
* `force` is a Boolean, where true (default) will force the use of TIFF output and false will use the input format.
|
|
||||||
|
|
||||||
#### raw()
|
|
||||||
|
|
||||||
Provide raw, uncompressed uint8 (unsigned char) image data for Buffer and Stream based output.
|
|
||||||
|
|
||||||
The number of channels depends on the input image and selected options.
|
|
||||||
|
|
||||||
* 1 channel for images converted to `greyscale()`, with each byte representing one pixel.
|
|
||||||
* 3 channels for colour images without alpha transparency, with bytes ordered \[red, green, blue, red, green, blue, etc.\]).
|
|
||||||
* 4 channels for colour images with alpha transparency, with bytes ordered \[red, green, blue, alpha, red, green, blue, alpha, etc.\].
|
|
||||||
|
|
||||||
#### toFormat(format, [options])
|
|
||||||
|
|
||||||
Convenience method for the above output format methods, where `format` is either:
|
|
||||||
|
|
||||||
* an attribute of the `sharp.format` Object e.g. `sharp.format.jpeg`, or
|
|
||||||
* a String containing `jpeg`, `png`, `webp`, `tiff` or `raw`.
|
|
||||||
|
|
||||||
#### withMetadata([metadata])
|
|
||||||
|
|
||||||
Include all metadata (EXIF, XMP, IPTC) from the input image in the output image.
|
|
||||||
This will also convert to and add the latest web-friendly v2 sRGB ICC profile.
|
|
||||||
|
|
||||||
The optional `metadata` parameter, if present, is an Object with the attributes to update.
|
|
||||||
New attributes cannot be inserted, only existing attributes updated.
|
|
||||||
|
|
||||||
* `orientation` is an integral Number between 1 and 8, used to update the value of the EXIF `Orientation` tag.
|
|
||||||
This has no effect if the input image does not have an EXIF `Orientation` tag.
|
|
||||||
|
|
||||||
The default behaviour, when `withMetadata` is not used, is to strip all metadata and convert to the device-independent sRGB colour space.
|
|
||||||
|
|
||||||
#### tile(options)
|
|
||||||
|
|
||||||
The size, overlap, container and directory layout to use when generating square Deep Zoom image pyramid tiles.
|
|
||||||
|
|
||||||
`options` is an Object with one or more of the following attributes:
|
|
||||||
|
|
||||||
* `size` is an integral Number between 1 and 8192. The default value is 256 pixels.
|
|
||||||
* `overlap` is an integral Number between 0 and 8192. The default value is 0 pixels.
|
|
||||||
* `container` is a String, with value `fs` or `zip`. The default value is `fs`.
|
|
||||||
* `layout` is a String, with value `dz`, `zoomify` or `google`. The default value is `dz`.
|
|
||||||
|
|
||||||
You can also use the file extension `.zip` or `.szi` to write to a compressed archive file format.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
sharp('input.tiff')
|
|
||||||
.tile({
|
|
||||||
size: 512
|
|
||||||
})
|
|
||||||
.toFile('output.dzi', function(err, info) {
|
|
||||||
// output.dzi is the Deep Zoom XML definition
|
|
||||||
// output_files contains 512x512 tiles grouped by zoom level
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### Attributes
|
|
||||||
|
|
||||||
#### format
|
|
||||||
|
|
||||||
An Object containing nested boolean values
|
|
||||||
representing the available input and output formats/methods,
|
|
||||||
for example:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
> console.dir(sharp.format);
|
|
||||||
|
|
||||||
{ jpeg: { id: 'jpeg',
|
|
||||||
input: { file: true, buffer: true, stream: true },
|
|
||||||
output: { file: true, buffer: true, stream: true } },
|
|
||||||
png: { id: 'png',
|
|
||||||
input: { file: true, buffer: true, stream: true },
|
|
||||||
output: { file: true, buffer: true, stream: true } },
|
|
||||||
webp: { id: 'webp',
|
|
||||||
input: { file: true, buffer: true, stream: true },
|
|
||||||
output: { file: true, buffer: true, stream: true } },
|
|
||||||
tiff: { id: 'tiff',
|
|
||||||
input: { file: true, buffer: true, stream: true },
|
|
||||||
output: { file: true, buffer: false, stream: false } },
|
|
||||||
raw: { id: 'raw',
|
|
||||||
input: { file: false, buffer: false, stream: false },
|
|
||||||
output: { file: false, buffer: true, stream: true } } }
|
|
||||||
```
|
|
||||||
|
|
||||||
#### queue
|
|
||||||
|
|
||||||
An EventEmitter that emits a `change` event when a task is either:
|
|
||||||
|
|
||||||
* queued, waiting for _libuv_ to provide a worker thread
|
|
||||||
* complete
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
sharp.queue.on('change', function(queueLength) {
|
|
||||||
console.log('Queue contains ' + queueLength + ' task(s)');
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
#### versions
|
|
||||||
|
|
||||||
An Object containing the version numbers of libvips and, on Linux, its dependencies.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
console.log(sharp.versions);
|
|
||||||
```
|
|
||||||
|
|
||||||
### Utilities
|
|
||||||
|
|
||||||
#### sharp.cache([options])
|
|
||||||
|
|
||||||
If `options` is provided, sets the limits of _libvips'_ operation cache.
|
|
||||||
|
|
||||||
* `options.memory` is the maximum memory in MB to use for this cache, with a default value of 50
|
|
||||||
* `options.files` is the maximum number of files to hold open, with a default value of 20
|
|
||||||
* `options.items` is the maximum number of operations to cache, with a default value of 100
|
|
||||||
|
|
||||||
`options` can also be a boolean, where `true` enables the default cache settings and `false` disables all caching.
|
|
||||||
|
|
||||||
Existing entries in the cache will be trimmed after any change in limits.
|
|
||||||
|
|
||||||
This method always returns cache statistics, useful for determining how much working memory is required for a particular task.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var stats = sharp.cache();
|
|
||||||
```
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
sharp.cache( { items: 200 } );
|
|
||||||
sharp.cache( { files: 0 } );
|
|
||||||
sharp.cache(false);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### sharp.concurrency([threads])
|
|
||||||
|
|
||||||
`threads`, if provided, is the Number of threads _libvips'_ should create for processing each image. The default value is the number of CPU cores. A value of `0` will reset to this default.
|
|
||||||
|
|
||||||
This method always returns the current concurrency.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var threads = sharp.concurrency(); // 4
|
|
||||||
sharp.concurrency(2); // 2
|
|
||||||
sharp.concurrency(0); // 4
|
|
||||||
```
|
|
||||||
|
|
||||||
The maximum number of images that can be processed in parallel is limited by libuv's `UV_THREADPOOL_SIZE` environment variable.
|
|
||||||
|
|
||||||
#### sharp.counters()
|
|
||||||
|
|
||||||
Provides access to internal task counters.
|
|
||||||
|
|
||||||
* `queue` is the number of tasks this module has queued waiting for _libuv_ to provide a worker thread from its pool.
|
|
||||||
* `process` is the number of resize tasks currently being processed.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var counters = sharp.counters(); // { queue: 2, process: 4 }
|
|
||||||
```
|
|
||||||
|
|
||||||
#### sharp.simd([enable])
|
|
||||||
|
|
||||||
_Requires libvips to have been compiled with liborc support_
|
|
||||||
|
|
||||||
Improves the performance of `resize`, `blur` and `sharpen` operations
|
|
||||||
by taking advantage of the SIMD vector unit of the CPU, e.g. Intel SSE and ARM NEON.
|
|
||||||
|
|
||||||
* `enable`, if present, is a boolean where `true` enables and `false` disables the use of SIMD.
|
|
||||||
|
|
||||||
This method always returns the current state.
|
|
||||||
|
|
||||||
This feature is currently disabled by default
|
|
||||||
but future versions may enable it by default.
|
|
||||||
|
|
||||||
When enabled, versions of liborc prior to 0.4.24
|
|
||||||
and versions of libvips prior to 8.2.0
|
|
||||||
have been known to crash under heavy load.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var simd = sharp.simd();
|
|
||||||
// simd is `true` if SIMD is currently enabled
|
|
||||||
```
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var simd = sharp.simd(true);
|
|
||||||
// attempts to enable the use of SIMD, returning true if available
|
|
||||||
```
|
|
@ -4,8 +4,13 @@
|
|||||||
npm install sharp
|
npm install sharp
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```sh
|
||||||
|
yarn add sharp
|
||||||
|
```
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
|
* Node v4+
|
||||||
* C++11 compatible compiler such as gcc 4.8+, clang 3.0+ or MSVC 2013+
|
* C++11 compatible compiler such as gcc 4.8+, clang 3.0+ or MSVC 2013+
|
||||||
* [node-gyp](https://github.com/TooTallNate/node-gyp#installation) and its dependencies
|
* [node-gyp](https://github.com/TooTallNate/node-gyp#installation) and its dependencies
|
||||||
|
|
||||||
|
113
lib/channel.js
Normal file
113
lib/channel.js
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const is = require('./is');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boolean operations for bandbool.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const bool = {
|
||||||
|
and: 'and',
|
||||||
|
or: 'or',
|
||||||
|
eor: 'eor'
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract a single channel from a multi-channel image.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* sharp(input)
|
||||||
|
* .extractChannel('green')
|
||||||
|
* .toFile('input_green.jpg', function(err, info) {
|
||||||
|
* // info.channels === 1
|
||||||
|
* // input_green.jpg contains the green channel of the input image
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* @param {Number|String} channel - zero-indexed band number to extract, or `red`, `green` or `blue` as alternative to `0`, `1` or `2` respectively.
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid channel
|
||||||
|
*/
|
||||||
|
const extractChannel = function extractChannel (channel) {
|
||||||
|
if (channel === 'red') {
|
||||||
|
channel = 0;
|
||||||
|
} else if (channel === 'green') {
|
||||||
|
channel = 1;
|
||||||
|
} else if (channel === 'blue') {
|
||||||
|
channel = 2;
|
||||||
|
}
|
||||||
|
if (is.integer(channel) && is.inRange(channel, 0, 4)) {
|
||||||
|
this.options.extractChannel = channel;
|
||||||
|
} else {
|
||||||
|
throw new Error('Cannot extract invalid channel ' + channel);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Join one or more channels to the image.
|
||||||
|
* The meaning of the added channels depends on the output colourspace, set with `toColourspace()`.
|
||||||
|
* By default the output image will be web-friendly sRGB, with additional channels interpreted as alpha channels.
|
||||||
|
* Channel ordering follows vips convention:
|
||||||
|
* - sRGB: 0: Red, 1: Green, 2: Blue, 3: Alpha.
|
||||||
|
* - CMYK: 0: Magenta, 1: Cyan, 2: Yellow, 3: Black, 4: Alpha.
|
||||||
|
*
|
||||||
|
* Buffers may be any of the image formats supported by sharp: JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data.
|
||||||
|
* For raw pixel input, the `options` object should contain a `raw` attribute, which follows the format of the attribute of the same name in the `sharp()` constructor.
|
||||||
|
*
|
||||||
|
* @param {Array|String|Buffer} images - one or more images (file paths, Buffers).
|
||||||
|
* @param {Object} options - image options, see `sharp()` constructor.
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid parameters
|
||||||
|
*/
|
||||||
|
const joinChannel = function joinChannel (images, options) {
|
||||||
|
if (Array.isArray(images)) {
|
||||||
|
images.forEach(function (image) {
|
||||||
|
this.options.joinChannelIn.push(this._createInputDescriptor(image, options));
|
||||||
|
}, this);
|
||||||
|
} else {
|
||||||
|
this.options.joinChannelIn.push(this._createInputDescriptor(images, options));
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a bitwise boolean operation on all input image channels (bands) to produce a single channel output image.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* sharp('3-channel-rgb-input.png')
|
||||||
|
* .bandbool(sharp.bool.and)
|
||||||
|
* .toFile('1-channel-output.png', function (err, info) {
|
||||||
|
* // The output will be a single channel image where each pixel `P = R & G & B`.
|
||||||
|
* // If `I(1,1) = [247, 170, 14] = [0b11110111, 0b10101010, 0b00001111]`
|
||||||
|
* // then `O(1,1) = 0b11110111 & 0b10101010 & 0b00001111 = 0b00000010 = 2`.
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* @param {String} boolOp - one of `and`, `or` or `eor` to perform that bitwise operation, like the C logic operators `&`, `|` and `^` respectively.
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid parameters
|
||||||
|
*/
|
||||||
|
const bandbool = function bandbool (boolOp) {
|
||||||
|
if (is.string(boolOp) && is.inArray(boolOp, ['and', 'or', 'eor'])) {
|
||||||
|
this.options.bandBoolOp = boolOp;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid bandbool operation ' + boolOp);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decorate the Sharp prototype with channel-related functions.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
module.exports = function (Sharp) {
|
||||||
|
// Public instance functions
|
||||||
|
[
|
||||||
|
extractChannel,
|
||||||
|
joinChannel,
|
||||||
|
bandbool
|
||||||
|
].forEach(function (f) {
|
||||||
|
Sharp.prototype[f.name] = f;
|
||||||
|
});
|
||||||
|
// Class attributes
|
||||||
|
Sharp.bool = bool;
|
||||||
|
};
|
104
lib/colour.js
Normal file
104
lib/colour.js
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const color = require('color');
|
||||||
|
const is = require('./is');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Colourspaces.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const colourspace = {
|
||||||
|
multiband: 'multiband',
|
||||||
|
'b-w': 'b-w',
|
||||||
|
bw: 'b-w',
|
||||||
|
cmyk: 'cmyk',
|
||||||
|
srgb: 'srgb'
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the background for the `embed`, `flatten` and `extend` operations.
|
||||||
|
* The default background is `{r: 0, g: 0, b: 0, a: 1}`, black without transparency.
|
||||||
|
*
|
||||||
|
* Delegates to the _color_ module, which can throw an Error
|
||||||
|
* but is liberal in what it accepts, clipping values to sensible min/max.
|
||||||
|
* The alpha value is a float between `0` (transparent) and `1` (opaque).
|
||||||
|
*
|
||||||
|
* @param {String|Object} rgba - parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha.
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid parameter
|
||||||
|
*/
|
||||||
|
const background = function background (rgba) {
|
||||||
|
const colour = color(rgba);
|
||||||
|
this.options.background = colour.rgbArray();
|
||||||
|
this.options.background.push(colour.alpha() * 255);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* By default the output image will be web-friendly sRGB and contain three (identical) color channels.
|
||||||
|
* This may be overridden by other sharp operations such as `toColourspace('b-w')`,
|
||||||
|
* which will produce an output image containing one color channel.
|
||||||
|
* An alpha channel may be present, and will be unchanged by the operation.
|
||||||
|
* @param {Boolean} [greyscale=true]
|
||||||
|
* @returns {Sharp}
|
||||||
|
*/
|
||||||
|
const greyscale = function greyscale (greyscale) {
|
||||||
|
this.options.greyscale = is.bool(greyscale) ? greyscale : true;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alternative spelling of `greyscale`.
|
||||||
|
* @param {Boolean} [grayscale=true]
|
||||||
|
* @returns {Sharp}
|
||||||
|
*/
|
||||||
|
const grayscale = function grayscale (grayscale) {
|
||||||
|
return this.greyscale(grayscale);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the output colourspace.
|
||||||
|
* By default output image will be web-friendly sRGB, with additional channels interpreted as alpha channels.
|
||||||
|
* @param {String} [colourspace] - output colourspace e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://github.com/jcupitt/libvips/blob/master/libvips/iofuncs/enumtypes.c#L568)
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid parameters
|
||||||
|
*/
|
||||||
|
const toColourspace = function toColourspace (colourspace) {
|
||||||
|
if (!is.string(colourspace)) {
|
||||||
|
throw new Error('Invalid output colourspace ' + colourspace);
|
||||||
|
}
|
||||||
|
this.options.colourspace = colourspace;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alternative spelling of `toColourspace`.
|
||||||
|
* @param {String} [colorspace] - output colorspace.
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid parameters
|
||||||
|
*/
|
||||||
|
const toColorspace = function toColorspace (colorspace) {
|
||||||
|
return this.toColourspace(colorspace);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decorate the Sharp prototype with colour-related functions.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
module.exports = function (Sharp) {
|
||||||
|
// Public instance functions
|
||||||
|
[
|
||||||
|
background,
|
||||||
|
greyscale,
|
||||||
|
grayscale,
|
||||||
|
toColourspace,
|
||||||
|
toColorspace
|
||||||
|
].forEach(function (f) {
|
||||||
|
Sharp.prototype[f.name] = f;
|
||||||
|
});
|
||||||
|
// Class attributes
|
||||||
|
Sharp.colourspace = colourspace;
|
||||||
|
Sharp.colorspace = colourspace;
|
||||||
|
};
|
92
lib/composite.js
Normal file
92
lib/composite.js
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const is = require('./is');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overlay (composite) an image over the processed (resized, extracted etc.) image.
|
||||||
|
*
|
||||||
|
* The overlay image must be the same size or smaller than the processed image.
|
||||||
|
* If both `top` and `left` options are provided, they take precedence over `gravity`.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* sharp('input.png')
|
||||||
|
* .rotate(180)
|
||||||
|
* .resize(300)
|
||||||
|
* .flatten()
|
||||||
|
* .background('#ff6600')
|
||||||
|
* .overlayWith('overlay.png', { gravity: sharp.gravity.southeast } )
|
||||||
|
* .sharpen()
|
||||||
|
* .withMetadata()
|
||||||
|
* .quality(90)
|
||||||
|
* .webp()
|
||||||
|
* .toBuffer()
|
||||||
|
* .then(function(outputBuffer) {
|
||||||
|
* // outputBuffer contains upside down, 300px wide, alpha channel flattened
|
||||||
|
* // onto orange background, composited with overlay.png with SE gravity,
|
||||||
|
* // sharpened, with metadata, 90% quality WebP image data. Phew!
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* @param {(Buffer|String)} overlay - Buffer containing image data or String containing the path to an image file.
|
||||||
|
* @param {Object} [options]
|
||||||
|
* @param {String} [options.gravity='centre'] - gravity at which to place the overlay.
|
||||||
|
* @param {Number} [options.top] - the pixel offset from the top edge.
|
||||||
|
* @param {Number} [options.left] - the pixel offset from the left edge.
|
||||||
|
* @param {Boolean} [options.tile=false] - set to true to repeat the overlay image across the entire image with the given `gravity`.
|
||||||
|
* @param {Boolean} [options.cutout=false] - set to true to apply only the alpha channel of the overlay image to the input image, giving the appearance of one image being cut out of another.
|
||||||
|
* @param {Object} [options.raw] - describes overlay when using raw pixel data.
|
||||||
|
* @param {Number} [options.raw.width]
|
||||||
|
* @param {Number} [options.raw.height]
|
||||||
|
* @param {Number} [options.raw.channels]
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid parameters
|
||||||
|
*/
|
||||||
|
const overlayWith = function overlayWith (overlay, options) {
|
||||||
|
this.options.overlay = this._createInputDescriptor(overlay, options, {
|
||||||
|
allowStream: false
|
||||||
|
});
|
||||||
|
if (is.object(options)) {
|
||||||
|
if (is.defined(options.tile)) {
|
||||||
|
if (is.bool(options.tile)) {
|
||||||
|
this.options.overlayTile = options.tile;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid overlay tile ' + options.tile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (is.defined(options.cutout)) {
|
||||||
|
if (is.bool(options.cutout)) {
|
||||||
|
this.options.overlayCutout = options.cutout;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid overlay cutout ' + options.cutout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (is.defined(options.left) || is.defined(options.top)) {
|
||||||
|
if (
|
||||||
|
is.integer(options.left) && is.inRange(options.left, 0, this.constructor.maximum.width) &&
|
||||||
|
is.integer(options.top) && is.inRange(options.top, 0, this.constructor.maximum.height)
|
||||||
|
) {
|
||||||
|
this.options.overlayXOffset = options.left;
|
||||||
|
this.options.overlayYOffset = options.top;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid overlay left ' + options.left + ' and/or top ' + options.top);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (is.defined(options.gravity)) {
|
||||||
|
if (is.integer(options.gravity) && is.inRange(options.gravity, 0, 8)) {
|
||||||
|
this.options.overlayGravity = options.gravity;
|
||||||
|
} else if (is.string(options.gravity) && is.integer(this.constructor.gravity[options.gravity])) {
|
||||||
|
this.options.overlayGravity = this.constructor.gravity[options.gravity];
|
||||||
|
} else {
|
||||||
|
throw new Error('Unsupported overlay gravity ' + options.gravity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decorate the Sharp prototype with composite-related functions.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
module.exports = function (Sharp) {
|
||||||
|
Sharp.prototype.overlayWith = overlayWith;
|
||||||
|
};
|
204
lib/constructor.js
Normal file
204
lib/constructor.js
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
const util = require('util');
|
||||||
|
const stream = require('stream');
|
||||||
|
const events = require('events');
|
||||||
|
const semver = require('semver');
|
||||||
|
const sharp = require('../build/Release/sharp.node');
|
||||||
|
|
||||||
|
// Versioning
|
||||||
|
let versions = {
|
||||||
|
vips: sharp.libvipsVersion()
|
||||||
|
};
|
||||||
|
(function () {
|
||||||
|
// Does libvips meet minimum requirement?
|
||||||
|
const libvipsVersionMin = require('../package.json').config.libvips;
|
||||||
|
if (semver.lt(versions.vips, libvipsVersionMin)) {
|
||||||
|
throw new Error('Found libvips ' + versions.vips + ' but require at least ' + libvipsVersionMin);
|
||||||
|
}
|
||||||
|
// Include versions of dependencies, if present
|
||||||
|
try {
|
||||||
|
versions = require('../vendor/lib/versions.json');
|
||||||
|
} catch (err) {}
|
||||||
|
})();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name sharp
|
||||||
|
*
|
||||||
|
* Constructor factory to create an instance of `sharp`, to which further methods are chained.
|
||||||
|
*
|
||||||
|
* JPEG, PNG or WebP format image data can be streamed out from this object.
|
||||||
|
* When using Stream based output, derived attributes are available from the `info` event.
|
||||||
|
*
|
||||||
|
* Implements the [stream.Duplex](http://nodejs.org/api/stream.html#stream_class_stream_duplex) class.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* sharp('input.jpg')
|
||||||
|
* .resize(300, 200)
|
||||||
|
* .toFile('output.jpg', function(err) {
|
||||||
|
* // output.jpg is a 300 pixels wide and 200 pixels high image
|
||||||
|
* // containing a scaled and cropped version of input.jpg
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Read image data from readableStream,
|
||||||
|
* // resize to 300 pixels wide,
|
||||||
|
* // emit an 'info' event with calculated dimensions
|
||||||
|
* // and finally write image data to writableStream
|
||||||
|
* var transformer = sharp()
|
||||||
|
* .resize(300)
|
||||||
|
* .on('info', function(info) {
|
||||||
|
* console.log('Image height is ' + info.height);
|
||||||
|
* });
|
||||||
|
* readableStream.pipe(transformer).pipe(writableStream);
|
||||||
|
*
|
||||||
|
* @param {(Buffer|String)} [input] - if present, can be
|
||||||
|
* a Buffer containing JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data, or
|
||||||
|
* a String containing the path to an JPEG, PNG, WebP, GIF, SVG or TIFF image file.
|
||||||
|
* JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data can be streamed into the object when null or undefined.
|
||||||
|
* @param {Object} [options] - if present, is an Object with optional attributes.
|
||||||
|
* @param {Number} [options.density=72] - integral number representing the DPI for vector images.
|
||||||
|
* @param {Object} [options.raw] - describes raw pixel image data. See `raw()` for pixel ordering.
|
||||||
|
* @param {Number} [options.raw.width]
|
||||||
|
* @param {Number} [options.raw.height]
|
||||||
|
* @param {Number} [options.raw.channels]
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid parameters
|
||||||
|
*/
|
||||||
|
const Sharp = function (input, options) {
|
||||||
|
if (!(this instanceof Sharp)) {
|
||||||
|
return new Sharp(input, options);
|
||||||
|
}
|
||||||
|
stream.Duplex.call(this);
|
||||||
|
this.options = {
|
||||||
|
// input options
|
||||||
|
sequentialRead: false,
|
||||||
|
limitInputPixels: maximum.pixels,
|
||||||
|
// ICC profiles
|
||||||
|
iccProfilePath: path.join(__dirname, 'icc') + path.sep,
|
||||||
|
// resize options
|
||||||
|
topOffsetPre: -1,
|
||||||
|
leftOffsetPre: -1,
|
||||||
|
widthPre: -1,
|
||||||
|
heightPre: -1,
|
||||||
|
topOffsetPost: -1,
|
||||||
|
leftOffsetPost: -1,
|
||||||
|
widthPost: -1,
|
||||||
|
heightPost: -1,
|
||||||
|
width: -1,
|
||||||
|
height: -1,
|
||||||
|
canvas: 'crop',
|
||||||
|
crop: 0,
|
||||||
|
angle: 0,
|
||||||
|
rotateBeforePreExtract: false,
|
||||||
|
flip: false,
|
||||||
|
flop: false,
|
||||||
|
extendTop: 0,
|
||||||
|
extendBottom: 0,
|
||||||
|
extendLeft: 0,
|
||||||
|
extendRight: 0,
|
||||||
|
withoutEnlargement: false,
|
||||||
|
kernel: 'lanczos3',
|
||||||
|
interpolator: 'bicubic',
|
||||||
|
// operations
|
||||||
|
background: [0, 0, 0, 255],
|
||||||
|
flatten: false,
|
||||||
|
negate: false,
|
||||||
|
blurSigma: 0,
|
||||||
|
sharpenSigma: 0,
|
||||||
|
sharpenFlat: 1,
|
||||||
|
sharpenJagged: 2,
|
||||||
|
threshold: 0,
|
||||||
|
thresholdGrayscale: true,
|
||||||
|
trimTolerance: 0,
|
||||||
|
gamma: 0,
|
||||||
|
greyscale: false,
|
||||||
|
normalise: 0,
|
||||||
|
booleanBufferIn: null,
|
||||||
|
booleanFileIn: '',
|
||||||
|
joinChannelIn: [],
|
||||||
|
extractChannel: -1,
|
||||||
|
colourspace: 'srgb',
|
||||||
|
// overlay
|
||||||
|
overlayGravity: 0,
|
||||||
|
overlayXOffset: -1,
|
||||||
|
overlayYOffset: -1,
|
||||||
|
overlayTile: false,
|
||||||
|
overlayCutout: false,
|
||||||
|
// output
|
||||||
|
fileOut: '',
|
||||||
|
formatOut: 'input',
|
||||||
|
streamOut: false,
|
||||||
|
withMetadata: false,
|
||||||
|
withMetadataOrientation: -1,
|
||||||
|
// output format
|
||||||
|
jpegQuality: 80,
|
||||||
|
jpegProgressive: false,
|
||||||
|
jpegChromaSubsampling: '4:2:0',
|
||||||
|
jpegTrellisQuantisation: false,
|
||||||
|
jpegOvershootDeringing: false,
|
||||||
|
jpegOptimiseScans: false,
|
||||||
|
pngProgressive: false,
|
||||||
|
pngCompressionLevel: 6,
|
||||||
|
pngAdaptiveFiltering: true,
|
||||||
|
webpQuality: 80,
|
||||||
|
tiffQuality: 80,
|
||||||
|
tileSize: 256,
|
||||||
|
tileOverlap: 0,
|
||||||
|
// Function to notify of queue length changes
|
||||||
|
queueListener: function (queueLength) {
|
||||||
|
queue.emit('change', queueLength);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.options.input = this._createInputDescriptor(input, options, { allowStream: true });
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
util.inherits(Sharp, stream.Duplex);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pixel limits.
|
||||||
|
* @member
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const maximum = {
|
||||||
|
width: 0x3FFF,
|
||||||
|
height: 0x3FFF,
|
||||||
|
pixels: Math.pow(0x3FFF, 2)
|
||||||
|
};
|
||||||
|
Sharp.maximum = maximum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An EventEmitter that emits a `change` event when a task is either:
|
||||||
|
* - queued, waiting for _libuv_ to provide a worker thread
|
||||||
|
* - complete
|
||||||
|
* @member
|
||||||
|
* @example
|
||||||
|
* sharp.queue.on('change', function(queueLength) {
|
||||||
|
* console.log('Queue contains ' + queueLength + ' task(s)');
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
const queue = new events.EventEmitter();
|
||||||
|
Sharp.queue = queue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An Object containing nested boolean values representing the available input and output formats/methods.
|
||||||
|
* @example
|
||||||
|
* console.log(sharp.format());
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
Sharp.format = sharp.format();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An Object containing the version numbers of libvips and its dependencies.
|
||||||
|
* @member
|
||||||
|
* @example
|
||||||
|
* console.log(sharp.versions);
|
||||||
|
*/
|
||||||
|
Sharp.versions = versions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export constructor.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
module.exports = Sharp;
|
17
lib/index.js
Normal file
17
lib/index.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const Sharp = require('./constructor');
|
||||||
|
[
|
||||||
|
'input',
|
||||||
|
'resize',
|
||||||
|
'composite',
|
||||||
|
'operation',
|
||||||
|
'colour',
|
||||||
|
'channel',
|
||||||
|
'output',
|
||||||
|
'utility'
|
||||||
|
].forEach(function (decorator) {
|
||||||
|
require('./' + decorator)(Sharp);
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = Sharp;
|
250
lib/input.js
Normal file
250
lib/input.js
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const util = require('util');
|
||||||
|
const is = require('./is');
|
||||||
|
const sharp = require('../build/Release/sharp.node');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create Object containing input and input-related options.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const _createInputDescriptor = function _createInputDescriptor (input, inputOptions, containerOptions) {
|
||||||
|
const inputDescriptor = {};
|
||||||
|
if (is.string(input)) {
|
||||||
|
// filesystem
|
||||||
|
inputDescriptor.file = input;
|
||||||
|
} else if (is.buffer(input)) {
|
||||||
|
// Buffer
|
||||||
|
inputDescriptor.buffer = input;
|
||||||
|
} else if (!is.defined(input) && is.object(containerOptions) && containerOptions.allowStream) {
|
||||||
|
// Stream
|
||||||
|
inputDescriptor.buffer = [];
|
||||||
|
} else {
|
||||||
|
throw new Error('Unsupported input ' + typeof input);
|
||||||
|
}
|
||||||
|
if (is.object(inputOptions)) {
|
||||||
|
// Density
|
||||||
|
if (is.defined(inputOptions.density)) {
|
||||||
|
if (is.integer(inputOptions.density) && is.inRange(inputOptions.density, 1, 2400)) {
|
||||||
|
inputDescriptor.density = inputOptions.density;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid density (1 to 2400) ' + inputOptions.density);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Raw pixel input
|
||||||
|
if (is.defined(inputOptions.raw)) {
|
||||||
|
if (
|
||||||
|
is.object(inputOptions.raw) &&
|
||||||
|
is.integer(inputOptions.raw.width) && is.inRange(inputOptions.raw.width, 1, this.constructor.maximum.width) &&
|
||||||
|
is.integer(inputOptions.raw.height) && is.inRange(inputOptions.raw.height, 1, this.constructor.maximum.height) &&
|
||||||
|
is.integer(inputOptions.raw.channels) && is.inRange(inputOptions.raw.channels, 1, 4)
|
||||||
|
) {
|
||||||
|
inputDescriptor.rawWidth = inputOptions.raw.width;
|
||||||
|
inputDescriptor.rawHeight = inputOptions.raw.height;
|
||||||
|
inputDescriptor.rawChannels = inputOptions.raw.channels;
|
||||||
|
} else {
|
||||||
|
throw new Error('Expected width, height and channels for raw pixel input');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (is.defined(inputOptions)) {
|
||||||
|
throw new Error('Invalid input options ' + inputOptions);
|
||||||
|
}
|
||||||
|
return inputDescriptor;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle incoming Buffer chunk on Writable Stream.
|
||||||
|
* @private
|
||||||
|
* @param {Buffer} chunk
|
||||||
|
* @param {String} encoding - unused
|
||||||
|
* @param {Function} callback
|
||||||
|
*/
|
||||||
|
const _write = function _write (chunk, encoding, callback) {
|
||||||
|
if (Array.isArray(this.options.input.buffer)) {
|
||||||
|
if (is.buffer(chunk)) {
|
||||||
|
this.options.input.buffer.push(chunk);
|
||||||
|
callback();
|
||||||
|
} else {
|
||||||
|
callback(new Error('Non-Buffer data on Writable Stream'));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
callback(new Error('Unexpected data on Writable Stream'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flattens the array of chunks accumulated in input.buffer.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const _flattenBufferIn = function _flattenBufferIn () {
|
||||||
|
if (this._isStreamInput()) {
|
||||||
|
this.options.input.buffer = Buffer.concat(this.options.input.buffer);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Are we expecting Stream-based input?
|
||||||
|
* @private
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
const _isStreamInput = function _isStreamInput () {
|
||||||
|
return Array.isArray(this.options.input.buffer);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Take a "snapshot" of the Sharp instance, returning a new instance.
|
||||||
|
* Cloned instances inherit the input of their parent instance.
|
||||||
|
* This allows multiple output Streams and therefore multiple processing pipelines to share a single input Stream.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const pipeline = sharp().rotate();
|
||||||
|
* pipeline.clone().resize(800, 600).pipe(firstWritableStream);
|
||||||
|
* pipeline.clone().extract({ left: 20, top: 20, width: 100, height: 100 }).pipe(secondWritableStream);
|
||||||
|
* readableStream.pipe(pipeline);
|
||||||
|
* // firstWritableStream receives auto-rotated, resized readableStream
|
||||||
|
* // secondWritableStream receives auto-rotated, extracted region of readableStream
|
||||||
|
*
|
||||||
|
* @returns {Sharp}
|
||||||
|
*/
|
||||||
|
const clone = function clone () {
|
||||||
|
const that = this;
|
||||||
|
// Clone existing options
|
||||||
|
const clone = this.constructor.call();
|
||||||
|
util._extend(clone.options, this.options);
|
||||||
|
// Pass 'finish' event to clone for Stream-based input
|
||||||
|
this.on('finish', function () {
|
||||||
|
// Clone inherits input data
|
||||||
|
that._flattenBufferIn();
|
||||||
|
clone.options.bufferIn = that.options.bufferIn;
|
||||||
|
clone.emit('finish');
|
||||||
|
});
|
||||||
|
return clone;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fast access to image metadata without decoding any compressed image data.
|
||||||
|
* A Promises/A+ promise is returned when `callback` is not provided.
|
||||||
|
*
|
||||||
|
* - `format`: Name of decoder used to decompress image data e.g. `jpeg`, `png`, `webp`, `gif`, `svg`
|
||||||
|
* - `width`: Number of pixels wide
|
||||||
|
* - `height`: Number of pixels high
|
||||||
|
* - `space`: Name of colour space interpretation e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://github.com/jcupitt/libvips/blob/master/libvips/iofuncs/enumtypes.c#L568)
|
||||||
|
* - `channels`: Number of bands e.g. `3` for sRGB, `4` for CMYK
|
||||||
|
* - `density`: Number of pixels per inch (DPI), if present
|
||||||
|
* - `hasProfile`: Boolean indicating the presence of an embedded ICC profile
|
||||||
|
* - `hasAlpha`: Boolean indicating the presence of an alpha transparency channel
|
||||||
|
* - `orientation`: Number value of the EXIF Orientation header, if present
|
||||||
|
* - `exif`: Buffer containing raw EXIF data, if present
|
||||||
|
* - `icc`: Buffer containing raw [ICC](https://www.npmjs.com/package/icc) profile data, if present
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const image = sharp(inputJpg);
|
||||||
|
* image
|
||||||
|
* .metadata()
|
||||||
|
* .then(function(metadata) {
|
||||||
|
* return image
|
||||||
|
* .resize(Math.round(metadata.width / 2))
|
||||||
|
* .webp()
|
||||||
|
* .toBuffer();
|
||||||
|
* })
|
||||||
|
* .then(function(data) {
|
||||||
|
* // data contains a WebP image half the width and height of the original JPEG
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* @param {Function} [callback] - called with the arguments `(err, metadata)`
|
||||||
|
* @returns {Promise|Sharp}
|
||||||
|
*/
|
||||||
|
const metadata = function metadata (callback) {
|
||||||
|
const that = this;
|
||||||
|
if (is.fn(callback)) {
|
||||||
|
if (this._isStreamInput()) {
|
||||||
|
this.on('finish', function () {
|
||||||
|
that._flattenBufferIn();
|
||||||
|
sharp.metadata(that.options, callback);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
sharp.metadata(this.options, callback);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
} else {
|
||||||
|
if (this._isStreamInput()) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
that.on('finish', function () {
|
||||||
|
that._flattenBufferIn();
|
||||||
|
sharp.metadata(that.options, function (err, metadata) {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
} else {
|
||||||
|
resolve(metadata);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
sharp.metadata(that.options, function (err, metadata) {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
} else {
|
||||||
|
resolve(metadata);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* The default limit is 268402689 (0x3FFF * 0x3FFF) pixels.
|
||||||
|
* @param {(Number|Boolean)} limit - an integral Number of pixels, zero or false to remove limit, true to use default limit.
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid limit
|
||||||
|
*/
|
||||||
|
const limitInputPixels = function limitInputPixels (limit) {
|
||||||
|
// if we pass in false we represent the integer as 0 to disable
|
||||||
|
if (limit === false) {
|
||||||
|
limit = 0;
|
||||||
|
} else if (limit === true) {
|
||||||
|
limit = this.constructor.maximum.pixels;
|
||||||
|
}
|
||||||
|
if (is.integer(limit) && limit >= 0) {
|
||||||
|
this.options.limitInputPixels = limit;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid pixel limit (0 to ' + this.constructor.maximum.pixels + ') ' + limit);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* @param {Boolean} [sequentialRead=true]
|
||||||
|
* @returns {Sharp}
|
||||||
|
*/
|
||||||
|
const sequentialRead = function sequentialRead (sequentialRead) {
|
||||||
|
this.options.sequentialRead = is.bool(sequentialRead) ? sequentialRead : true;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decorate the Sharp prototype with input-related functions.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
module.exports = function (Sharp) {
|
||||||
|
[
|
||||||
|
// Private
|
||||||
|
_createInputDescriptor,
|
||||||
|
_write,
|
||||||
|
_flattenBufferIn,
|
||||||
|
_isStreamInput,
|
||||||
|
// Public
|
||||||
|
clone,
|
||||||
|
metadata,
|
||||||
|
limitInputPixels,
|
||||||
|
sequentialRead
|
||||||
|
].forEach(function (f) {
|
||||||
|
Sharp.prototype[f.name] = f;
|
||||||
|
});
|
||||||
|
};
|
94
lib/is.js
Normal file
94
lib/is.js
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this value defined and not null?
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const defined = function (val) {
|
||||||
|
return typeof val !== 'undefined' && val !== null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this value an object?
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const object = function (val) {
|
||||||
|
return typeof val === 'object';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this value a function?
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const fn = function (val) {
|
||||||
|
return typeof val === 'function';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this value a boolean?
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const bool = function (val) {
|
||||||
|
return typeof val === 'boolean';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this value a Buffer object?
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const buffer = function (val) {
|
||||||
|
return object(val) && val instanceof Buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this value a non-empty string?
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const string = function (val) {
|
||||||
|
return typeof val === 'string' && val.length > 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this value a real number?
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const number = function (val) {
|
||||||
|
return typeof val === 'number' && !Number.isNaN(val);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this value an integer?
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const integer = function (val) {
|
||||||
|
return number(val) && val % 1 === 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this value within an inclusive given range?
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const inRange = function (val, min, max) {
|
||||||
|
return val >= min && val <= max;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this value within the elements of an array?
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const inArray = function (val, list) {
|
||||||
|
return list.indexOf(val) !== -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
defined: defined,
|
||||||
|
object: object,
|
||||||
|
fn: fn,
|
||||||
|
bool: bool,
|
||||||
|
buffer: buffer,
|
||||||
|
string: string,
|
||||||
|
number: number,
|
||||||
|
integer: integer,
|
||||||
|
inRange: inRange,
|
||||||
|
inArray: inArray
|
||||||
|
};
|
431
lib/operation.js
Normal file
431
lib/operation.js
Normal file
@ -0,0 +1,431 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const is = require('./is');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rotate the output image by either an explicit angle
|
||||||
|
* or auto-orient based on the EXIF `Orientation` tag.
|
||||||
|
*
|
||||||
|
* Use this method without angle to determine the angle from EXIF data.
|
||||||
|
* Mirroring is supported and may infer the use of a flip operation.
|
||||||
|
*
|
||||||
|
* The use of `rotate` implies the removal of the EXIF `Orientation` tag, if any.
|
||||||
|
*
|
||||||
|
* Method order is important when both rotating and extracting regions,
|
||||||
|
* for example `rotate(x).extract(y)` will produce a different result to `extract(y).rotate(x)`.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const pipeline = sharp()
|
||||||
|
* .rotate()
|
||||||
|
* .resize(null, 200)
|
||||||
|
* .toBuffer(function (err, outputBuffer, info) {
|
||||||
|
* // outputBuffer contains 200px high JPEG image data,
|
||||||
|
* // auto-rotated using EXIF Orientation tag
|
||||||
|
* // info.width and info.height contain the dimensions of the resized image
|
||||||
|
* });
|
||||||
|
* readableStream.pipe(pipeline);
|
||||||
|
*
|
||||||
|
* @param {Number} [angle=auto] 0, 90, 180 or 270.
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid parameters
|
||||||
|
*/
|
||||||
|
const rotate = function rotate (angle) {
|
||||||
|
if (!is.defined(angle)) {
|
||||||
|
this.options.angle = -1;
|
||||||
|
} else if (is.integer(angle) && is.inArray(angle, [0, 90, 180, 270])) {
|
||||||
|
this.options.angle = angle;
|
||||||
|
} else {
|
||||||
|
throw new Error('Unsupported angle (0, 90, 180, 270) ' + angle);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract a region of the image.
|
||||||
|
*
|
||||||
|
* - Use `extract` before `resize` for pre-resize extraction.
|
||||||
|
* - Use `extract` after `resize` for post-resize extraction.
|
||||||
|
* - Use `extract` before and after for both.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* sharp(input)
|
||||||
|
* .extract({ left: left, top: top, width: width, height: height })
|
||||||
|
* .toFile(output, function(err) {
|
||||||
|
* // Extract a region of the input image, saving in the same format.
|
||||||
|
* });
|
||||||
|
* @example
|
||||||
|
* sharp(input)
|
||||||
|
* .extract({ left: leftOffsetPre, top: topOffsetPre, width: widthPre, height: heightPre })
|
||||||
|
* .resize(width, height)
|
||||||
|
* .extract({ left: leftOffsetPost, top: topOffsetPost, width: widthPost, height: heightPost })
|
||||||
|
* .toFile(output, function(err) {
|
||||||
|
* // Extract a region, resize, then extract from the resized image
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* @param {Object} options
|
||||||
|
* @param {Number} options.left - zero-indexed offset from left edge
|
||||||
|
* @param {Number} options.top - zero-indexed offset from top edge
|
||||||
|
* @param {Number} options.width - dimension of extracted image
|
||||||
|
* @param {Number} options.height - dimension of extracted image
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid parameters
|
||||||
|
*/
|
||||||
|
const extract = function extract (options) {
|
||||||
|
const suffix = this.options.width === -1 && this.options.height === -1 ? 'Pre' : 'Post';
|
||||||
|
['left', 'top', 'width', 'height'].forEach(function (name) {
|
||||||
|
const value = options[name];
|
||||||
|
if (is.integer(value) && value >= 0) {
|
||||||
|
this.options[name + (name === 'left' || name === 'top' ? 'Offset' : '') + suffix] = value;
|
||||||
|
} else {
|
||||||
|
throw new Error('Non-integer value for ' + name + ' of ' + value);
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
// Ensure existing rotation occurs before pre-resize extraction
|
||||||
|
if (suffix === 'Pre' && this.options.angle !== 0) {
|
||||||
|
this.options.rotateBeforePreExtract = true;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* @param {Boolean} [flip=true]
|
||||||
|
* @returns {Sharp}
|
||||||
|
*/
|
||||||
|
const flip = function flip (flip) {
|
||||||
|
this.options.flip = is.bool(flip) ? flip : true;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* @param {Boolean} [flop=true]
|
||||||
|
* @returns {Sharp}
|
||||||
|
*/
|
||||||
|
const flop = function flop (flop) {
|
||||||
|
this.options.flop = is.bool(flop) ? flop : true;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sharpen the image.
|
||||||
|
* When used without parameters, performs a fast, mild sharpen of the output image.
|
||||||
|
* When a `sigma` is provided, performs a slower, more accurate sharpen of the L channel in the LAB colour space.
|
||||||
|
* Separate control over the level of sharpening in "flat" and "jagged" areas is available.
|
||||||
|
*
|
||||||
|
* @param {Number} [sigma] - the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`.
|
||||||
|
* @param {Number} [flat=1.0] - the level of sharpening to apply to "flat" areas.
|
||||||
|
* @param {Number} [jagged=2.0] - the level of sharpening to apply to "jagged" areas.
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid parameters
|
||||||
|
*/
|
||||||
|
const sharpen = function sharpen (sigma, flat, jagged) {
|
||||||
|
if (!is.defined(sigma)) {
|
||||||
|
// No arguments: default to mild sharpen
|
||||||
|
this.options.sharpenSigma = -1;
|
||||||
|
} else if (is.bool(sigma)) {
|
||||||
|
// Boolean argument: apply mild sharpen?
|
||||||
|
this.options.sharpenSigma = sigma ? -1 : 0;
|
||||||
|
} else if (is.number(sigma) && is.inRange(sigma, 0.01, 10000)) {
|
||||||
|
// Numeric argument: specific sigma
|
||||||
|
this.options.sharpenSigma = sigma;
|
||||||
|
// Control over flat areas
|
||||||
|
if (is.defined(flat)) {
|
||||||
|
if (is.number(flat) && is.inRange(flat, 0, 10000)) {
|
||||||
|
this.options.sharpenFlat = flat;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid sharpen level for flat areas (0.0 - 10000.0) ' + flat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Control over jagged areas
|
||||||
|
if (is.defined(jagged)) {
|
||||||
|
if (is.number(jagged) && is.inRange(jagged, 0, 10000)) {
|
||||||
|
this.options.sharpenJagged = jagged;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid sharpen level for jagged areas (0.0 - 10000.0) ' + jagged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid sharpen sigma (0.01 - 10000) ' + sigma);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blur the image.
|
||||||
|
* When used without parameters, performs a fast, mild blur of the output image.
|
||||||
|
* When a `sigma` is provided, performs a slower, more accurate Gaussian blur.
|
||||||
|
* @param {Number} [sigma] a value between 0.3 and 1000 representing the sigma of the Gaussian mask, where `sigma = 1 + radius / 2`.
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid parameters
|
||||||
|
*/
|
||||||
|
const blur = function blur (sigma) {
|
||||||
|
if (!is.defined(sigma)) {
|
||||||
|
// No arguments: default to mild blur
|
||||||
|
this.options.blurSigma = -1;
|
||||||
|
} else if (is.bool(sigma)) {
|
||||||
|
// Boolean argument: apply mild blur?
|
||||||
|
this.options.blurSigma = sigma ? -1 : 0;
|
||||||
|
} else if (is.number(sigma) && is.inRange(sigma, 0.3, 1000)) {
|
||||||
|
// Numeric argument: specific sigma
|
||||||
|
this.options.blurSigma = sigma;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid blur sigma (0.3 - 1000.0) ' + sigma);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Resize to 140 pixels wide, then add 10 transparent pixels
|
||||||
|
* // to the top, left and right edges and 20 to the bottom edge
|
||||||
|
* sharp(input)
|
||||||
|
* .resize(140)
|
||||||
|
* .background({r: 0, g: 0, b: 0, a: 0})
|
||||||
|
* .extend({top: 10, bottom: 20, left: 10, right: 10})
|
||||||
|
* ...
|
||||||
|
*
|
||||||
|
* @param {(Number|Object)} extend - single pixel count to add to all edges or an Object with per-edge counts
|
||||||
|
* @param {Number} [extend.top]
|
||||||
|
* @param {Number} [extend.left]
|
||||||
|
* @param {Number} [extend.bottom]
|
||||||
|
* @param {Number} [extend.right]
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid parameters
|
||||||
|
*/
|
||||||
|
const extend = function extend (extend) {
|
||||||
|
if (is.integer(extend) && extend > 0) {
|
||||||
|
this.options.extendTop = extend;
|
||||||
|
this.options.extendBottom = extend;
|
||||||
|
this.options.extendLeft = extend;
|
||||||
|
this.options.extendRight = extend;
|
||||||
|
} else if (
|
||||||
|
is.object(extend) &&
|
||||||
|
is.integer(extend.top) && extend.top >= 0 &&
|
||||||
|
is.integer(extend.bottom) && extend.bottom >= 0 &&
|
||||||
|
is.integer(extend.left) && extend.left >= 0 &&
|
||||||
|
is.integer(extend.right) && extend.right >= 0
|
||||||
|
) {
|
||||||
|
this.options.extendTop = extend.top;
|
||||||
|
this.options.extendBottom = extend.bottom;
|
||||||
|
this.options.extendLeft = extend.left;
|
||||||
|
this.options.extendRight = extend.right;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid edge extension ' + extend);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge alpha transparency channel, if any, with `background`.
|
||||||
|
* @param {Boolean} [flatten=true]
|
||||||
|
* @returns {Sharp}
|
||||||
|
*/
|
||||||
|
const flatten = function flatten (flatten) {
|
||||||
|
this.options.flatten = is.bool(flatten) ? flatten : true;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trim "boring" pixels from all edges that contain values within a percentage similarity of the top-left pixel.
|
||||||
|
* @param {Number} [tolerance=10] value between 1 and 99 representing the percentage similarity.
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid parameters
|
||||||
|
*/
|
||||||
|
const trim = function trim (tolerance) {
|
||||||
|
if (!is.defined(tolerance)) {
|
||||||
|
this.options.trimTolerance = 10;
|
||||||
|
} else if (is.integer(tolerance) && is.inRange(tolerance, 1, 99)) {
|
||||||
|
this.options.trimTolerance = tolerance;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid trim tolerance (1 to 99) ' + tolerance);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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`.
|
||||||
|
* This can improve the perceived brightness of a resized image in non-linear colour spaces.
|
||||||
|
* JPEG and WebP input images will not take advantage of the shrink-on-load performance optimisation
|
||||||
|
* when applying a gamma correction.
|
||||||
|
* @param {Number} [gamma=2.2] value between 1.0 and 3.0.
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid parameters
|
||||||
|
*/
|
||||||
|
const gamma = function gamma (gamma) {
|
||||||
|
if (!is.defined(gamma)) {
|
||||||
|
// Default gamma correction of 2.2 (sRGB)
|
||||||
|
this.options.gamma = 2.2;
|
||||||
|
} else if (is.number(gamma) && is.inRange(gamma, 1, 3)) {
|
||||||
|
this.options.gamma = gamma;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid gamma correction (1.0 to 3.0) ' + gamma);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produce the "negative" of the image.
|
||||||
|
* @param {Boolean} [negate=true]
|
||||||
|
* @returns {Sharp}
|
||||||
|
*/
|
||||||
|
const negate = function negate (negate) {
|
||||||
|
this.options.negate = is.bool(negate) ? negate : true;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enhance output image contrast by stretching its luminance to cover the full dynamic range.
|
||||||
|
* @param {Boolean} [normalise=true]
|
||||||
|
* @returns {Sharp}
|
||||||
|
*/
|
||||||
|
const normalise = function normalise (normalise) {
|
||||||
|
this.options.normalise = is.bool(normalise) ? normalise : true;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alternative spelling of normalise.
|
||||||
|
* @param {Boolean} [normalize=true]
|
||||||
|
* @returns {Sharp}
|
||||||
|
*/
|
||||||
|
const normalize = function normalize (normalize) {
|
||||||
|
return this.normalise(normalize);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convolve the image with the specified kernel.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* sharp(input)
|
||||||
|
* .convolve({
|
||||||
|
* width: 3,
|
||||||
|
* height: 3,
|
||||||
|
* kernel: [-1, 0, 1, -2, 0, 2, -1, 0, 1]
|
||||||
|
* })
|
||||||
|
* .raw()
|
||||||
|
* .toBuffer(function(err, data, info) {
|
||||||
|
* // data contains the raw pixel data representing the convolution
|
||||||
|
* // of the input image with the horizontal Sobel operator
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* @param {Object} kernel
|
||||||
|
* @param {Number} kernel.width - width of the kernel in pixels.
|
||||||
|
* @param {Number} kernel.height - width of the kernel in pixels.
|
||||||
|
* @param {Array} kernel.kernel - Array of length `width*height` containing the kernel values.
|
||||||
|
* @param {Number} [kernel.scale=sum] - the scale of the kernel in pixels.
|
||||||
|
* @param {Number} [kernel.offset=0] - the offset of the kernel in pixels.
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid parameters
|
||||||
|
*/
|
||||||
|
const convolve = function convolve (kernel) {
|
||||||
|
if (!is.object(kernel) || !Array.isArray(kernel.kernel) ||
|
||||||
|
!is.integer(kernel.width) || !is.integer(kernel.height) ||
|
||||||
|
!is.inRange(kernel.width, 3, 1001) || !is.inRange(kernel.height, 3, 1001) ||
|
||||||
|
kernel.height * kernel.width !== kernel.kernel.length
|
||||||
|
) {
|
||||||
|
// must pass in a kernel
|
||||||
|
throw new Error('Invalid convolution kernel');
|
||||||
|
}
|
||||||
|
// Default scale is sum of kernel values
|
||||||
|
if (!is.integer(kernel.scale)) {
|
||||||
|
kernel.scale = kernel.kernel.reduce(function (a, b) {
|
||||||
|
return a + b;
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
// Clip scale to a minimum value of 1
|
||||||
|
if (kernel.scale < 1) {
|
||||||
|
kernel.scale = 1;
|
||||||
|
}
|
||||||
|
if (!is.integer(kernel.offset)) {
|
||||||
|
kernel.offset = 0;
|
||||||
|
}
|
||||||
|
this.options.convKernel = kernel;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any pixel value greather than or equal to the threshold value will be set to 255, otherwise it will be set to 0.
|
||||||
|
* @param {Number} [threshold=128] - a value in the range 0-255 representing the level at which the threshold will be applied.
|
||||||
|
* @param {Object} [options]
|
||||||
|
* @param {Boolean} [options.greyscale=true] - convert to single channel greyscale.
|
||||||
|
* @param {Boolean} [options.grayscale=true] - alternative spelling for greyscale.
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid parameters
|
||||||
|
*/
|
||||||
|
const threshold = function threshold (threshold, options) {
|
||||||
|
if (!is.defined(threshold)) {
|
||||||
|
this.options.threshold = 128;
|
||||||
|
} else if (is.bool(threshold)) {
|
||||||
|
this.options.threshold = threshold ? 128 : 0;
|
||||||
|
} else if (is.integer(threshold) && is.inRange(threshold, 0, 255)) {
|
||||||
|
this.options.threshold = threshold;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid threshold (0 to 255) ' + threshold);
|
||||||
|
}
|
||||||
|
if (!is.object(options) || options.greyscale === true || options.grayscale === true) {
|
||||||
|
this.options.thresholdGrayscale = true;
|
||||||
|
} else {
|
||||||
|
this.options.thresholdGrayscale = false;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a bitwise boolean operation with operand image.
|
||||||
|
*
|
||||||
|
* This operation creates an output image where each pixel is the result of
|
||||||
|
* the selected bitwise boolean `operation` between the corresponding pixels of the input images.
|
||||||
|
*
|
||||||
|
* @param {Buffer|String} operand - Buffer containing image data or String containing the path to an image file.
|
||||||
|
* @param {String} operator - one of `and`, `or` or `eor` to perform that bitwise operation, like the C logic operators `&`, `|` and `^` respectively.
|
||||||
|
* @param {Object} [options]
|
||||||
|
* @param {Object} [options.raw] - describes operand when using raw pixel data.
|
||||||
|
* @param {Number} [options.raw.width]
|
||||||
|
* @param {Number} [options.raw.height]
|
||||||
|
* @param {Number} [options.raw.channels]
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid parameters
|
||||||
|
*/
|
||||||
|
const boolean = function boolean (operand, operator, options) {
|
||||||
|
this.options.boolean = this._createInputDescriptor(operand, options);
|
||||||
|
if (is.string(operator) && is.inArray(operator, ['and', 'or', 'eor'])) {
|
||||||
|
this.options.booleanOp = operator;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid boolean operator ' + operator);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decorate the Sharp prototype with operation-related functions.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
module.exports = function (Sharp) {
|
||||||
|
[
|
||||||
|
rotate,
|
||||||
|
extract,
|
||||||
|
flip,
|
||||||
|
flop,
|
||||||
|
sharpen,
|
||||||
|
blur,
|
||||||
|
extend,
|
||||||
|
flatten,
|
||||||
|
trim,
|
||||||
|
gamma,
|
||||||
|
negate,
|
||||||
|
normalise,
|
||||||
|
normalize,
|
||||||
|
convolve,
|
||||||
|
threshold,
|
||||||
|
boolean
|
||||||
|
].forEach(function (f) {
|
||||||
|
Sharp.prototype[f.name] = f;
|
||||||
|
});
|
||||||
|
};
|
502
lib/output.js
Normal file
502
lib/output.js
Normal file
@ -0,0 +1,502 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const util = require('util');
|
||||||
|
const is = require('./is');
|
||||||
|
const sharp = require('../build/Release/sharp.node');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write output image data to a file.
|
||||||
|
*
|
||||||
|
* If an explicit output format is not selected, it will be inferred from the extension,
|
||||||
|
* with JPEG, PNG, WebP, TIFF, DZI, and libvips' V format supported.
|
||||||
|
* Note that raw pixel data is only supported for buffer output.
|
||||||
|
*
|
||||||
|
* A Promises/A+ promise is returned when `callback` is not provided.
|
||||||
|
*
|
||||||
|
* @param {String} fileOut - the path to write the image data to.
|
||||||
|
* @param {Function} [callback] - called on completion with two arguments `(err, info)`.
|
||||||
|
* `info` contains the output image `format`, `size` (bytes), `width`, `height` and `channels`.
|
||||||
|
* @returns {Promise} - when no callback is provided
|
||||||
|
* @throws {Error} Invalid parameters
|
||||||
|
*/
|
||||||
|
const toFile = function toFile (fileOut, callback) {
|
||||||
|
if (!fileOut || fileOut.length === 0) {
|
||||||
|
const errOutputInvalid = new Error('Invalid output');
|
||||||
|
if (is.fn(callback)) {
|
||||||
|
callback(errOutputInvalid);
|
||||||
|
} else {
|
||||||
|
return Promise.reject(errOutputInvalid);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.options.input.file === fileOut) {
|
||||||
|
const errOutputIsInput = new Error('Cannot use same file for input and output');
|
||||||
|
if (is.fn(callback)) {
|
||||||
|
callback(errOutputIsInput);
|
||||||
|
} else {
|
||||||
|
return Promise.reject(errOutputIsInput);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.options.fileOut = fileOut;
|
||||||
|
return this._pipeline(callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write output to a Buffer.
|
||||||
|
* By default, the format will match the input image. JPEG, PNG, WebP, and RAW are supported.
|
||||||
|
* `callback`, if present, gets three arguments `(err, buffer, info)` where:
|
||||||
|
* - `err` is an error message, if any.
|
||||||
|
* - `buffer` is the output image data.
|
||||||
|
* - `info` contains the output image `format`, `size` (bytes), `width`, `height` and `channels`.
|
||||||
|
* A Promises/A+ promise is returned when `callback` is not provided.
|
||||||
|
*
|
||||||
|
* @param {Function} [callback]
|
||||||
|
* @returns {Promise} - when no callback is provided
|
||||||
|
*/
|
||||||
|
const toBuffer = function toBuffer (callback) {
|
||||||
|
return this._pipeline(callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* This will also convert to and add a web-friendly sRGB ICC profile.
|
||||||
|
* @param {Object} [withMetadata]
|
||||||
|
* @param {Number} [withMetadata.orientation] value between 1 and 8, used to update the EXIF `Orientation` tag.
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid parameters
|
||||||
|
*/
|
||||||
|
const withMetadata = function withMetadata (withMetadata) {
|
||||||
|
this.options.withMetadata = is.bool(withMetadata) ? withMetadata : true;
|
||||||
|
if (is.object(withMetadata)) {
|
||||||
|
if (is.defined(withMetadata.orientation)) {
|
||||||
|
if (is.integer(withMetadata.orientation) && is.inRange(withMetadata.orientation, 1, 8)) {
|
||||||
|
this.options.withMetadataOrientation = withMetadata.orientation;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid orientation (1 to 8) ' + withMetadata.orientation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use these JPEG options for output image.
|
||||||
|
* @param {Object} [options] - output options
|
||||||
|
* @param {Number} [options.quality=80] - quality, integer 1-100
|
||||||
|
* @param {Boolean} [options.progressive=false] - use progressive (interlace) scan
|
||||||
|
* @param {String} [options.chromaSubsampling='4:2:0'] - set to '4:4:4' to prevent chroma subsampling when quality <= 90
|
||||||
|
* @param {Boolean} [trellisQuantisation=false] - apply trellis quantisation, requires mozjpeg
|
||||||
|
* @param {Boolean} [overshootDeringing=false] - apply overshoot deringing, requires mozjpeg
|
||||||
|
* @param {Boolean} [optimiseScans=false] - optimise progressive scans, forces progressive, requires mozjpeg
|
||||||
|
* @param {Boolean} [options.force=true] - force JPEG output, otherwise attempt to use input format
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid options
|
||||||
|
*/
|
||||||
|
const jpeg = function jpeg (options) {
|
||||||
|
if (is.object(options)) {
|
||||||
|
if (is.defined(options.quality)) {
|
||||||
|
if (is.integer(options.quality) && is.inRange(options.quality, 1, 100)) {
|
||||||
|
this.options.jpegQuality = options.quality;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid quality (integer, 1-100) ' + options.quality);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (is.defined(options.progressive)) {
|
||||||
|
this._setBooleanOption('jpegProgressive', options.progressive);
|
||||||
|
}
|
||||||
|
if (is.defined(options.chromaSubsampling)) {
|
||||||
|
if (is.string(options.chromaSubsampling) && is.inArray(options.chromaSubsampling, ['4:2:0', '4:4:4'])) {
|
||||||
|
this.options.jpegChromaSubsampling = options.chromaSubsampling;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid chromaSubsampling (4:2:0, 4:4:4) ' + options.chromaSubsampling);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
options.trellisQuantisation = options.trellisQuantisation || options.trellisQuantization;
|
||||||
|
if (is.defined(options.trellisQuantisation)) {
|
||||||
|
this._setBooleanOption('jpegTrellisQuantisation', options.trellisQuantisation);
|
||||||
|
}
|
||||||
|
if (is.defined(options.overshootDeringing)) {
|
||||||
|
this._setBooleanOption('jpegOvershootDeringing', options.overshootDeringing);
|
||||||
|
}
|
||||||
|
options.optimiseScans = options.optimiseScans || options.optimizeScans;
|
||||||
|
if (is.defined(options.optimiseScans)) {
|
||||||
|
this._setBooleanOption('jpegOptimiseScans', options.optimiseScans);
|
||||||
|
if (options.optimiseScans) {
|
||||||
|
this.options.jpegProgressive = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this._updateFormatOut('jpeg', options);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use these PNG options for output image.
|
||||||
|
* @param {Object} [options]
|
||||||
|
* @param {Boolean} [options.progressive=false] - use progressive (interlace) scan
|
||||||
|
* @param {Number} [options.compressionLevel=6] - zlib compression level
|
||||||
|
* @param {Boolean} [options.adaptiveFiltering=true] - use adaptive row filtering
|
||||||
|
* @param {Boolean} [options.force=true] - force PNG output, otherwise attempt to use input format
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid options
|
||||||
|
*/
|
||||||
|
const png = function png (options) {
|
||||||
|
if (is.object(options)) {
|
||||||
|
if (is.defined(options.progressive)) {
|
||||||
|
this._setBooleanOption('pngProgressive', options.progressive);
|
||||||
|
}
|
||||||
|
if (is.defined(options.compressionLevel)) {
|
||||||
|
if (is.integer(options.compressionLevel) && is.inRange(options.compressionLevel, 0, 9)) {
|
||||||
|
this.options.pngCompressionLevel = options.compressionLevel;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid compressionLevel (integer, 0-9) ' + options.compressionLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (is.defined(options.adaptiveFiltering)) {
|
||||||
|
this._setBooleanOption('pngAdaptiveFiltering', options.adaptiveFiltering);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this._updateFormatOut('png', options);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use these WebP options for output image.
|
||||||
|
* @param {Object} [options] - output options
|
||||||
|
* @param {Number} [options.quality=80] - quality, integer 1-100
|
||||||
|
* @param {Boolean} [options.force=true] - force WebP output, otherwise attempt to use input format
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid options
|
||||||
|
*/
|
||||||
|
const webp = function webp (options) {
|
||||||
|
if (is.object(options)) {
|
||||||
|
if (is.defined(options.quality)) {
|
||||||
|
if (is.integer(options.quality) && is.inRange(options.quality, 1, 100)) {
|
||||||
|
this.options.webpQuality = options.quality;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid quality (integer, 1-100) ' + options.quality);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this._updateFormatOut('webp', options);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use these TIFF options for output image.
|
||||||
|
* @param {Object} [options] - output options
|
||||||
|
* @param {Number} [options.quality=80] - quality, integer 1-100
|
||||||
|
* @param {Boolean} [options.force=true] - force TIFF output, otherwise attempt to use input format
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid options
|
||||||
|
*/
|
||||||
|
const tiff = function tiff (options) {
|
||||||
|
if (is.object(options)) {
|
||||||
|
if (is.defined(options.quality)) {
|
||||||
|
if (is.integer(options.quality) && is.inRange(options.quality, 1, 100)) {
|
||||||
|
this.options.tiffQuality = options.quality;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid quality (integer, 1-100) ' + options.quality);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this._updateFormatOut('tiff', options);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Force output to be raw, uncompressed uint8 pixel data.
|
||||||
|
* @returns {Sharp}
|
||||||
|
*/
|
||||||
|
const raw = function raw () {
|
||||||
|
return this._updateFormatOut('raw');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Force output to a given format.
|
||||||
|
* @param {(String|Object)} format - as a String or an Object with an 'id' attribute
|
||||||
|
* @param {Object} options - output options
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} unsupported format or options
|
||||||
|
*/
|
||||||
|
const toFormat = function toFormat (format, options) {
|
||||||
|
if (is.object(format) && is.string(format.id)) {
|
||||||
|
format = format.id;
|
||||||
|
}
|
||||||
|
if (!is.inArray(format, ['jpeg', 'png', 'webp', 'tiff', 'raw'])) {
|
||||||
|
throw new Error('Unsupported output format ' + format);
|
||||||
|
}
|
||||||
|
return this[format](options);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use tile-based deep zoom (image pyramid) output.
|
||||||
|
* You can also use a `.zip` or `.szi` file extension with `toFile` to write to a compressed archive file format.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* sharp('input.tiff')
|
||||||
|
* .tile({
|
||||||
|
* size: 512
|
||||||
|
* })
|
||||||
|
* .toFile('output.dzi', function(err, info) {
|
||||||
|
* // output.dzi is the Deep Zoom XML definition
|
||||||
|
* // output_files contains 512x512 tiles grouped by zoom level
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* @param {Object} [tile]
|
||||||
|
* @param {Number} [tile.size=256] tile size in pixels, a value between 1 and 8192.
|
||||||
|
* @param {Number} [tile.overlap=0] tile overlap in pixels, a value between 0 and 8192.
|
||||||
|
* @param {String} [tile.container='fs'] tile container, with value `fs` (filesystem) or `zip` (compressed file).
|
||||||
|
* @param {String} [tile.layout='dz'] filesystem layout, possible values are `dz`, `zoomify` or `google`.
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid parameters
|
||||||
|
*/
|
||||||
|
const tile = function tile (tile) {
|
||||||
|
if (is.object(tile)) {
|
||||||
|
// Size of square tiles, in pixels
|
||||||
|
if (is.defined(tile.size)) {
|
||||||
|
if (is.integer(tile.size) && is.inRange(tile.size, 1, 8192)) {
|
||||||
|
this.options.tileSize = tile.size;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid tile size (1 to 8192) ' + tile.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Overlap of tiles, in pixels
|
||||||
|
if (is.defined(tile.overlap)) {
|
||||||
|
if (is.integer(tile.overlap) && is.inRange(tile.overlap, 0, 8192)) {
|
||||||
|
if (tile.overlap > this.options.tileSize) {
|
||||||
|
throw new Error('Tile overlap ' + tile.overlap + ' cannot be larger than tile size ' + this.options.tileSize);
|
||||||
|
}
|
||||||
|
this.options.tileOverlap = tile.overlap;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid tile overlap (0 to 8192) ' + tile.overlap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Container
|
||||||
|
if (is.defined(tile.container)) {
|
||||||
|
if (is.string(tile.container) && is.inArray(tile.container, ['fs', 'zip'])) {
|
||||||
|
this.options.tileContainer = tile.container;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid tile container ' + tile.container);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Layout
|
||||||
|
if (is.defined(tile.layout)) {
|
||||||
|
if (is.string(tile.layout) && is.inArray(tile.layout, ['dz', 'google', 'zoomify'])) {
|
||||||
|
this.options.tileLayout = tile.layout;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid tile layout ' + tile.layout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the output format unless options.force is false,
|
||||||
|
* in which case revert to input format.
|
||||||
|
* @private
|
||||||
|
* @param {String} formatOut
|
||||||
|
* @param {Object} [options]
|
||||||
|
* @param {Boolean} [options.force=true] - force output format, otherwise attempt to use input format
|
||||||
|
* @returns {Sharp}
|
||||||
|
*/
|
||||||
|
const _updateFormatOut = function _updateFormatOut (formatOut, options) {
|
||||||
|
this.options.formatOut = (is.object(options) && options.force === false) ? 'input' : formatOut;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update a Boolean attribute of the this.options Object.
|
||||||
|
* @private
|
||||||
|
* @param {String} key
|
||||||
|
* @param {Boolean} val
|
||||||
|
* @throws {Error} Invalid key
|
||||||
|
*/
|
||||||
|
const _setBooleanOption = function _setBooleanOption (key, val) {
|
||||||
|
if (is.bool(val)) {
|
||||||
|
this.options[key] = val;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid ' + key + ' (boolean) ' + val);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by a WriteableStream to notify us it is ready for data.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const _read = function _read () {
|
||||||
|
if (!this.options.streamOut) {
|
||||||
|
this.options.streamOut = true;
|
||||||
|
this._pipeline();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoke the C++ image processing pipeline
|
||||||
|
* Supports callback, stream and promise variants
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const _pipeline = function _pipeline (callback) {
|
||||||
|
const that = this;
|
||||||
|
if (typeof callback === 'function') {
|
||||||
|
// output=file/buffer
|
||||||
|
if (this._isStreamInput()) {
|
||||||
|
// output=file/buffer, input=stream
|
||||||
|
this.on('finish', function () {
|
||||||
|
that._flattenBufferIn();
|
||||||
|
sharp.pipeline(that.options, callback);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// output=file/buffer, input=file/buffer
|
||||||
|
sharp.pipeline(this.options, callback);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
} else if (this.options.streamOut) {
|
||||||
|
// output=stream
|
||||||
|
if (this._isStreamInput()) {
|
||||||
|
// output=stream, input=stream
|
||||||
|
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 {
|
||||||
|
// output=stream, input=file/buffer
|
||||||
|
sharp.pipeline(this.options, function (err, data, info) {
|
||||||
|
if (err) {
|
||||||
|
that.emit('error', err);
|
||||||
|
} else {
|
||||||
|
that.emit('info', info);
|
||||||
|
that.push(data);
|
||||||
|
}
|
||||||
|
that.push(null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
} else {
|
||||||
|
// output=promise
|
||||||
|
if (this._isStreamInput()) {
|
||||||
|
// output=promise, input=stream
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
that.on('finish', function () {
|
||||||
|
that._flattenBufferIn();
|
||||||
|
sharp.pipeline(that.options, function (err, data) {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
} else {
|
||||||
|
resolve(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// output=promise, input=file/buffer
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
sharp.pipeline(that.options, function (err, data) {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
} else {
|
||||||
|
resolve(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Deprecated output options
|
||||||
|
const quality = util.deprecate(function (quality) {
|
||||||
|
const formatOut = this.options.formatOut;
|
||||||
|
const options = { quality: quality };
|
||||||
|
this.jpeg(options).webp(options).tiff(options);
|
||||||
|
this.options.formatOut = formatOut;
|
||||||
|
return this;
|
||||||
|
}, 'quality: use jpeg({ quality: ... }), webp({ quality: ... }) and/or tiff({ quality: ... }) instead');
|
||||||
|
const progressive = util.deprecate(function (progressive) {
|
||||||
|
const formatOut = this.options.formatOut;
|
||||||
|
const options = { progressive: (progressive !== false) };
|
||||||
|
this.jpeg(options).png(options);
|
||||||
|
this.options.formatOut = formatOut;
|
||||||
|
return this;
|
||||||
|
}, 'progressive: use jpeg({ progressive: ... }) and/or png({ progressive: ... }) instead');
|
||||||
|
const compressionLevel = util.deprecate(function (compressionLevel) {
|
||||||
|
const formatOut = this.options.formatOut;
|
||||||
|
this.png({ compressionLevel: compressionLevel });
|
||||||
|
this.options.formatOut = formatOut;
|
||||||
|
return this;
|
||||||
|
}, 'compressionLevel: use png({ compressionLevel: ... }) instead');
|
||||||
|
const withoutAdaptiveFiltering = util.deprecate(function (withoutAdaptiveFiltering) {
|
||||||
|
const formatOut = this.options.formatOut;
|
||||||
|
this.png({ adaptiveFiltering: (withoutAdaptiveFiltering === false) });
|
||||||
|
this.options.formatOut = formatOut;
|
||||||
|
return this;
|
||||||
|
}, 'withoutAdaptiveFiltering: use png({ adaptiveFiltering: ... }) instead');
|
||||||
|
const withoutChromaSubsampling = util.deprecate(function (withoutChromaSubsampling) {
|
||||||
|
const formatOut = this.options.formatOut;
|
||||||
|
this.jpeg({ chromaSubsampling: (withoutChromaSubsampling === false) ? '4:2:0' : '4:4:4' });
|
||||||
|
this.options.formatOut = formatOut;
|
||||||
|
return this;
|
||||||
|
}, 'withoutChromaSubsampling: use jpeg({ chromaSubsampling: "4:4:4" }) instead');
|
||||||
|
const trellisQuantisation = util.deprecate(function (trellisQuantisation) {
|
||||||
|
const formatOut = this.options.formatOut;
|
||||||
|
this.jpeg({ trellisQuantisation: (trellisQuantisation !== false) });
|
||||||
|
this.options.formatOut = formatOut;
|
||||||
|
return this;
|
||||||
|
}, 'trellisQuantisation: use jpeg({ trellisQuantisation: ... }) instead');
|
||||||
|
const overshootDeringing = util.deprecate(function (overshootDeringing) {
|
||||||
|
const formatOut = this.options.formatOut;
|
||||||
|
this.jpeg({ overshootDeringing: (overshootDeringing !== false) });
|
||||||
|
this.options.formatOut = formatOut;
|
||||||
|
return this;
|
||||||
|
}, 'overshootDeringing: use jpeg({ overshootDeringing: ... }) instead');
|
||||||
|
const optimiseScans = util.deprecate(function (optimiseScans) {
|
||||||
|
const formatOut = this.options.formatOut;
|
||||||
|
this.jpeg({ optimiseScans: (optimiseScans !== false) });
|
||||||
|
this.options.formatOut = formatOut;
|
||||||
|
return this;
|
||||||
|
}, 'optimiseScans: use jpeg({ optimiseScans: ... }) instead');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decorate the Sharp prototype with output-related functions.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
module.exports = function (Sharp) {
|
||||||
|
[
|
||||||
|
// Public
|
||||||
|
toFile,
|
||||||
|
toBuffer,
|
||||||
|
withMetadata,
|
||||||
|
jpeg,
|
||||||
|
png,
|
||||||
|
webp,
|
||||||
|
tiff,
|
||||||
|
raw,
|
||||||
|
toFormat,
|
||||||
|
tile,
|
||||||
|
// Private
|
||||||
|
_updateFormatOut,
|
||||||
|
_setBooleanOption,
|
||||||
|
_read,
|
||||||
|
_pipeline
|
||||||
|
].forEach(function (f) {
|
||||||
|
Sharp.prototype[f.name] = f;
|
||||||
|
});
|
||||||
|
// Deprecated
|
||||||
|
Sharp.prototype.quality = quality;
|
||||||
|
Sharp.prototype.progressive = progressive;
|
||||||
|
Sharp.prototype.compressionLevel = compressionLevel;
|
||||||
|
Sharp.prototype.withoutAdaptiveFiltering = withoutAdaptiveFiltering;
|
||||||
|
Sharp.prototype.withoutChromaSubsampling = withoutChromaSubsampling;
|
||||||
|
Sharp.prototype.trellisQuantisation = trellisQuantisation;
|
||||||
|
Sharp.prototype.trellisQuantization = trellisQuantisation;
|
||||||
|
Sharp.prototype.overshootDeringing = overshootDeringing;
|
||||||
|
Sharp.prototype.optimiseScans = optimiseScans;
|
||||||
|
Sharp.prototype.optimizeScans = optimiseScans;
|
||||||
|
};
|
294
lib/resize.js
Normal file
294
lib/resize.js
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const is = require('./is');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Weighting to apply to image crop.
|
||||||
|
* @member
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const gravity = {
|
||||||
|
center: 0,
|
||||||
|
centre: 0,
|
||||||
|
north: 1,
|
||||||
|
east: 2,
|
||||||
|
south: 3,
|
||||||
|
west: 4,
|
||||||
|
northeast: 5,
|
||||||
|
southeast: 6,
|
||||||
|
southwest: 7,
|
||||||
|
northwest: 8
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strategies for automagic crop behaviour.
|
||||||
|
* @member
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const strategy = {
|
||||||
|
entropy: 16,
|
||||||
|
attention: 17
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reduction kernels.
|
||||||
|
* @member
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const kernel = {
|
||||||
|
cubic: 'cubic',
|
||||||
|
lanczos2: 'lanczos2',
|
||||||
|
lanczos3: 'lanczos3'
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enlargement interpolators.
|
||||||
|
* @member
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const interpolator = {
|
||||||
|
nearest: 'nearest',
|
||||||
|
bilinear: 'bilinear',
|
||||||
|
bicubic: 'bicubic',
|
||||||
|
nohalo: 'nohalo',
|
||||||
|
lbb: 'lbb',
|
||||||
|
locallyBoundedBicubic: 'lbb',
|
||||||
|
vsqbs: 'vsqbs',
|
||||||
|
vertexSplitQuadraticBasisSpline: 'vsqbs'
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resize image to `width` x `height`.
|
||||||
|
* By default, the resized image is centre cropped to the exact size specified.
|
||||||
|
*
|
||||||
|
* Possible reduction kernels are:
|
||||||
|
* - `cubic`: Use a [Catmull-Rom spline](https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline).
|
||||||
|
* - `lanczos2`: Use a [Lanczos kernel](https://en.wikipedia.org/wiki/Lanczos_resampling#Lanczos_kernel) with `a=2`.
|
||||||
|
* - `lanczos3`: Use a Lanczos kernel with `a=3` (the default).
|
||||||
|
*
|
||||||
|
* Possible enlargement interpolators are:
|
||||||
|
* - `nearest`: Use [nearest neighbour interpolation](http://en.wikipedia.org/wiki/Nearest-neighbor_interpolation).
|
||||||
|
* - `bilinear`: Use [bilinear interpolation](http://en.wikipedia.org/wiki/Bilinear_interpolation), faster than bicubic but with less smooth results.
|
||||||
|
* - `vertexSplitQuadraticBasisSpline`: Use the smoother [VSQBS interpolation](https://github.com/jcupitt/libvips/blob/master/libvips/resample/vsqbs.cpp#L48) to prevent "staircasing" when enlarging.
|
||||||
|
* - `bicubic`: Use [bicubic interpolation](http://en.wikipedia.org/wiki/Bicubic_interpolation) (the default).
|
||||||
|
* - `locallyBoundedBicubic`: Use [LBB interpolation](https://github.com/jcupitt/libvips/blob/master/libvips/resample/lbb.cpp#L100), which prevents some "[acutance](http://en.wikipedia.org/wiki/Acutance)" but typically reduces performance by a factor of 2.
|
||||||
|
* - `nohalo`: Use [Nohalo interpolation](http://eprints.soton.ac.uk/268086/), which prevents acutance but typically reduces performance by a factor of 3.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* sharp(inputBuffer)
|
||||||
|
* .resize(200, 300, {
|
||||||
|
* kernel: sharp.kernel.lanczos2,
|
||||||
|
* interpolator: sharp.interpolator.nohalo
|
||||||
|
* })
|
||||||
|
* .background('white')
|
||||||
|
* .embed()
|
||||||
|
* .toFile('output.tiff')
|
||||||
|
* .then(function() {
|
||||||
|
* // output.tiff is a 200 pixels wide and 300 pixels high image
|
||||||
|
* // containing a lanczos2/nohalo scaled version, embedded on a white canvas,
|
||||||
|
* // of the image data in inputBuffer
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* @param {Number} [width] - pixels wide the resultant image should be, between 1 and 16383 (0x3FFF). Use `null` or `undefined` to auto-scale the width to match the height.
|
||||||
|
* @param {Number} [height] - pixels high the resultant image should be, between 1 and 16383. Use `null` or `undefined` to auto-scale the height to match the width.
|
||||||
|
* @param {Object} [options]
|
||||||
|
* @param {String} [options.kernel='lanczos3'] - the kernel to use for image reduction.
|
||||||
|
* @param {String} [options.interpolator='bicubic'] - the interpolator to use for image enlargement.
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid parameters
|
||||||
|
*/
|
||||||
|
const resize = function resize (width, height, options) {
|
||||||
|
if (is.defined(width)) {
|
||||||
|
if (is.integer(width) && is.inRange(width, 1, this.constructor.maximum.width)) {
|
||||||
|
this.options.width = width;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid width (1 to ' + this.constructor.maximum.width + ') ' + width);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.options.width = -1;
|
||||||
|
}
|
||||||
|
if (is.defined(height)) {
|
||||||
|
if (is.integer(height) && is.inRange(height, 1, this.constructor.maximum.height)) {
|
||||||
|
this.options.height = height;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid height (1 to ' + this.constructor.maximum.height + ') ' + height);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.options.height = -1;
|
||||||
|
}
|
||||||
|
if (is.object(options)) {
|
||||||
|
// Kernel
|
||||||
|
if (is.defined(options.kernel)) {
|
||||||
|
if (is.string(kernel[options.kernel])) {
|
||||||
|
this.options.kernel = kernel[options.kernel];
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid kernel ' + options.kernel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Interpolator
|
||||||
|
if (is.defined(options.interpolator)) {
|
||||||
|
if (is.string(interpolator[options.interpolator])) {
|
||||||
|
this.options.interpolator = interpolator[options.interpolator];
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid interpolator ' + options.interpolator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crop the resized image to the exact size specified, the default behaviour.
|
||||||
|
*
|
||||||
|
* Possible attributes of the optional `sharp.gravity` are `north`, `northeast`, `east`, `southeast`, `south`,
|
||||||
|
* `southwest`, `west`, `northwest`, `center` and `centre`.
|
||||||
|
*
|
||||||
|
* The experimental strategy-based approach resizes so one dimension is at its target length
|
||||||
|
* then repeatedly ranks edge regions, discarding the edge with the lowest score based on the selected strategy.
|
||||||
|
* - `entropy`: focus on the region with the highest [Shannon entropy](https://en.wikipedia.org/wiki/Entropy_%28information_theory%29).
|
||||||
|
* - `attention`: focus on the region with the highest luminance frequency, colour saturation and presence of skin tones.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const transformer = sharp()
|
||||||
|
* .resize(200, 200)
|
||||||
|
* .crop(sharp.strategy.entropy)
|
||||||
|
* .on('error', function(err) {
|
||||||
|
* console.log(err);
|
||||||
|
* });
|
||||||
|
* // Read image data from readableStream
|
||||||
|
* // Write 200px square auto-cropped image data to writableStream
|
||||||
|
* readableStream.pipe(transformer).pipe(writableStream);
|
||||||
|
*
|
||||||
|
* @param {String} [crop='centre'] - A member of `sharp.gravity` to crop to an edge/corner or `sharp.strategy` to crop dynamically.
|
||||||
|
* @returns {Sharp}
|
||||||
|
* @throws {Error} Invalid parameters
|
||||||
|
*/
|
||||||
|
const crop = function crop (crop) {
|
||||||
|
this.options.canvas = 'crop';
|
||||||
|
if (!is.defined(crop)) {
|
||||||
|
// Default
|
||||||
|
this.options.crop = gravity.center;
|
||||||
|
} else if (is.integer(crop) && is.inRange(crop, 0, 8)) {
|
||||||
|
// Gravity (numeric)
|
||||||
|
this.options.crop = crop;
|
||||||
|
} else if (is.string(crop) && is.integer(gravity[crop])) {
|
||||||
|
// Gravity (string)
|
||||||
|
this.options.crop = gravity[crop];
|
||||||
|
} else if (is.integer(crop) && crop >= strategy.entropy) {
|
||||||
|
// Strategy
|
||||||
|
this.options.crop = crop;
|
||||||
|
} else {
|
||||||
|
throw new Error('Unsupported crop ' + crop);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* If the background contains an alpha value then WebP and PNG format output images will
|
||||||
|
* contain an alpha channel, even when the input image does not.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* sharp('input.gif')
|
||||||
|
* .resize(200, 300)
|
||||||
|
* .background({r: 0, g: 0, b: 0, a: 0})
|
||||||
|
* .embed()
|
||||||
|
* .toFormat(sharp.format.webp)
|
||||||
|
* .toBuffer(function(err, outputBuffer) {
|
||||||
|
* if (err) {
|
||||||
|
* throw err;
|
||||||
|
* }
|
||||||
|
* // outputBuffer contains WebP image data of a 200 pixels wide and 300 pixels high
|
||||||
|
* // containing a scaled version, embedded on a transparent canvas, of input.gif
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* @returns {Sharp}
|
||||||
|
*/
|
||||||
|
const embed = function embed () {
|
||||||
|
this.options.canvas = 'embed';
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Both `width` and `height` must be provided via `resize` otherwise the behaviour will default to `crop`.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* sharp(inputBuffer)
|
||||||
|
* .resize(200, 200)
|
||||||
|
* .max()
|
||||||
|
* .toFormat('jpeg')
|
||||||
|
* .toBuffer()
|
||||||
|
* .then(function(outputBuffer) {
|
||||||
|
* // outputBuffer contains JPEG image data no wider than 200 pixels and no higher
|
||||||
|
* // than 200 pixels regardless of the inputBuffer image dimensions
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* @returns {Sharp}
|
||||||
|
*/
|
||||||
|
const max = function max () {
|
||||||
|
this.options.canvas = 'max';
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Both `width` and `height` must be provided via `resize` otherwise the behaviour will default to `crop`.
|
||||||
|
*
|
||||||
|
* @returns {Sharp}
|
||||||
|
*/
|
||||||
|
const min = function min () {
|
||||||
|
this.options.canvas = 'min';
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ignoring the aspect ratio of the input, stretch the image to
|
||||||
|
* the exact `width` and/or `height` provided via `resize`.
|
||||||
|
* @returns {Sharp}
|
||||||
|
*/
|
||||||
|
const ignoreAspectRatio = function ignoreAspectRatio () {
|
||||||
|
this.options.canvas = 'ignore_aspect';
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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:
|
||||||
|
* "*change the dimensions of the image only if its width or height exceeds the geometry specification*".
|
||||||
|
* @param {Boolean} [withoutEnlargement=true]
|
||||||
|
* @returns {Sharp}
|
||||||
|
*/
|
||||||
|
const withoutEnlargement = function withoutEnlargement (withoutEnlargement) {
|
||||||
|
this.options.withoutEnlargement = is.bool(withoutEnlargement) ? withoutEnlargement : true;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decorate the Sharp prototype with resize-related functions.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
module.exports = function (Sharp) {
|
||||||
|
[
|
||||||
|
resize,
|
||||||
|
crop,
|
||||||
|
embed,
|
||||||
|
max,
|
||||||
|
min,
|
||||||
|
ignoreAspectRatio,
|
||||||
|
withoutEnlargement
|
||||||
|
].forEach(function (f) {
|
||||||
|
Sharp.prototype[f.name] = f;
|
||||||
|
});
|
||||||
|
// Class attributes
|
||||||
|
Sharp.gravity = gravity;
|
||||||
|
Sharp.strategy = strategy;
|
||||||
|
Sharp.kernel = kernel;
|
||||||
|
Sharp.interpolator = interpolator;
|
||||||
|
};
|
116
lib/utility.js
Normal file
116
lib/utility.js
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const is = require('./is');
|
||||||
|
const sharp = require('../build/Release/sharp.node');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* This method always returns cache statistics,
|
||||||
|
* useful for determining how much working memory is required for a particular task.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const stats = sharp.cache();
|
||||||
|
* @example
|
||||||
|
* sharp.cache( { items: 200 } );
|
||||||
|
* sharp.cache( { files: 0 } );
|
||||||
|
* sharp.cache(false);
|
||||||
|
*
|
||||||
|
* @param {Object|Boolean} options - Object with the following attributes, or Boolean where true uses default cache settings and false removes all caching.
|
||||||
|
* @param {Number} [options.memory=50] - is the maximum memory in MB to use for this cache
|
||||||
|
* @param {Number} [options.files=20] - is the maximum number of files to hold open
|
||||||
|
* @param {Number} [options.items=100] - is the maximum number of operations to cache
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
const cache = function cache (options) {
|
||||||
|
if (is.bool(options)) {
|
||||||
|
if (options) {
|
||||||
|
// Default cache settings of 50MB, 20 files, 100 items
|
||||||
|
return sharp.cache(50, 20, 100);
|
||||||
|
} else {
|
||||||
|
return sharp.cache(0, 0, 0);
|
||||||
|
}
|
||||||
|
} else if (is.object(options)) {
|
||||||
|
return sharp.cache(options.memory, options.files, options.items);
|
||||||
|
} else {
|
||||||
|
return sharp.cache();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
cache(true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets, or when a concurrency is provided sets,
|
||||||
|
* the number of threads _libvips'_ should create to process each image.
|
||||||
|
* The default value is the number of CPU cores.
|
||||||
|
* A value of `0` will reset to this default.
|
||||||
|
*
|
||||||
|
* The maximum number of images that can be processed in parallel
|
||||||
|
* is limited by libuv's `UV_THREADPOOL_SIZE` environment variable.
|
||||||
|
*
|
||||||
|
* This method always returns the current concurrency.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const threads = sharp.concurrency(); // 4
|
||||||
|
* sharp.concurrency(2); // 2
|
||||||
|
* sharp.concurrency(0); // 4
|
||||||
|
*
|
||||||
|
* @param {Number} [concurrency]
|
||||||
|
* @returns {Number} concurrency
|
||||||
|
*/
|
||||||
|
const concurrency = function concurrency (concurrency) {
|
||||||
|
return sharp.concurrency(is.integer(concurrency) ? concurrency : null);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides access to internal task counters.
|
||||||
|
* - queue is the number of tasks this module has queued waiting for _libuv_ to provide a worker thread from its pool.
|
||||||
|
* - process is the number of resize tasks currently being processed.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const counters = sharp.counters(); // { queue: 2, process: 4 }
|
||||||
|
*
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
const counters = function counters () {
|
||||||
|
return sharp.counters();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get and set use of SIMD vector unit instructions.
|
||||||
|
* Requires libvips to have been compiled with liborc support.
|
||||||
|
*
|
||||||
|
* Improves the performance of `resize`, `blur` and `sharpen` operations
|
||||||
|
* by taking advantage of the SIMD vector unit of the CPU, e.g. Intel SSE and ARM NEON.
|
||||||
|
*
|
||||||
|
* This feature is currently off by default but future versions may reverse this.
|
||||||
|
* Versions of liborc prior to 0.4.25 are known to segfault under heavy load.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const simd = sharp.simd();
|
||||||
|
* // simd is `true` if SIMD is currently enabled
|
||||||
|
* @example
|
||||||
|
* const simd = sharp.simd(true);
|
||||||
|
* // attempts to enable the use of SIMD, returning true if available
|
||||||
|
*
|
||||||
|
* @param {Boolean} [simd=false]
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
const simd = function simd (simd) {
|
||||||
|
return sharp.simd(is.bool(simd) ? simd : null);
|
||||||
|
};
|
||||||
|
simd(false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decorate the Sharp class with utility-related functions.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
module.exports = function (Sharp) {
|
||||||
|
[
|
||||||
|
cache,
|
||||||
|
concurrency,
|
||||||
|
counters,
|
||||||
|
simd
|
||||||
|
].forEach(function (f) {
|
||||||
|
Sharp[f.name] = f;
|
||||||
|
});
|
||||||
|
};
|
11
mkdocs.yml
11
mkdocs.yml
@ -12,6 +12,15 @@ dev_addr: 0.0.0.0:10101
|
|||||||
pages:
|
pages:
|
||||||
- Home: index.md
|
- Home: index.md
|
||||||
- Installation: install.md
|
- Installation: install.md
|
||||||
- API: api.md
|
- API:
|
||||||
|
- Constructor: api-constructor.md
|
||||||
|
- Input: api-input.md
|
||||||
|
- Output: api-output.md
|
||||||
|
- "Resizing images": api-resize.md
|
||||||
|
- "Compositing images": api-composite.md
|
||||||
|
- "Image operations": api-operation.md
|
||||||
|
- "Colour manipulation": api-colour.md
|
||||||
|
- "Channel manipulation": api-channel.md
|
||||||
|
- Utilities: api-utility.md
|
||||||
- Performance: performance.md
|
- Performance: performance.md
|
||||||
- Changelog: changelog.md
|
- Changelog: changelog.md
|
||||||
|
@ -34,9 +34,10 @@
|
|||||||
"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=96 mocha --slow=5000 --timeout=60000 ./test/unit/*.js",
|
"test": "semistandard && cross-env VIPS_WARNING=0 nyc --reporter=lcov --branches=96 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"
|
||||||
},
|
},
|
||||||
"main": "index.js",
|
"main": "lib/",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git://github.com/lovell/sharp"
|
"url": "git://github.com/lovell/sharp"
|
||||||
@ -59,7 +60,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"caw": "^2.0.0",
|
"caw": "^2.0.0",
|
||||||
"color": "^0.11.3",
|
"color": "^0.11.3",
|
||||||
"got": "^6.5.0",
|
"got": "^6.6.0",
|
||||||
"nan": "^2.4.0",
|
"nan": "^2.4.0",
|
||||||
"semver": "^5.3.0",
|
"semver": "^5.3.0",
|
||||||
"tar": "^2.2.1"
|
"tar": "^2.2.1"
|
||||||
@ -68,6 +69,7 @@
|
|||||||
"async": "^2.1.2",
|
"async": "^2.1.2",
|
||||||
"bufferutil": "^1.2.1",
|
"bufferutil": "^1.2.1",
|
||||||
"cross-env": "^3.1.3",
|
"cross-env": "^3.1.3",
|
||||||
|
"documentation": "^4.0.0-beta11",
|
||||||
"exif-reader": "^1.0.1",
|
"exif-reader": "^1.0.1",
|
||||||
"icc": "^0.0.2",
|
"icc": "^0.0.2",
|
||||||
"mocha": "^3.1.2",
|
"mocha": "^3.1.2",
|
||||||
|
@ -37,7 +37,6 @@ namespace sharp {
|
|||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
@ -178,7 +177,7 @@ namespace sharp {
|
|||||||
/*
|
/*
|
||||||
* Stretch luminance to cover full dynamic range.
|
* Stretch luminance to cover full dynamic range.
|
||||||
*/
|
*/
|
||||||
VImage Normalize(VImage image) {
|
VImage Normalise(VImage image) {
|
||||||
// Get original colourspace
|
// Get original colourspace
|
||||||
VipsInterpretation typeBeforeNormalize = image.interpretation();
|
VipsInterpretation typeBeforeNormalize = image.interpretation();
|
||||||
if (typeBeforeNormalize == VIPS_INTERPRETATION_RGB) {
|
if (typeBeforeNormalize == VIPS_INTERPRETATION_RGB) {
|
||||||
|
@ -41,7 +41,7 @@ namespace sharp {
|
|||||||
/*
|
/*
|
||||||
* Stretch luminance to cover full dynamic range.
|
* Stretch luminance to cover full dynamic range.
|
||||||
*/
|
*/
|
||||||
VImage Normalize(VImage image);
|
VImage Normalise(VImage image);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Gamma encoding/decoding
|
* Gamma encoding/decoding
|
||||||
|
@ -649,9 +649,9 @@ class PipelineWorker : public Nan::AsyncWorker {
|
|||||||
image = sharp::Gamma(image, baton->gamma);
|
image = sharp::Gamma(image, baton->gamma);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply normalization - stretch luminance to cover full dynamic range
|
// Apply normalisation - stretch luminance to cover full dynamic range
|
||||||
if (baton->normalize) {
|
if (baton->normalise) {
|
||||||
image = sharp::Normalize(image);
|
image = sharp::Normalise(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply bitwise boolean operation between images
|
// Apply bitwise boolean operation between images
|
||||||
@ -1091,7 +1091,7 @@ NAN_METHOD(pipeline) {
|
|||||||
}
|
}
|
||||||
baton->gamma = AttrTo<double>(options, "gamma");
|
baton->gamma = AttrTo<double>(options, "gamma");
|
||||||
baton->greyscale = AttrTo<bool>(options, "greyscale");
|
baton->greyscale = AttrTo<bool>(options, "greyscale");
|
||||||
baton->normalize = AttrTo<bool>(options, "normalize");
|
baton->normalise = AttrTo<bool>(options, "normalise");
|
||||||
baton->angle = AttrTo<int32_t>(options, "angle");
|
baton->angle = AttrTo<int32_t>(options, "angle");
|
||||||
baton->rotateBeforePreExtract = AttrTo<bool>(options, "rotateBeforePreExtract");
|
baton->rotateBeforePreExtract = AttrTo<bool>(options, "rotateBeforePreExtract");
|
||||||
baton->flip = AttrTo<bool>(options, "flip");
|
baton->flip = AttrTo<bool>(options, "flip");
|
||||||
|
@ -62,7 +62,7 @@ struct PipelineBaton {
|
|||||||
int trimTolerance;
|
int trimTolerance;
|
||||||
double gamma;
|
double gamma;
|
||||||
bool greyscale;
|
bool greyscale;
|
||||||
bool normalize;
|
bool normalise;
|
||||||
int angle;
|
int angle;
|
||||||
bool rotateBeforePreExtract;
|
bool rotateBeforePreExtract;
|
||||||
bool flip;
|
bool flip;
|
||||||
@ -130,7 +130,7 @@ struct PipelineBaton {
|
|||||||
trimTolerance(0),
|
trimTolerance(0),
|
||||||
gamma(0.0),
|
gamma(0.0),
|
||||||
greyscale(false),
|
greyscale(false),
|
||||||
normalize(false),
|
normalise(false),
|
||||||
angle(0),
|
angle(0),
|
||||||
flip(false),
|
flip(false),
|
||||||
flop(false),
|
flop(false),
|
||||||
|
2
test/fixtures/index.js
vendored
2
test/fixtures/index.js
vendored
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
const maxColourDistance = require('../../build/Release/sharp')._maxColourDistance;
|
const maxColourDistance = require('../../build/Release/sharp')._maxColourDistance;
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
|
|
||||||
describe('Alpha transparency', function () {
|
describe('Alpha transparency', function () {
|
||||||
it('Flatten to black', function (done) {
|
it('Flatten to black', function (done) {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
|
|
||||||
describe('Bandbool per-channel boolean operations', function () {
|
describe('Bandbool per-channel boolean operations', function () {
|
||||||
[
|
[
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
describe('Blur', function () {
|
describe('Blur', function () {
|
||||||
|
@ -4,7 +4,7 @@ const fs = require('fs');
|
|||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
|
|
||||||
describe('Boolean operation between two images', function () {
|
describe('Boolean operation between two images', function () {
|
||||||
const inputJpgBooleanTestBuffer = fs.readFileSync(fixtures.inputJpgBooleanTest);
|
const inputJpgBooleanTestBuffer = fs.readFileSync(fixtures.inputJpgBooleanTest);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
|
|
||||||
// Define SHARP_TEST_WITHOUT_CACHE environment variable to prevent use of libvips' cache
|
// Define SHARP_TEST_WITHOUT_CACHE environment variable to prevent use of libvips' cache
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
describe('Clone', function () {
|
describe('Clone', function () {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
describe('Colour space conversion', function () {
|
describe('Colour space conversion', function () {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
describe('Convolve', function () {
|
describe('Convolve', function () {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
describe('Crop', function () {
|
describe('Crop', function () {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
describe('Embed', function () {
|
describe('Embed', function () {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
describe('Extend', function () {
|
describe('Extend', function () {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
describe('Partial image extraction', function () {
|
describe('Partial image extraction', function () {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
describe('Image channel extraction', function () {
|
describe('Image channel extraction', function () {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
describe('Gamma correction', function () {
|
describe('Gamma correction', function () {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
describe('Interpolators and kernels', function () {
|
describe('Interpolators and kernels', function () {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
describe('Input/output', function () {
|
describe('Input/output', function () {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
describe('Image channel insertion', function () {
|
describe('Image channel insertion', function () {
|
||||||
|
@ -5,7 +5,7 @@ const assert = require('assert');
|
|||||||
const exifReader = require('exif-reader');
|
const exifReader = require('exif-reader');
|
||||||
const icc = require('icc');
|
const icc = require('icc');
|
||||||
|
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
describe('Image metadata', function () {
|
describe('Image metadata', function () {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
describe('Negate', function () {
|
describe('Negate', function () {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
const assertNormalized = function (data) {
|
const assertNormalized = function (data) {
|
||||||
@ -17,13 +17,9 @@ const assertNormalized = function (data) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
describe('Normalization', function () {
|
describe('Normalization', function () {
|
||||||
it('uses the same prototype for both spellings', function () {
|
|
||||||
assert.strictEqual(sharp.prototype.normalize, sharp.prototype.normalise);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('spreads rgb image values between 0 and 255', function (done) {
|
it('spreads rgb image values between 0 and 255', function (done) {
|
||||||
sharp(fixtures.inputJpgWithLowContrast)
|
sharp(fixtures.inputJpgWithLowContrast)
|
||||||
.normalize()
|
.normalise()
|
||||||
.raw()
|
.raw()
|
||||||
.toBuffer(function (err, data, info) {
|
.toBuffer(function (err, data, info) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
@ -47,7 +43,7 @@ describe('Normalization', function () {
|
|||||||
|
|
||||||
it('stretches greyscale images with alpha channel', function (done) {
|
it('stretches greyscale images with alpha channel', function (done) {
|
||||||
sharp(fixtures.inputPngWithGreyAlpha)
|
sharp(fixtures.inputPngWithGreyAlpha)
|
||||||
.normalize()
|
.normalise()
|
||||||
.raw()
|
.raw()
|
||||||
.toBuffer(function (err, data, info) {
|
.toBuffer(function (err, data, info) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
@ -73,7 +69,7 @@ describe('Normalization', function () {
|
|||||||
|
|
||||||
it('keeps the alpha channel of greyscale images intact', function (done) {
|
it('keeps the alpha channel of greyscale images intact', function (done) {
|
||||||
sharp(fixtures.inputPngWithGreyAlpha)
|
sharp(fixtures.inputPngWithGreyAlpha)
|
||||||
.normalize()
|
.normalise()
|
||||||
.toBuffer(function (err, data) {
|
.toBuffer(function (err, data) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
sharp(data).metadata(function (err, metadata) {
|
sharp(data).metadata(function (err, metadata) {
|
||||||
@ -99,7 +95,7 @@ describe('Normalization', function () {
|
|||||||
|
|
||||||
it('works with 16-bit RGBA images', function (done) {
|
it('works with 16-bit RGBA images', function (done) {
|
||||||
sharp(fixtures.inputPngWithTransparency16bit)
|
sharp(fixtures.inputPngWithTransparency16bit)
|
||||||
.normalize()
|
.normalise()
|
||||||
.raw()
|
.raw()
|
||||||
.toBuffer(function (err, data, info) {
|
.toBuffer(function (err, data, info) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
|
@ -4,7 +4,7 @@ const fs = require('fs');
|
|||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
const getPaths = function (baseName, extension) {
|
const getPaths = function (baseName, extension) {
|
||||||
|
@ -10,6 +10,6 @@ describe('Require-time checks', function () {
|
|||||||
*/
|
*/
|
||||||
it('Require alongside C++ module that does not use libc++', function () {
|
it('Require alongside C++ module that does not use libc++', function () {
|
||||||
const bufferutil = require('bufferutil');
|
const bufferutil = require('bufferutil');
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
describe('Resize dimensions', function () {
|
describe('Resize dimensions', function () {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
describe('Rotation', function () {
|
describe('Rotation', function () {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
describe('Sharpen', function () {
|
describe('Sharpen', function () {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
describe('Threshold', function () {
|
describe('Threshold', function () {
|
||||||
|
@ -8,7 +8,7 @@ const eachLimit = require('async/eachLimit');
|
|||||||
const rimraf = require('rimraf');
|
const rimraf = require('rimraf');
|
||||||
const unzip = require('unzip');
|
const unzip = require('unzip');
|
||||||
|
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
// Verifies all tiles in a given dz output directory are <= size
|
// Verifies all tiles in a given dz output directory are <= size
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
const fixtures = require('../fixtures');
|
const fixtures = require('../fixtures');
|
||||||
|
|
||||||
describe('Trim borders', function () {
|
describe('Trim borders', function () {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const sharp = require('../../index');
|
const sharp = require('../../');
|
||||||
|
|
||||||
const defaultConcurrency = sharp.concurrency();
|
const defaultConcurrency = sharp.concurrency();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user