mirror of
https://github.com/lovell/sharp.git
synced 2026-02-04 21:56:18 +01:00
Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba29ba1ab7 | ||
|
|
e0fa15f5cb | ||
|
|
82a1ff359d | ||
|
|
18e1f10a94 | ||
|
|
4828a17643 | ||
|
|
3b4f95597a | ||
|
|
bd52e93fca | ||
|
|
6fdc79d569 | ||
|
|
7dbad7206e | ||
|
|
a8a0c1e935 | ||
|
|
00bcf60566 | ||
|
|
4a745f2d2e | ||
|
|
057074b238 | ||
|
|
4b8cc13a05 | ||
|
|
a4e8586b59 | ||
|
|
095b37db6a | ||
|
|
efff650314 | ||
|
|
0764ca8fde | ||
|
|
403160434b | ||
|
|
730ab14faa | ||
|
|
51d70c4574 | ||
|
|
765ccd2aaa | ||
|
|
5399332f81 | ||
|
|
43b7f9fc0e | ||
|
|
3925689435 | ||
|
|
96a994a4c0 | ||
|
|
84c20373ec | ||
|
|
a216d2945b | ||
|
|
755a0caf3d | ||
|
|
703d90e663 | ||
|
|
e230ce41d7 | ||
|
|
596b38a3bb | ||
|
|
d31a91a599 | ||
|
|
400ef71b6f | ||
|
|
bb15cd9067 | ||
|
|
6ee6a226e1 | ||
|
|
94d51a94c8 |
2
.github/CONTRIBUTING.md
vendored
2
.github/CONTRIBUTING.md
vendored
@@ -71,7 +71,7 @@ The public API is documented with [JSDoc](http://usejsdoc.org/) annotated commen
|
||||
|
||||
These can be converted to Markdown by running:
|
||||
```sh
|
||||
npm run docs
|
||||
npm run docs-build
|
||||
```
|
||||
|
||||
Please include documentation updates in any Pull Request that modifies the public API.
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/installation.md
vendored
2
.github/ISSUE_TEMPLATE/installation.md
vendored
@@ -13,6 +13,8 @@ Have you ensured the platform and version of Node.js used for `npm install` is t
|
||||
|
||||
If you are installing as a `root` or `sudo` user, have you tried with the `npm install --unsafe-perm` flag?
|
||||
|
||||
If you are using the `ignore-scripts` feature of `npm`, have you tried with the `npm install --ignore-scripts=false` flag?
|
||||
|
||||
What is the complete output of running `npm install --verbose sharp`? Have you checked this output for useful error messages?
|
||||
|
||||
What is the output of running `npx envinfo --binaries --languages --system --utilities`?
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -15,3 +15,4 @@ vendor
|
||||
.vscode/
|
||||
package-lock.json
|
||||
.idea
|
||||
.firebase
|
||||
|
||||
76
.travis.yml
76
.travis.yml
@@ -1,90 +1,74 @@
|
||||
matrix:
|
||||
include:
|
||||
- name: "Linux (glibc) - Node 8"
|
||||
- name: "Linux (glibc 2.17+) - Node.js 10"
|
||||
os: linux
|
||||
dist: trusty
|
||||
sudo: false
|
||||
language: node_js
|
||||
node_js: "8"
|
||||
- name: "Linux (glibc) - Node 10"
|
||||
os: linux
|
||||
dist: trusty
|
||||
sudo: false
|
||||
dist: xenial
|
||||
language: node_js
|
||||
node_js: "10"
|
||||
- name: "Linux (glibc) - Node 12"
|
||||
- name: "Linux (glibc 2.17+) - Node.js 12"
|
||||
os: linux
|
||||
dist: trusty
|
||||
sudo: false
|
||||
dist: xenial
|
||||
language: node_js
|
||||
node_js: "12"
|
||||
- name: "Linux (glibc) - Node 13"
|
||||
- name: "Linux (glibc 2.17+) - Node.js 13"
|
||||
os: linux
|
||||
dist: trusty
|
||||
sudo: false
|
||||
dist: xenial
|
||||
language: node_js
|
||||
node_js: "13"
|
||||
after_success:
|
||||
- npm install coveralls
|
||||
- cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js
|
||||
- name: "Linux (musl) - Node 8"
|
||||
- name: "Linux (musl 1.1.20+) - Node.js 10"
|
||||
os: linux
|
||||
dist: trusty
|
||||
sudo: true
|
||||
dist: bionic
|
||||
language: minimal
|
||||
before_install:
|
||||
- sudo docker run -dit --name sharp --env CI --env PREBUILD_TOKEN --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp node:8-alpine
|
||||
- sudo docker run -dit --name sharp --env CI --env PREBUILD_TOKEN --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp node:10.17.0-alpine3.9 # https://github.com/nodejs/docker-node/issues/1158
|
||||
- sudo docker exec sharp apk add build-base git python2 --update-cache
|
||||
install: sudo docker exec sharp sh -c "npm install --unsafe-perm"
|
||||
script: sudo docker exec sharp sh -c "npm test"
|
||||
- name: "Linux (musl) - Node 10"
|
||||
- name: "Linux (musl 1.1.20+) - Node.js 12"
|
||||
os: linux
|
||||
dist: trusty
|
||||
sudo: true
|
||||
language: minimal
|
||||
before_install:
|
||||
- sudo docker run -dit --name sharp --env CI --env PREBUILD_TOKEN --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp node:10-alpine
|
||||
- sudo docker exec sharp apk add build-base git python2 --update-cache
|
||||
install: sudo docker exec sharp sh -c "npm install --unsafe-perm"
|
||||
script: sudo docker exec sharp sh -c "npm test"
|
||||
- name: "Linux (musl) - Node 12"
|
||||
os: linux
|
||||
dist: trusty
|
||||
sudo: true
|
||||
dist: bionic
|
||||
language: minimal
|
||||
before_install:
|
||||
- sudo docker run -dit --name sharp --env CI --env PREBUILD_TOKEN --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp node:12.0-alpine
|
||||
- sudo docker exec sharp apk add build-base git python2 --update-cache
|
||||
install: sudo docker exec sharp sh -c "npm install --unsafe-perm"
|
||||
script: sudo docker exec sharp sh -c "npm test"
|
||||
- name: "Linux (musl) - Node 13"
|
||||
- name: "Linux (musl 1.1.20+) - Node.js 13"
|
||||
os: linux
|
||||
dist: trusty
|
||||
sudo: true
|
||||
dist: bionic
|
||||
language: minimal
|
||||
before_install:
|
||||
- sudo docker run -dit --name sharp --env CI --env PREBUILD_TOKEN --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp node:13.0-alpine
|
||||
- sudo docker exec sharp apk add build-base git python2 --update-cache
|
||||
install: sudo docker exec sharp sh -c "npm install --unsafe-perm"
|
||||
script: sudo docker exec sharp sh -c "npm test"
|
||||
- name: "OS X - Node 8"
|
||||
- name: "Linux ARM64v8 (glibc 2.29+) - Node.js 10"
|
||||
arch: arm64
|
||||
os: linux
|
||||
dist: bionic
|
||||
language: minimal
|
||||
before_install:
|
||||
- sudo docker run -dit --name sharp --env CI --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp arm64v8/debian:bullseye
|
||||
- sudo docker exec sharp apt-get update
|
||||
- sudo docker exec sharp apt-get install -y build-essential git python2 nodejs npm
|
||||
install: sudo docker exec sharp sh -c "npm install --unsafe-perm"
|
||||
script: sudo docker exec sharp sh -c "npm test"
|
||||
- name: "macOS (10.13+) - Node.js 10"
|
||||
os: osx
|
||||
osx_image: xcode9.2
|
||||
language: node_js
|
||||
node_js: "8"
|
||||
- name: "OS X - Node 10"
|
||||
os: osx
|
||||
osx_image: xcode9.2
|
||||
osx_image: xcode10.1
|
||||
language: node_js
|
||||
node_js: "10"
|
||||
- name: "OS X - Node 12"
|
||||
- name: "macOS (10.13+) - Node.js 12"
|
||||
os: osx
|
||||
osx_image: xcode9.2
|
||||
osx_image: xcode10.1
|
||||
language: node_js
|
||||
node_js: "12"
|
||||
- name: "OS X - Node 13"
|
||||
- name: "macOS (10.13+) - Node.js 13"
|
||||
os: osx
|
||||
osx_image: xcode10
|
||||
osx_image: xcode10.1
|
||||
language: node_js
|
||||
node_js: "13"
|
||||
cache:
|
||||
|
||||
@@ -20,8 +20,8 @@ Lanczos resampling ensures quality is not sacrificed for speed.
|
||||
As well as image resizing, operations such as
|
||||
rotation, extraction, compositing and gamma correction are available.
|
||||
|
||||
Most modern 64-bit OS X, Windows and Linux systems running
|
||||
Node versions 8, 10, 12 and 13
|
||||
Most modern 64-bit macOS, Windows and Linux systems running
|
||||
Node versions 10, 12 and 13
|
||||
do not require any additional install or runtime dependencies.
|
||||
|
||||
## Examples
|
||||
@@ -102,7 +102,7 @@ covers reporting bugs, requesting features and submitting code changes.
|
||||
|
||||
### Licensing
|
||||
|
||||
Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019 Lovell Fuller and contributors.
|
||||
Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Lovell Fuller and contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
os: Visual Studio 2015
|
||||
os: Visual Studio 2017
|
||||
version: "{build}"
|
||||
build: off
|
||||
platform: x64
|
||||
environment:
|
||||
matrix:
|
||||
- nodejs_version: "8"
|
||||
- nodejs_version: "10"
|
||||
- nodejs_version: "12"
|
||||
- nodejs_version: "13"
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
],
|
||||
'sources': [
|
||||
'src/libvips/cplusplus/VError.cpp',
|
||||
'src/libvips/cplusplus/VConnection.cpp',
|
||||
'src/libvips/cplusplus/VInterpolate.cpp',
|
||||
'src/libvips/cplusplus/VImage.cpp'
|
||||
],
|
||||
@@ -127,7 +128,6 @@
|
||||
'../vendor/lib/libgobject-2.0.so',
|
||||
# Dependencies of dependencies, included for openSUSE support
|
||||
'../vendor/lib/libcairo.so',
|
||||
'../vendor/lib/libcroco-0.6.so',
|
||||
'../vendor/lib/libexif.so',
|
||||
'../vendor/lib/libexpat.so',
|
||||
'../vendor/lib/libffi.so',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# sharp
|
||||
|
||||
<img src="image/sharp-logo.svg" width="160" height="160" alt="sharp logo" align="right">
|
||||
<img src="https://raw.githubusercontent.com/lovell/sharp/master/docs/image/sharp-logo.svg?sanitize=true" width="160" height="160" alt="sharp logo" align="right">
|
||||
|
||||
The typical use case for this high speed Node.js module
|
||||
is to convert large images in common formats to
|
||||
@@ -16,8 +16,8 @@ Lanczos resampling ensures quality is not sacrificed for speed.
|
||||
As well as image resizing, operations such as
|
||||
rotation, extraction, compositing and gamma correction are available.
|
||||
|
||||
Most modern 64-bit OS X, Windows and Linux systems running
|
||||
Node versions 8, 10, 12 and 13
|
||||
Most modern 64-bit macOS, Windows and Linux systems running
|
||||
Node versions 10, 12 and 13
|
||||
do not require any additional install or runtime dependencies.
|
||||
|
||||
[](https://coveralls.io/r/lovell/sharp?branch=master)
|
||||
@@ -34,15 +34,14 @@ A single input Stream can be split into multiple processing pipelines and output
|
||||
|
||||
Deep Zoom image pyramids can be generated,
|
||||
suitable for use with "slippy map" tile viewers like
|
||||
[OpenSeadragon](https://github.com/openseadragon/openseadragon)
|
||||
and [Leaflet](https://github.com/turban/Leaflet.Zoomify).
|
||||
[OpenSeadragon](https://github.com/openseadragon/openseadragon).
|
||||
|
||||
### Fast
|
||||
|
||||
This module is powered by the blazingly fast
|
||||
[libvips](https://github.com/libvips/libvips) image processing library,
|
||||
originally created in 1989 at Birkbeck College
|
||||
and currently maintained by
|
||||
and currently maintained by a small team led by
|
||||
[John Cupitt](https://github.com/jcupitt).
|
||||
|
||||
Only small regions of uncompressed image data
|
||||
@@ -131,12 +130,13 @@ the help and code contributions of the following people:
|
||||
* [Nicolas Stepien](https://github.com/MayhemYDG)
|
||||
* [Paul Neave](https://github.com/neave)
|
||||
* [Brendan Kennedy](https://github.com/rustyguts)
|
||||
* [Brychan Bennett-Odlum](https://github.com/BrychanOdlum)
|
||||
|
||||
Thank you!
|
||||
|
||||
### Licensing
|
||||
|
||||
Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019 Lovell Fuller and contributors.
|
||||
Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Lovell Fuller and contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -32,6 +32,10 @@ sharp('rgb.jpg')
|
||||
|
||||
Returns **Sharp**
|
||||
|
||||
**Meta**
|
||||
|
||||
- **since**: 0.21.2
|
||||
|
||||
## extractChannel
|
||||
|
||||
Extract a single channel from a multi-channel image.
|
||||
|
||||
@@ -61,6 +61,10 @@ sharp('input.png')
|
||||
|
||||
Returns **Sharp**
|
||||
|
||||
**Meta**
|
||||
|
||||
- **since**: 0.22.0
|
||||
|
||||
[1]: https://libvips.github.io/libvips/API/current/libvips-conversion.html#VipsBlendMode
|
||||
|
||||
[2]: https://www.cairographics.org/operators/
|
||||
|
||||
@@ -11,6 +11,11 @@
|
||||
- `options` **[Object][3]?** if present, is an Object with optional attributes.
|
||||
- `options.failOnError` **[Boolean][4]** by default halt processing and raise an error when loading invalid images.
|
||||
Set this flag to `false` if you'd rather apply a "best effort" to decode images, even if the data is corrupt or invalid. (optional, default `true`)
|
||||
- `options.limitInputPixels` **([Number][5] \| [Boolean][4])** Do not process input images where the number of pixels
|
||||
(width x height) exceeds this limit. Assumes image dimensions contained in the input metadata can be trusted.
|
||||
An integral Number of pixels, zero or false to remove limit, true to use default limit of 268402689 (0x3FFF x 0x3FFF). (optional, default `268402689`)
|
||||
- `options.sequentialRead` **[Boolean][4]** Set this to `true` to use sequential rather than random access where possible.
|
||||
This can reduce memory usage and might improve performance on some systems. (optional, default `false`)
|
||||
- `options.density` **[Number][5]** number representing the DPI for vector images. (optional, default `72`)
|
||||
- `options.pages` **[Number][5]** number of pages to extract for multi-page input (GIF, TIFF, PDF), use -1 for all pages. (optional, default `1`)
|
||||
- `options.page` **[Number][5]** page number to start extracting from for multi-page input (GIF, TIFF, PDF), zero based. (optional, default `0`)
|
||||
@@ -67,43 +72,25 @@ sharp({
|
||||
|
||||
Returns **[Sharp][8]**
|
||||
|
||||
### format
|
||||
## clone
|
||||
|
||||
An Object containing nested boolean values representing the available input and output formats/methods.
|
||||
|
||||
#### Examples
|
||||
|
||||
```javascript
|
||||
console.log(sharp.format);
|
||||
```
|
||||
|
||||
Returns **[Object][3]**
|
||||
|
||||
### versions
|
||||
|
||||
An Object containing the version numbers of libvips and its dependencies.
|
||||
|
||||
#### Examples
|
||||
|
||||
```javascript
|
||||
console.log(sharp.versions);
|
||||
```
|
||||
|
||||
## queue
|
||||
|
||||
An EventEmitter that emits a `change` event when a task is either:
|
||||
|
||||
- queued, waiting for _libuv_ to provide a worker thread
|
||||
- complete
|
||||
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
|
||||
sharp.queue.on('change', function(queueLength) {
|
||||
console.log('Queue contains ' + queueLength + ' task(s)');
|
||||
});
|
||||
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][8]**
|
||||
|
||||
[1]: https://nodejs.org/api/buffer.html
|
||||
|
||||
[2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
|
||||
|
||||
@@ -1,24 +1,5 @@
|
||||
<!-- 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 (uncached) image metadata without decoding any compressed image data.
|
||||
@@ -35,7 +16,9 @@ A `Promise` is returned when `callback` is not provided.
|
||||
- `chromaSubsampling`: String containing JPEG chroma subsampling, `4:2:0` or `4:4:4` for RGB, `4:2:0:4` or `4:4:4:4` for CMYK
|
||||
- `isProgressive`: Boolean indicating whether the image is interlaced using a progressive scan
|
||||
- `pages`: Number of pages/frames contained within the image, with support for TIFF, HEIF, PDF, animated GIF and animated WebP
|
||||
- `pageHeight`: Number of pixels high each page in this PDF image will be.
|
||||
- `pageHeight`: Number of pixels high each page in a multi-page image will be.
|
||||
- `loop`: Number of times to loop an animated image, zero refers to a continuous loop.
|
||||
- `delay`: Delay in ms between each page in an animated image, provided as an array of integers.
|
||||
- `pagePrimary`: Number of the primary page in a HEIF image
|
||||
- `hasProfile`: Boolean indicating the presence of an embedded ICC profile
|
||||
- `hasAlpha`: Boolean indicating the presence of an alpha transparency channel
|
||||
@@ -44,6 +27,7 @@ A `Promise` is returned when `callback` is not provided.
|
||||
- `icc`: Buffer containing raw [ICC][3] profile data, if present
|
||||
- `iptc`: Buffer containing raw IPTC data, if present
|
||||
- `xmp`: Buffer containing raw XMP data, if present
|
||||
- `tifftagPhotoshop`: Buffer containing raw TIFFTAG_PHOTOSHOP data, if present
|
||||
|
||||
### Parameters
|
||||
|
||||
@@ -104,34 +88,6 @@ image
|
||||
|
||||
Returns **[Promise][5]<[Object][6]>**
|
||||
|
||||
## limitInputPixels
|
||||
|
||||
Do not process input images where the number of pixels (width x height) exceeds this limit.
|
||||
Assumes image dimensions contained in the input metadata can be trusted.
|
||||
The default limit is 268402689 (0x3FFF x 0x3FFF) pixels.
|
||||
|
||||
### Parameters
|
||||
|
||||
- `limit` **([Number][7] \| [Boolean][8])** an integral Number of pixels, zero or false to remove limit, true to use default limit.
|
||||
|
||||
|
||||
- Throws **[Error][9]** Invalid limit
|
||||
|
||||
Returns **Sharp**
|
||||
|
||||
## sequentialRead
|
||||
|
||||
An advanced setting that switches the libvips access method to `VIPS_ACCESS_SEQUENTIAL`.
|
||||
This will reduce memory usage and can improve performance on some systems.
|
||||
|
||||
The default behaviour _before_ function call is `false`, meaning the libvips access method is not sequential.
|
||||
|
||||
### Parameters
|
||||
|
||||
- `sequentialRead` **[Boolean][8]** (optional, default `true`)
|
||||
|
||||
Returns **Sharp**
|
||||
|
||||
[1]: https://github.com/libvips/libvips/blob/master/libvips/iofuncs/enumtypes.c#L636
|
||||
|
||||
[2]: https://github.com/libvips/libvips/blob/master/libvips/iofuncs/enumtypes.c#L672
|
||||
@@ -143,9 +99,3 @@ Returns **Sharp**
|
||||
[5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise
|
||||
|
||||
[6]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
|
||||
|
||||
[7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
|
||||
|
||||
[8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
|
||||
|
||||
[9]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error
|
||||
|
||||
@@ -287,6 +287,10 @@ sharp(input)
|
||||
|
||||
Returns **Sharp**
|
||||
|
||||
**Meta**
|
||||
|
||||
- **since**: 0.21.1
|
||||
|
||||
## modulate
|
||||
|
||||
Transforms the image using brightness, saturation and hue rotation.
|
||||
@@ -322,6 +326,10 @@ sharp(input)
|
||||
|
||||
Returns **Sharp**
|
||||
|
||||
**Meta**
|
||||
|
||||
- **since**: 0.22.1
|
||||
|
||||
[1]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
|
||||
|
||||
[2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
|
||||
|
||||
@@ -112,6 +112,28 @@ sharp('input.jpg')
|
||||
|
||||
Returns **Sharp**
|
||||
|
||||
## toFormat
|
||||
|
||||
Force output to a given format.
|
||||
|
||||
### Parameters
|
||||
|
||||
- `format` **([String][2] \| [Object][6])** as a String or an Object with an 'id' attribute
|
||||
- `options` **[Object][6]** output options
|
||||
|
||||
### Examples
|
||||
|
||||
```javascript
|
||||
// Convert any input to PNG output
|
||||
const data = await sharp(input)
|
||||
.toFormat('png')
|
||||
.toBuffer();
|
||||
```
|
||||
|
||||
- Throws **[Error][4]** unsupported format or options
|
||||
|
||||
Returns **Sharp**
|
||||
|
||||
## jpeg
|
||||
|
||||
Use these JPEG options for output image.
|
||||
@@ -268,6 +290,10 @@ Most versions of libheif support only the patent-encumbered HEVC compression for
|
||||
|
||||
Returns **Sharp**
|
||||
|
||||
**Meta**
|
||||
|
||||
- **since**: 0.23.0
|
||||
|
||||
## raw
|
||||
|
||||
Force output to be raw, uncompressed uint8 pixel data.
|
||||
@@ -283,28 +309,6 @@ const { data, info } = await sharp('input.jpg')
|
||||
|
||||
Returns **Sharp**
|
||||
|
||||
## toFormat
|
||||
|
||||
Force output to a given format.
|
||||
|
||||
### Parameters
|
||||
|
||||
- `format` **([String][2] \| [Object][6])** as a String or an Object with an 'id' attribute
|
||||
- `options` **[Object][6]** output options
|
||||
|
||||
### Examples
|
||||
|
||||
```javascript
|
||||
// Convert any input to PNG output
|
||||
const data = await sharp(input)
|
||||
.toFormat('png')
|
||||
.toBuffer();
|
||||
```
|
||||
|
||||
- Throws **[Error][4]** unsupported format or options
|
||||
|
||||
Returns **Sharp**
|
||||
|
||||
## tile
|
||||
|
||||
Use tile-based deep zoom (image pyramid) output.
|
||||
|
||||
@@ -114,6 +114,15 @@ sharp(input)
|
||||
});
|
||||
```
|
||||
|
||||
```javascript
|
||||
const scaleByHalf = await sharp(input)
|
||||
.metadata()
|
||||
.then(({ width }) => sharp(input)
|
||||
.resize(Math.round(width * 0.5))
|
||||
.toBuffer()
|
||||
);
|
||||
```
|
||||
|
||||
- Throws **[Error][13]** Invalid parameters
|
||||
|
||||
Returns **Sharp**
|
||||
|
||||
@@ -1,5 +1,27 @@
|
||||
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
|
||||
|
||||
## format
|
||||
|
||||
An Object containing nested boolean values representing the available input and output formats/methods.
|
||||
|
||||
### Examples
|
||||
|
||||
```javascript
|
||||
console.log(sharp.format);
|
||||
```
|
||||
|
||||
Returns **[Object][1]**
|
||||
|
||||
## versions
|
||||
|
||||
An Object containing the version numbers of libvips and its dependencies.
|
||||
|
||||
### Examples
|
||||
|
||||
```javascript
|
||||
console.log(sharp.versions);
|
||||
```
|
||||
|
||||
## cache
|
||||
|
||||
Gets or, when options are provided, sets the limits of _libvips'_ operation cache.
|
||||
@@ -54,6 +76,21 @@ sharp.concurrency(0); // 4
|
||||
|
||||
Returns **[Number][3]** concurrency
|
||||
|
||||
## 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)');
|
||||
});
|
||||
```
|
||||
|
||||
## counters
|
||||
|
||||
Provides access to internal task counters.
|
||||
|
||||
@@ -1,10 +1,50 @@
|
||||
# Changelog
|
||||
|
||||
### v0.23 - "*vision*"
|
||||
## v0.24 - "*wit*"
|
||||
|
||||
Requires libvips v8.9.0.
|
||||
|
||||
### v0.24.0 - 16<sup>th</sup> January 2020
|
||||
|
||||
* Drop support for Node.js 8.
|
||||
[#1910](https://github.com/lovell/sharp/issues/1910)
|
||||
|
||||
* Drop support for undefined input where options also provided.
|
||||
[#1768](https://github.com/lovell/sharp/issues/1768)
|
||||
|
||||
* Move `limitInputPixels` and `sequentialRead` to input options, deprecating functions of the same name.
|
||||
|
||||
* Expose `delay` and `loop` metadata for animated images.
|
||||
[#1905](https://github.com/lovell/sharp/issues/1905)
|
||||
|
||||
* Ensure correct colour output for 16-bit, 2-channel PNG input with ICC profile.
|
||||
[#2013](https://github.com/lovell/sharp/issues/2013)
|
||||
|
||||
* Prevent use of sequentialRead for rotate operations.
|
||||
[#2016](https://github.com/lovell/sharp/issues/2016)
|
||||
|
||||
* Correctly bind max width and height values when using withoutEnlargement.
|
||||
[#2024](https://github.com/lovell/sharp/pull/2024)
|
||||
[@BrychanOdlum](https://github.com/BrychanOdlum)
|
||||
|
||||
* Add support for input with 16-bit RGB profile.
|
||||
[#2037](https://github.com/lovell/sharp/issues/2037)
|
||||
|
||||
## v0.23 - "*vision*"
|
||||
|
||||
Requires libvips v8.8.1.
|
||||
|
||||
#### v0.23.3 - 17<sup>th</sup> November 2019
|
||||
### v0.23.4 - 5<sup>th</sup> December 2019
|
||||
|
||||
* Handle zero-length Buffer objects when using Node.js v13.2.0+.
|
||||
|
||||
* Expose raw TIFFTAG_PHOTOSHOP metadata.
|
||||
[#1600](https://github.com/lovell/sharp/issues/1600)
|
||||
|
||||
* Improve thread safety by using copy-on-write when updating metadata.
|
||||
[#1986](https://github.com/lovell/sharp/issues/1986)
|
||||
|
||||
### v0.23.3 - 17<sup>th</sup> November 2019
|
||||
|
||||
* Ensure `trim` operation supports images contained in the alpha channel.
|
||||
[#1597](https://github.com/lovell/sharp/issues/1597)
|
||||
@@ -20,7 +60,7 @@ Requires libvips v8.8.1.
|
||||
* Ensure `modulate` and other colour-based operations can co-exist.
|
||||
[#1958](https://github.com/lovell/sharp/issues/1958)
|
||||
|
||||
#### v0.23.2 - 28<sup>th</sup> October 2019
|
||||
### v0.23.2 - 28<sup>th</sup> October 2019
|
||||
|
||||
* Add `background` option to tile output operation.
|
||||
[#1924](https://github.com/lovell/sharp/pull/1924)
|
||||
@@ -30,7 +70,7 @@ Requires libvips v8.8.1.
|
||||
[#1932](https://github.com/lovell/sharp/pull/1932)
|
||||
[@MayhemYDG](https://github.com/MayhemYDG)
|
||||
|
||||
#### v0.23.1 - 26<sup>th</sup> September 2019
|
||||
### v0.23.1 - 26<sup>th</sup> September 2019
|
||||
|
||||
* Ensure `sharp.format.vips` is present and correct (filesystem only).
|
||||
[#1813](https://github.com/lovell/sharp/issues/1813)
|
||||
@@ -52,7 +92,7 @@ Requires libvips v8.8.1.
|
||||
|
||||
* Ensure image is at least 3x3 pixels before attempting trim operation.
|
||||
|
||||
#### v0.23.0 - 29<sup>th</sup> July 2019
|
||||
### v0.23.0 - 29<sup>th</sup> July 2019
|
||||
|
||||
* Remove `overlayWith` previously deprecated in v0.22.0.
|
||||
|
||||
@@ -82,11 +122,11 @@ Requires libvips v8.8.1.
|
||||
[#1755](https://github.com/lovell/sharp/pull/1755)
|
||||
[@iovdin](https://github.com/iovdin)
|
||||
|
||||
### v0.22 - "*uptake*"
|
||||
## v0.22 - "*uptake*"
|
||||
|
||||
Requires libvips v8.7.4.
|
||||
|
||||
#### v0.22.1 - 25<sup>th</sup> April 2019
|
||||
### v0.22.1 - 25<sup>th</sup> April 2019
|
||||
|
||||
* Add `modulate` operation for brightness, saturation and hue.
|
||||
[#1601](https://github.com/lovell/sharp/pull/1601)
|
||||
@@ -99,7 +139,7 @@ Requires libvips v8.7.4.
|
||||
* Add support for Node 12.
|
||||
[#1668](https://github.com/lovell/sharp/issues/1668)
|
||||
|
||||
#### v0.22.0 - 18<sup>th</sup> March 2019
|
||||
### v0.22.0 - 18<sup>th</sup> March 2019
|
||||
|
||||
* Remove functions previously deprecated in v0.21.0:
|
||||
`background`, `crop`, `embed`, `ignoreAspectRatio`, `max`, `min` and `withoutEnlargement`.
|
||||
@@ -117,18 +157,18 @@ Requires libvips v8.7.4.
|
||||
[#1595](https://github.com/lovell/sharp/pull/1595)
|
||||
[@ramiel](https://github.com/ramiel)
|
||||
|
||||
### v0.21 - "*teeth*"
|
||||
## v0.21 - "*teeth*"
|
||||
|
||||
Requires libvips v8.7.0.
|
||||
|
||||
#### v0.21.3 - 19<sup>th</sup> January 2019
|
||||
### v0.21.3 - 19<sup>th</sup> January 2019
|
||||
|
||||
* Input image decoding now fails fast, set `failOnError` to change this behaviour.
|
||||
|
||||
* Failed filesystem-based input now separates missing file and invalid format errors.
|
||||
[#1542](https://github.com/lovell/sharp/issues/1542)
|
||||
|
||||
#### v0.21.2 - 13<sup>th</sup> January 2019
|
||||
### v0.21.2 - 13<sup>th</sup> January 2019
|
||||
|
||||
* Ensure all metadata is removed from PNG output unless `withMetadata` used.
|
||||
|
||||
@@ -153,7 +193,7 @@ Requires libvips v8.7.0.
|
||||
* Ensure forced output format applied correctly when output chaining.
|
||||
[#1528](https://github.com/lovell/sharp/issues/1528)
|
||||
|
||||
#### v0.21.1 - 7<sup>th</sup> December 2018
|
||||
### v0.21.1 - 7<sup>th</sup> December 2018
|
||||
|
||||
* Install: support `sharp_dist_base_url` npm config, like existing `SHARP_DIST_BASE_URL`.
|
||||
[#1422](https://github.com/lovell/sharp/pull/1422)
|
||||
@@ -182,7 +222,7 @@ Requires libvips v8.7.0.
|
||||
[#1483](https://github.com/lovell/sharp/pull/1483)
|
||||
[@mbklein](https://github.com/mbklein)
|
||||
|
||||
#### v0.21.0 - 4<sup>th</sup> October 2018
|
||||
### v0.21.0 - 4<sup>th</sup> October 2018
|
||||
|
||||
* Deprecate the following resize-related functions:
|
||||
`crop`, `embed`, `ignoreAspectRatio`, `max`, `min` and `withoutEnlargement`.
|
||||
@@ -219,11 +259,11 @@ Requires libvips v8.7.0.
|
||||
[#1385](https://github.com/lovell/sharp/pull/1385)
|
||||
[@freezy](https://github.com/freezy)
|
||||
|
||||
### v0.20 - "*prebuild*"
|
||||
## v0.20 - "*prebuild*"
|
||||
|
||||
Requires libvips v8.6.1.
|
||||
|
||||
#### v0.20.8 - 5<sup>th</sup> September 2018
|
||||
### v0.20.8 - 5<sup>th</sup> September 2018
|
||||
|
||||
* Avoid race conditions when creating directories during installation.
|
||||
[#1358](https://github.com/lovell/sharp/pull/1358)
|
||||
@@ -233,12 +273,12 @@ Requires libvips v8.6.1.
|
||||
[#1362](https://github.com/lovell/sharp/pull/1362)
|
||||
[@aeirola](https://github.com/aeirola)
|
||||
|
||||
#### v0.20.7 - 21<sup>st</sup> August 2018
|
||||
### v0.20.7 - 21<sup>st</sup> August 2018
|
||||
|
||||
* Use copy+unlink if rename operation fails during installation.
|
||||
[#1345](https://github.com/lovell/sharp/issues/1345)
|
||||
|
||||
#### v0.20.6 - 20<sup>th</sup> August 2018
|
||||
### v0.20.6 - 20<sup>th</sup> August 2018
|
||||
|
||||
* Add removeAlpha operation to remove alpha channel, if any.
|
||||
[#1248](https://github.com/lovell/sharp/issues/1248)
|
||||
@@ -269,13 +309,13 @@ Requires libvips v8.6.1.
|
||||
|
||||
* Add experimental entropy field to stats response.
|
||||
|
||||
#### v0.20.5 - 27<sup>th</sup> June 2018
|
||||
### v0.20.5 - 27<sup>th</sup> June 2018
|
||||
|
||||
* Expose libjpeg optimize_coding flag.
|
||||
[#1265](https://github.com/lovell/sharp/pull/1265)
|
||||
[@tomlokhorst](https://github.com/tomlokhorst)
|
||||
|
||||
#### v0.20.4 - 20<sup>th</sup> June 2018
|
||||
### v0.20.4 - 20<sup>th</sup> June 2018
|
||||
|
||||
* Prevent possible rounding error when using shrink-on-load and 90/270 degree rotation.
|
||||
[#1241](https://github.com/lovell/sharp/issues/1241)
|
||||
@@ -285,13 +325,13 @@ Requires libvips v8.6.1.
|
||||
[#1257](https://github.com/lovell/sharp/issues/1257)
|
||||
[@jeremychone](https://github.com/jeremychone)
|
||||
|
||||
#### v0.20.3 - 29<sup>th</sup> May 2018
|
||||
### v0.20.3 - 29<sup>th</sup> May 2018
|
||||
|
||||
* Fix tint operation by ensuring LAB interpretation and allowing negative values.
|
||||
[#1235](https://github.com/lovell/sharp/issues/1235)
|
||||
[@wezside](https://github.com/wezside)
|
||||
|
||||
#### v0.20.2 - 28<sup>th</sup> April 2018
|
||||
### v0.20.2 - 28<sup>th</sup> April 2018
|
||||
|
||||
* Add tint operation to set image chroma.
|
||||
[#825](https://github.com/lovell/sharp/pull/825)
|
||||
@@ -309,7 +349,7 @@ Requires libvips v8.6.1.
|
||||
[#1208](https://github.com/lovell/sharp/pull/1208)
|
||||
[@woolite64](https://github.com/woolite64)
|
||||
|
||||
#### v0.20.1 - 17<sup>th</sup> March 2018
|
||||
### v0.20.1 - 17<sup>th</sup> March 2018
|
||||
|
||||
* Improve installation experience when a globally-installed libvips below the minimum required version is found.
|
||||
[#1148](https://github.com/lovell/sharp/issues/1148)
|
||||
@@ -322,16 +362,16 @@ Requires libvips v8.6.1.
|
||||
[#1161](https://github.com/lovell/sharp/pull/1161)
|
||||
[@BiancoA](https://github.com/BiancoA)
|
||||
|
||||
#### v0.20.0 - 5<sup>th</sup> March 2018
|
||||
### v0.20.0 - 5<sup>th</sup> March 2018
|
||||
|
||||
* Add support for prebuilt sharp binaries on common platforms.
|
||||
[#186](https://github.com/lovell/sharp/issues/186)
|
||||
|
||||
### v0.19 - "*suit*"
|
||||
## v0.19 - "*suit*"
|
||||
|
||||
Requires libvips v8.6.1.
|
||||
|
||||
#### v0.19.1 - 24<sup>th</sup> February 2018
|
||||
### v0.19.1 - 24<sup>th</sup> February 2018
|
||||
|
||||
* Expose libvips' linear transform feature.
|
||||
[#1024](https://github.com/lovell/sharp/pull/1024)
|
||||
@@ -345,7 +385,7 @@ Requires libvips v8.6.1.
|
||||
[#1134](https://github.com/lovell/sharp/issues/1134)
|
||||
[@pieh](https://github.com/pieh)
|
||||
|
||||
#### v0.19.0 - 11<sup>th</sup> January 2018
|
||||
### v0.19.0 - 11<sup>th</sup> January 2018
|
||||
|
||||
* Expose offset coordinates of strategy-based crop.
|
||||
[#868](https://github.com/lovell/sharp/issues/868)
|
||||
@@ -389,17 +429,17 @@ Requires libvips v8.6.1.
|
||||
|
||||
* TIFF output: switch default predictor from 'none' to 'horizontal' to match libvips' behaviour.
|
||||
|
||||
### v0.18 - "*ridge*"
|
||||
## v0.18 - "*ridge*"
|
||||
|
||||
Requires libvips v8.5.5.
|
||||
|
||||
#### v0.18.4 - 18<sup>th</sup> September 2017
|
||||
### v0.18.4 - 18<sup>th</sup> September 2017
|
||||
|
||||
* Ensure input Buffer really is marked as Persistent, prevents mark-sweep GC.
|
||||
[#950](https://github.com/lovell/sharp/issues/950)
|
||||
[@lfdoherty](https://github.com/lfdoherty)
|
||||
|
||||
#### v0.18.3 - 13<sup>th</sup> September 2017
|
||||
### v0.18.3 - 13<sup>th</sup> September 2017
|
||||
|
||||
* Skip shrink-on-load when trimming.
|
||||
[#888](https://github.com/lovell/sharp/pull/888)
|
||||
@@ -409,7 +449,7 @@ Requires libvips v8.5.5.
|
||||
[#945](https://github.com/lovell/sharp/pull/945)
|
||||
[@pbomb](https://github.com/pbomb)
|
||||
|
||||
#### v0.18.2 - 1<sup>st</sup> July 2017
|
||||
### v0.18.2 - 1<sup>st</sup> July 2017
|
||||
|
||||
* Expose libvips' xres and yres properties for TIFF output.
|
||||
[#828](https://github.com/lovell/sharp/pull/828)
|
||||
@@ -426,13 +466,13 @@ Requires libvips v8.5.5.
|
||||
[#857](https://github.com/lovell/sharp/pull/857)
|
||||
[@ekremkaraca](https://github.com/ekremkaraca)
|
||||
|
||||
#### v0.18.1 - 30<sup>th</sup> May 2017
|
||||
### v0.18.1 - 30<sup>th</sup> May 2017
|
||||
|
||||
* Remove regression from #781 that could cause incorrect shrink calculation.
|
||||
[#831](https://github.com/lovell/sharp/issues/831)
|
||||
[@suprMax](https://github.com/suprMax)
|
||||
|
||||
#### v0.18.0 - 30<sup>th</sup> May 2017
|
||||
### v0.18.0 - 30<sup>th</sup> May 2017
|
||||
|
||||
* Remove the previously-deprecated output format "option" functions:
|
||||
quality, progressive, compressionLevel, withoutAdaptiveFiltering,
|
||||
@@ -490,11 +530,11 @@ Requires libvips v8.5.5.
|
||||
[#814](https://github.com/lovell/sharp/pull/814)
|
||||
[@jingsam](https://github.com/jingsam)
|
||||
|
||||
### v0.17 - "*quill*"
|
||||
## v0.17 - "*quill*"
|
||||
|
||||
Requires libvips v8.4.2.
|
||||
|
||||
#### v0.17.3 - 1<sup>st</sup> April 2017
|
||||
### v0.17.3 - 1<sup>st</sup> April 2017
|
||||
|
||||
* Allow toBuffer to optionally resolve a Promise with both info and data.
|
||||
[#143](https://github.com/lovell/sharp/issues/143)
|
||||
@@ -512,7 +552,7 @@ Requires libvips v8.4.2.
|
||||
[#738](https://github.com/lovell/sharp/pull/738)
|
||||
[@kristojorg](https://github.com/kristojorg)
|
||||
|
||||
#### v0.17.2 - 11<sup>th</sup> February 2017
|
||||
### v0.17.2 - 11<sup>th</sup> February 2017
|
||||
|
||||
* Ensure Readable side of Stream can start flowing after Writable side has finished.
|
||||
[#671](https://github.com/lovell/sharp/issues/671)
|
||||
@@ -522,7 +562,7 @@ Requires libvips v8.4.2.
|
||||
[#685](https://github.com/lovell/sharp/pull/685)
|
||||
[@rnanwani](https://github.com/rnanwani)
|
||||
|
||||
#### v0.17.1 - 15<sup>th</sup> January 2017
|
||||
### v0.17.1 - 15<sup>th</sup> January 2017
|
||||
|
||||
* Improve error messages for invalid parameters.
|
||||
[@spikeon](https://github.com/spikeon)
|
||||
@@ -535,7 +575,7 @@ Requires libvips v8.4.2.
|
||||
[@wangzhiwei1888](https://github.com/wangzhiwei1888)
|
||||
[#679](https://github.com/lovell/sharp/issues/679)
|
||||
|
||||
#### v0.17.0 - 11<sup>th</sup> December 2016
|
||||
### v0.17.0 - 11<sup>th</sup> December 2016
|
||||
|
||||
* Drop support for versions of Node prior to v4.
|
||||
|
||||
@@ -572,17 +612,17 @@ Requires libvips v8.4.2.
|
||||
[#646](https://github.com/lovell/sharp/issues/646)
|
||||
[@DaGaMs](https://github.com/DaGaMs)
|
||||
|
||||
### v0.16 - "*pencil*"
|
||||
## v0.16 - "*pencil*"
|
||||
|
||||
Requires libvips v8.3.3
|
||||
|
||||
#### v0.16.2 - 22<sup>nd</sup> October 2016
|
||||
### v0.16.2 - 22<sup>nd</sup> October 2016
|
||||
|
||||
* Restrict readelf usage to Linux only when detecting global libvips version.
|
||||
[#602](https://github.com/lovell/sharp/issues/602)
|
||||
[@caoko](https://github.com/caoko)
|
||||
|
||||
#### v0.16.1 - 13<sup>th</sup> October 2016
|
||||
### v0.16.1 - 13<sup>th</sup> October 2016
|
||||
|
||||
* C++11 ABI version is now auto-detected, remove sharp-cxx11 installation flag.
|
||||
|
||||
@@ -601,7 +641,7 @@ Requires libvips v8.3.3
|
||||
[#566](https://github.com/lovell/sharp/issues/566)
|
||||
[@Nateowami](https://github.com/Nateowami)
|
||||
|
||||
#### v0.16.0 - 18<sup>th</sup> August 2016
|
||||
### v0.16.0 - 18<sup>th</sup> August 2016
|
||||
|
||||
* Add pre-compiled libvips for OS X, ARMv7 and ARMv8.
|
||||
[#312](https://github.com/lovell/sharp/issues/312)
|
||||
@@ -641,11 +681,11 @@ Requires libvips v8.3.3
|
||||
* Remove deprecated interpolateWith method - use resize(w, h, { interpolator: ... })
|
||||
[#310](https://github.com/lovell/sharp/issues/310)
|
||||
|
||||
### v0.15 - "*outfit*"
|
||||
## v0.15 - "*outfit*"
|
||||
|
||||
Requires libvips v8.3.1
|
||||
|
||||
#### v0.15.1 - 12<sup>th</sup> July 2016
|
||||
### v0.15.1 - 12<sup>th</sup> July 2016
|
||||
|
||||
* Concat Stream-based input in single operation for ~+3% perf and less GC.
|
||||
[#429](https://github.com/lovell/sharp/issues/429)
|
||||
@@ -711,7 +751,7 @@ Requires libvips v8.3.1
|
||||
[#501](https://github.com/lovell/sharp/pull/501)
|
||||
[@mhirsch](https://github.com/mhirsch)
|
||||
|
||||
#### v0.15.0 - 21<sup>st</sup> May 2016
|
||||
### v0.15.0 - 21<sup>st</sup> May 2016
|
||||
|
||||
* Use libvips' new Lanczos 3 kernel as default for image reduction.
|
||||
Deprecate interpolateWith method, now provided as a resize option.
|
||||
@@ -729,11 +769,11 @@ Requires libvips v8.3.1
|
||||
[#413](https://github.com/lovell/sharp/issues/413)
|
||||
[@jardakotesovec](https://github.com/jardakotesovec)
|
||||
|
||||
### v0.14 - "*needle*"
|
||||
## v0.14 - "*needle*"
|
||||
|
||||
Requires libvips v8.2.3
|
||||
|
||||
#### v0.14.1 - 16<sup>th</sup> April 2016
|
||||
### v0.14.1 - 16<sup>th</sup> April 2016
|
||||
|
||||
* Allow removal of limitation on input pixel count via limitInputPixels. Use with care.
|
||||
[#250](https://github.com/lovell/sharp/issues/250)
|
||||
@@ -757,7 +797,7 @@ Requires libvips v8.2.3
|
||||
[#412](https://github.com/lovell/sharp/issues/412)
|
||||
[@nouh](https://github.com/nouh)
|
||||
|
||||
#### v0.14.0 - 2<sup>nd</sup> April 2016
|
||||
### v0.14.0 - 2<sup>nd</sup> April 2016
|
||||
|
||||
* Add ability to extend (pad) the edges of an image.
|
||||
[#128](https://github.com/lovell/sharp/issues/128)
|
||||
@@ -794,17 +834,17 @@ Requires libvips v8.2.3
|
||||
* Remove deprecated style of calling extract API. Breaks calls using positional arguments.
|
||||
[#276](https://github.com/lovell/sharp/issues/276)
|
||||
|
||||
### v0.13 - "*mind*"
|
||||
## v0.13 - "*mind*"
|
||||
|
||||
Requires libvips v8.2.2
|
||||
|
||||
#### v0.13.1 - 27<sup>th</sup> February 2016
|
||||
### v0.13.1 - 27<sup>th</sup> February 2016
|
||||
|
||||
* Fix embedding onto transparent backgrounds; regression introduced in v0.13.0.
|
||||
[#366](https://github.com/lovell/sharp/issues/366)
|
||||
[@diegocsandrim](https://github.com/diegocsandrim)
|
||||
|
||||
#### v0.13.0 - 15<sup>th</sup> February 2016
|
||||
### v0.13.0 - 15<sup>th</sup> February 2016
|
||||
|
||||
* Improve vector image support by allowing control of density/DPI.
|
||||
Switch pre-built libs from Imagemagick to Graphicsmagick.
|
||||
@@ -849,11 +889,11 @@ Requires libvips v8.2.2
|
||||
|
||||
* Add support for gamma correction of images with an alpha channel.
|
||||
|
||||
### v0.12 - "*look*"
|
||||
## v0.12 - "*look*"
|
||||
|
||||
Requires libvips v8.2.0
|
||||
|
||||
#### v0.12.2 - 16<sup>th</sup> January 2016
|
||||
### v0.12.2 - 16<sup>th</sup> January 2016
|
||||
|
||||
* Upgrade libvips to v8.2.0 for improved vips_shrink.
|
||||
|
||||
@@ -871,7 +911,7 @@ Requires libvips v8.2.0
|
||||
[#331](https://github.com/lovell/sharp/issues/331)
|
||||
[@dtoubelis](https://github.com/dtoubelis)
|
||||
|
||||
#### v0.12.1 - 12<sup>th</sup> December 2015
|
||||
### v0.12.1 - 12<sup>th</sup> December 2015
|
||||
|
||||
* Allow use of SIMD vector instructions (via liborc) to be toggled on/off.
|
||||
[#172](https://github.com/lovell/sharp/issues/172)
|
||||
@@ -884,7 +924,7 @@ Requires libvips v8.2.0
|
||||
|
||||
* Use the NPM-configured HTTPS proxy, if any, for binary downloads.
|
||||
|
||||
#### v0.12.0 - 23<sup>rd</sup> November 2015
|
||||
### v0.12.0 - 23<sup>rd</sup> November 2015
|
||||
|
||||
* Bundle pre-compiled libvips and its dependencies for 64-bit Linux and Windows.
|
||||
[#42](https://github.com/lovell/sharp/issues/42)
|
||||
@@ -920,9 +960,9 @@ Requires libvips v8.2.0
|
||||
[#309](https://github.com/lovell/sharp/pull/309)
|
||||
[@papandreou](https://github.com/papandreou)
|
||||
|
||||
### v0.11 - "*knife*"
|
||||
## v0.11 - "*knife*"
|
||||
|
||||
#### v0.11.4 - 5<sup>th</sup> November 2015
|
||||
### v0.11.4 - 5<sup>th</sup> November 2015
|
||||
|
||||
* Add corners, e.g. `northeast`, to existing `gravity` option.
|
||||
[#291](https://github.com/lovell/sharp/pull/291)
|
||||
@@ -936,13 +976,13 @@ Requires libvips v8.2.0
|
||||
[#287](https://github.com/lovell/sharp/pull/287)
|
||||
[@vlapo](https://github.com/vlapo)
|
||||
|
||||
#### v0.11.3 - 8<sup>th</sup> September 2015
|
||||
### v0.11.3 - 8<sup>th</sup> September 2015
|
||||
|
||||
* Intrepret blurSigma, sharpenFlat, and sharpenJagged as double precision.
|
||||
[#263](https://github.com/lovell/sharp/pull/263)
|
||||
[@chrisriley](https://github.com/chrisriley)
|
||||
|
||||
#### v0.11.2 - 28<sup>th</sup> August 2015
|
||||
### v0.11.2 - 28<sup>th</sup> August 2015
|
||||
|
||||
* Allow crop gravity to be provided as a String.
|
||||
[#255](https://github.com/lovell/sharp/pull/255)
|
||||
@@ -950,7 +990,7 @@ Requires libvips v8.2.0
|
||||
* Add support for io.js v3 and Node v4.
|
||||
[#246](https://github.com/lovell/sharp/issues/246)
|
||||
|
||||
#### v0.11.1 - 12<sup>th</sup> August 2015
|
||||
### v0.11.1 - 12<sup>th</sup> August 2015
|
||||
|
||||
* Silence MSVC warning: "C4530: C++ exception handler used, but unwind semantics are not enabled".
|
||||
[#244](https://github.com/lovell/sharp/pull/244)
|
||||
@@ -960,7 +1000,7 @@ Requires libvips v8.2.0
|
||||
[#249](https://github.com/lovell/sharp/issues/249)
|
||||
[@compeak](https://github.com/compeak)
|
||||
|
||||
#### v0.11.0 - 15<sup>th</sup> July 2015
|
||||
### v0.11.0 - 15<sup>th</sup> July 2015
|
||||
|
||||
* Allow alpha transparency compositing via new `overlayWith` method.
|
||||
[#97](https://github.com/lovell/sharp/issues/97)
|
||||
@@ -988,9 +1028,9 @@ Requires libvips v8.2.0
|
||||
[#238](https://github.com/lovell/sharp/issues/238)
|
||||
[@richardadjogah](https://github.com/richardadjogah)
|
||||
|
||||
### v0.10 - "*judgment*"
|
||||
## v0.10 - "*judgment*"
|
||||
|
||||
#### v0.10.1 - 1<sup>st</sup> June 2015
|
||||
### v0.10.1 - 1<sup>st</sup> June 2015
|
||||
|
||||
* Allow embed of image with alpha transparency onto non-transparent background.
|
||||
[#204](https://github.com/lovell/sharp/issues/204)
|
||||
@@ -1000,7 +1040,7 @@ Requires libvips v8.2.0
|
||||
[#228](https://github.com/lovell/sharp/issues/228)
|
||||
[@doggan](https://github.com/doggan)
|
||||
|
||||
#### v0.10.0 - 23<sup>rd</sup> April 2015
|
||||
### v0.10.0 - 23<sup>rd</sup> April 2015
|
||||
|
||||
* Add support for Windows (x86).
|
||||
[#19](https://github.com/lovell/sharp/issues/19)
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
/* Nest document subheadings in navigation */
|
||||
ul.subnav ul:not(.subnav) {
|
||||
padding-left: 2em;
|
||||
font-size: 80%;
|
||||
}
|
||||
96
docs/firebase.json
Normal file
96
docs/firebase.json
Normal file
@@ -0,0 +1,96 @@
|
||||
{
|
||||
"hosting": {
|
||||
"site": "pixelplumbing-sharp",
|
||||
"public": ".",
|
||||
"ignore": [
|
||||
".*",
|
||||
"*.json",
|
||||
"*.md",
|
||||
"image/**"
|
||||
],
|
||||
"headers": [
|
||||
{
|
||||
"source": "**",
|
||||
"headers": [
|
||||
{
|
||||
"key": "Cache-Control",
|
||||
"value": "max-age=86400"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"redirects": [
|
||||
{
|
||||
"source": "**/install/**",
|
||||
"destination": "/install",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "**/api-constructor/**",
|
||||
"destination": "/api-constructor",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "**/api-input/**",
|
||||
"destination": "/api-input",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "**/api-output/**",
|
||||
"destination": "/api-output",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "**/api-resize/**",
|
||||
"destination": "/api-resize",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "**/api-compsite/**",
|
||||
"destination": "/api-compsite",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "**/api-operation/**",
|
||||
"destination": "/api-operation",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "**/api-colour/**",
|
||||
"destination": "/api-colour",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "**/api-channel/**",
|
||||
"destination": "/api-channel",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "**/api-utility/**",
|
||||
"destination": "/api-utility",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "**/performance/**",
|
||||
"destination": "/performance",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "**/changelog/**",
|
||||
"destination": "/changelog",
|
||||
"type": 301
|
||||
},
|
||||
{
|
||||
"source": "/en/**",
|
||||
"destination": "/",
|
||||
"type": 301
|
||||
}
|
||||
],
|
||||
"rewrites": [
|
||||
{
|
||||
"source": "**",
|
||||
"destination": "/index.html"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
139
docs/index.html
Normal file
139
docs/index.html
Normal file
@@ -0,0 +1,139 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<link rel="icon" type="image/png" href="https://pixel.plumbing/px/32x32/sharp-logo.svg">
|
||||
<link rel="apple-touch-icon-precomposed" sizes="152x152" href="https://pixel.plumbing/px/152x152/sharp-logo.svg">
|
||||
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="https://pixel.plumbing/px/144x144/sharp-logo.svg">
|
||||
<link rel="apple-touch-icon-precomposed" sizes="120x120" href="https://pixel.plumbing/px/120x120/sharp-logo.svg">
|
||||
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="https://pixel.plumbing/px/114x114/sharp-logo.svg">
|
||||
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="https://pixel.plumbing/px/72x72/sharp-logo.svg">
|
||||
<link rel="apple-touch-icon-precomposed" href="https://pixel.plumbing/px/57x57/sharp-logo.svg">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/docute@4/dist/docute.min.css">
|
||||
<style>
|
||||
@media (max-width: 576px) {
|
||||
.shorten-strapline {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
img[alt='sharp logo'] {
|
||||
margin: 0 0 16px 16px;
|
||||
}
|
||||
</style>
|
||||
<title>sharp - High performance Node.js image processing</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="docute"></div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/docute@4/dist/docute.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/docute-google-analytics@1/dist/index.min.js"></script>
|
||||
<script>
|
||||
var docuteApiTitlePlugin = {
|
||||
name: 'apiTitle',
|
||||
extend(api) {
|
||||
api.processMarkdown(function (md) {
|
||||
var title = api.store.getters.sidebarLinks
|
||||
.filter(function (sidebarLink) {
|
||||
return sidebarLink.link === api.router.history.current.path
|
||||
})
|
||||
.map(function (sidebarLink) {
|
||||
return sidebarLink.title;
|
||||
})[0];
|
||||
return title
|
||||
? md.replace(/<!-- Generated by documentation.js. Update this documentation by updating the source code. -->/, '# ' + title)
|
||||
: md;
|
||||
});
|
||||
}
|
||||
};
|
||||
new Docute({
|
||||
router: { mode: 'history' },
|
||||
logo: '<div style="display:flex;align-items:center">'
|
||||
+ '<strong>sharp</strong> '
|
||||
+ '<img src="https://pixel.plumbing/px/16x16/sharp-logo.svg" style="padding:8px" alt="#"> '
|
||||
+ '<span style="opacity:0.8;white-space:pre" class="shorten-strapline">High performance </span> '
|
||||
+ '<span style="opacity:0.8">Node.js image processing</span> '
|
||||
+ '</div>',
|
||||
darkThemeToggler: true,
|
||||
detectSystemDarkTheme: true,
|
||||
footer: '<a href="https://pixelplumbing.com/" target="_blank">pixelplumbing.com<a>',
|
||||
plugins: [
|
||||
docuteGoogleAnalytics('UA-13034748-12'),
|
||||
docuteApiTitlePlugin
|
||||
],
|
||||
sourcePath: 'https://cdn.jsdelivr.net/gh/lovell/sharp@v0.24.0/docs',
|
||||
nav: [
|
||||
{
|
||||
title: 'Funding',
|
||||
link: 'https://opencollective.com/libvips'
|
||||
},
|
||||
{
|
||||
title: 'GitHub',
|
||||
link: 'https://github.com/lovell/sharp'
|
||||
}
|
||||
],
|
||||
sidebar: [
|
||||
{
|
||||
title: 'Home',
|
||||
link: '/'
|
||||
},
|
||||
{
|
||||
title: 'Installation',
|
||||
link: '/install'
|
||||
},
|
||||
{
|
||||
title: 'API',
|
||||
children: [
|
||||
{
|
||||
title: 'Constructor',
|
||||
link: '/api-constructor'
|
||||
},
|
||||
{
|
||||
title: 'Input metadata',
|
||||
link: '/api-input'
|
||||
},
|
||||
{
|
||||
title: 'Output options',
|
||||
link: '/api-output'
|
||||
},
|
||||
{
|
||||
title: 'Resizing images',
|
||||
link: '/api-resize'
|
||||
},
|
||||
{
|
||||
title: 'Compositing images',
|
||||
link: '/api-composite'
|
||||
},
|
||||
{
|
||||
title: 'Image operations',
|
||||
link: '/api-operation'
|
||||
},
|
||||
{
|
||||
title: 'Colour manipulation',
|
||||
link: '/api-colour'
|
||||
},
|
||||
{
|
||||
title: 'Channel manipulation',
|
||||
link: '/api-channel'
|
||||
},
|
||||
{
|
||||
title: 'Global properties',
|
||||
link: '/api-utility'
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Performance',
|
||||
link: '/performance'
|
||||
},
|
||||
{
|
||||
title: 'Changelog',
|
||||
link: '/changelog'
|
||||
}
|
||||
]
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
308
docs/install.md
308
docs/install.md
@@ -10,18 +10,69 @@ yarn add sharp
|
||||
|
||||
## Prerequisites
|
||||
|
||||
* Node.js v8.5.0+
|
||||
* Node.js v10.13.0+
|
||||
|
||||
### Building from source
|
||||
## Prebuilt binaries
|
||||
|
||||
Pre-compiled binaries for sharp are provided for use with
|
||||
Node versions 8, 10, 12 and 13 on
|
||||
64-bit Windows, OS X and Linux platforms.
|
||||
Ready-compiled sharp and libvips binaries are provided for use with
|
||||
Node.js versions 10, 12 and 13 on the most common platforms:
|
||||
|
||||
Sharp will be built from source at install time when:
|
||||
* macOS x64 (>= 10.13)
|
||||
* Linux x64 (glibc >= 2.17, musl >= 1.1.24)
|
||||
* Windows x64 with 64-bit `node.exe`
|
||||
|
||||
* a globally-installed libvips is detected,
|
||||
* pre-compiled binaries do not exist for the current platform and Node version, or
|
||||
A ~10MB tarball containing libvips and its most commonly used dependencies
|
||||
is downloaded via HTTPS and stored within `node_modules/sharp/vendor` during `npm install`.
|
||||
|
||||
This provides support for the
|
||||
JPEG, PNG, WebP, TIFF, GIF (input) and SVG (input) image formats.
|
||||
|
||||
The following platforms have prebuilt libvips but not sharp:
|
||||
|
||||
* Linux ARMv6
|
||||
* Linux ARMv7
|
||||
* Linux ARM64 (glibc >= 2.29)
|
||||
|
||||
The following platforms require compilation of both libvips and sharp from source:
|
||||
|
||||
* Linux x86
|
||||
* Linux x64 (glibc <= 2.16, includes RHEL/CentOS 6)
|
||||
* Linux ARM64 (glibc <= 2.28, musl)
|
||||
* Linux PowerPC
|
||||
* FreeBSD
|
||||
* OpenBSD
|
||||
|
||||
The following platforms are completely unsupported:
|
||||
|
||||
* Windows x86
|
||||
* Windows x64 with 32-bit `node.exe`
|
||||
|
||||
## Common problems
|
||||
|
||||
The platform and major version of Node.js used for `npm install`
|
||||
must be the same as the platform and major version of Node.js used at runtime.
|
||||
|
||||
The `npm install --unsafe-perm` flag must be used when installing as `root` or a `sudo` user.
|
||||
|
||||
Check the output of running `npm install --verbose sharp` for useful error messages.
|
||||
|
||||
## Custom libvips
|
||||
|
||||
To use a custom, globally-installed version of libvips instead of the provided binaries,
|
||||
make sure it is at least the version listed under `config.libvips` in the `package.json` file
|
||||
and that it can be located using `pkg-config --modversion vips-cpp`.
|
||||
|
||||
For help compiling libvips from source, please see
|
||||
[https://libvips.github.io/libvips/install.html#building-libvips-from-a-source-tarball](https://libvips.github.io/libvips/install.html#building-libvips-from-a-source-tarball).
|
||||
|
||||
The use of a globally-installed libvips is unsupported on Windows.
|
||||
|
||||
## Building from source
|
||||
|
||||
This module will be compiled from source at `npm install` time when:
|
||||
|
||||
* a globally-installed libvips is detected (set the `SHARP_IGNORE_GLOBAL_LIBVIPS` environment variable to skip this),
|
||||
* prebuilt binaries do not exist for the current platform and Node.js version, or
|
||||
* when the `npm install --build-from-source` flag is used.
|
||||
|
||||
Building from source requires:
|
||||
@@ -29,86 +80,32 @@ Building from source requires:
|
||||
* C++11 compatible compiler such as gcc 4.8+, clang 3.0+ or MSVC 2013+
|
||||
* [node-gyp](https://github.com/nodejs/node-gyp#installation) and its dependencies (includes Python 2.7)
|
||||
|
||||
## libvips
|
||||
## Custom prebuilt binaries
|
||||
|
||||
### Linux
|
||||
This is an advanced approach that most people will not require.
|
||||
|
||||
[](https://travis-ci.org/lovell/sharp)
|
||||
To install the prebuilt libvips binaries from a custom URL,
|
||||
set the `sharp_dist_base_url` npm config option
|
||||
or the `SHARP_DIST_BASE_URL` environment variable.
|
||||
|
||||
libvips and its dependencies are fetched and stored within `node_modules/sharp/vendor` during `npm install`.
|
||||
This involves an automated HTTPS download of approximately 10MB.
|
||||
|
||||
Most Linux-based (glibc, musl) operating systems running on x64 and ARMv6+ CPUs should "just work", e.g.:
|
||||
|
||||
* Debian 8+
|
||||
* Ubuntu 14.04+
|
||||
* Red Hat Enterprise 7+
|
||||
* CentOS 7+
|
||||
* Alpine 3.10+
|
||||
* Fedora 21+
|
||||
* openSUSE 13.2+
|
||||
* Archlinux
|
||||
* Raspbian Jessie
|
||||
* Amazon Linux
|
||||
* Solus
|
||||
|
||||
To use a globally-installed version of libvips instead of the provided binaries,
|
||||
make sure it is at least the version listed under `config.libvips` in the `package.json` file
|
||||
and that it can be located using `pkg-config --modversion vips-cpp`.
|
||||
|
||||
If you are using non-standard paths (anything other than `/usr` or `/usr/local`),
|
||||
you might need to set `PKG_CONFIG_PATH` during `npm install`
|
||||
and `LD_LIBRARY_PATH` at runtime.
|
||||
|
||||
This allows the use of newer versions of libvips with older versions of sharp.
|
||||
|
||||
For 32-bit Intel CPUs and older Linux-based operating systems such as
|
||||
those based on Red Hat Enterprise 6 (e.g. CentOS 6)
|
||||
compiling libvips from source is recommended.
|
||||
|
||||
[https://libvips.github.io/libvips/install.html#building-libvips-from-a-source-tarball](https://libvips.github.io/libvips/install.html#building-libvips-from-a-source-tarball)
|
||||
|
||||
#### Alpine Linux
|
||||
|
||||
libvips is available in the
|
||||
[community repository](https://pkgs.alpinelinux.org/packages?name=vips-dev):
|
||||
For example, both of the following will result in an attempt to download the file located at
|
||||
`https://hostname/path/libvips-x.y.z-platform.tar.gz`.
|
||||
|
||||
```sh
|
||||
apk add --upgrade --no-cache vips-dev build-base \
|
||||
--repository https://alpine.global.ssl.fastly.net/alpine/v3.10/community/
|
||||
npm config set sharp_dist_base_url "https://hostname/path/"
|
||||
npm install sharp
|
||||
```
|
||||
|
||||
The smaller stack size of musl libc means
|
||||
libvips may need to be used without a cache
|
||||
via `sharp.cache(false)` to avoid a stack overflow.
|
||||
```sh
|
||||
SHARP_DIST_BASE_URL="https://hostname/path/" npm install sharp
|
||||
```
|
||||
|
||||
### Mac OS
|
||||
To install the prebuilt sharp binaries from a custom URL, please see
|
||||
[https://github.com/prebuild/prebuild-install#custom-binaries](https://github.com/prebuild/prebuild-install#custom-binaries)
|
||||
|
||||
[](https://travis-ci.org/lovell/sharp)
|
||||
## FreeBSD
|
||||
|
||||
libvips and its dependencies are fetched and stored within `node_modules/sharp/vendor` during `npm install`.
|
||||
This involves an automated HTTPS download of approximately 8MB.
|
||||
|
||||
To use your own version of libvips instead of the provided binaries, make sure it is
|
||||
at least the version listed under `config.libvips` in the `package.json` file and
|
||||
that it can be located using `pkg-config --modversion vips-cpp`.
|
||||
|
||||
### Windows x64
|
||||
|
||||
[](https://ci.appveyor.com/project/lovell/sharp)
|
||||
|
||||
libvips and its dependencies are fetched and stored within `node_modules\sharp\vendor` during `npm install`.
|
||||
This involves an automated HTTPS download of approximately 10MB.
|
||||
If you are having issues during installation consider removing the directory
|
||||
`C:\Users\[user]\AppData\Roaming\npm-cache\_libvips`.
|
||||
|
||||
Only 64-bit (x64) `node.exe` is supported.
|
||||
|
||||
### FreeBSD
|
||||
|
||||
libvips must be installed before `npm install` is run.
|
||||
|
||||
This can be achieved via package or ports:
|
||||
The `vips` package must be installed before `npm install` is run.
|
||||
|
||||
```sh
|
||||
pkg install -y pkgconf vips
|
||||
@@ -118,46 +115,25 @@ pkg install -y pkgconf vips
|
||||
cd /usr/ports/graphics/vips/ && make install clean
|
||||
```
|
||||
|
||||
FreeBSD's gcc v4 and v5 need `CXXFLAGS=-D_GLIBCXX_USE_C99` set for C++11 support due to
|
||||
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=193528
|
||||
## Heroku
|
||||
|
||||
### Heroku
|
||||
Add the
|
||||
[jemalloc buildpack](https://github.com/gaffneyc/heroku-buildpack-jemalloc)
|
||||
to reduce the effects of memory fragmentation.
|
||||
|
||||
Set [NODE_MODULES_CACHE](https://devcenter.heroku.com/articles/nodejs-support#cache-behavior)
|
||||
Set
|
||||
[NODE_MODULES_CACHE](https://devcenter.heroku.com/articles/nodejs-support#cache-behavior)
|
||||
to `false` when using the `yarn` package manager.
|
||||
|
||||
### Docker
|
||||
|
||||
[Marc Bachmann](https://github.com/marcbachmann) maintains an
|
||||
[Ubuntu-based Dockerfile for libvips](https://github.com/marcbachmann/dockerfile-libvips).
|
||||
|
||||
```sh
|
||||
docker pull marcbachmann/libvips
|
||||
```
|
||||
|
||||
[Will Jordan](https://github.com/wjordan) maintains an
|
||||
[Alpine-based Dockerfile for libvips](https://github.com/wjordan/dockerfile-libvips).
|
||||
|
||||
```sh
|
||||
docker pull wjordan/libvips
|
||||
```
|
||||
|
||||
[Tailor Brands](https://github.com/TailorBrands) maintain
|
||||
[Debian-based Dockerfiles for libvips and nodejs](https://github.com/TailorBrands/docker-libvips).
|
||||
|
||||
```sh
|
||||
docker pull tailor/docker-libvips
|
||||
```
|
||||
|
||||
### AWS Lambda
|
||||
## AWS Lambda
|
||||
|
||||
Set the Lambda runtime to `nodejs10.x`.
|
||||
|
||||
The binaries in the `node_modules` directory of the
|
||||
[deployment package](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-create-deployment-pkg.html)
|
||||
must be for the Linux x64 platform/architecture.
|
||||
must be for the Linux x64 platform.
|
||||
|
||||
On non-Linux machines such as OS X and Windows run the following:
|
||||
On machines other than Linux x64, such as macOS and Windows, run the following:
|
||||
|
||||
```sh
|
||||
rm -rf node_modules/sharp
|
||||
@@ -174,116 +150,16 @@ docker run -v "$PWD":/var/task lambci/lambda:build-nodejs10.x npm install sharp
|
||||
To get the best performance select the largest memory available.
|
||||
A 1536 MB function provides ~12x more CPU time than a 128 MB function.
|
||||
|
||||
### NW.js
|
||||
## Electron
|
||||
|
||||
Run the `nw-gyp` tool after installation.
|
||||
Electron provides versions of the V8 JavaScript engine
|
||||
that are incompatible with Node.js.
|
||||
To ensure the correct binaries are used, run the following:
|
||||
|
||||
```sh
|
||||
cd node-modules/sharp
|
||||
nw-gyp rebuild --arch=x64 --target=[your nw version]
|
||||
node node_modules/sharp/install/dll-copy
|
||||
npm install
|
||||
npx electron-rebuild
|
||||
```
|
||||
|
||||
[http://docs.nwjs.io/en/latest/For%20Users/Advanced/Use%20Native%20Node%20Modules/](http://docs.nwjs.io/en/latest/For%20Users/Advanced/Use%20Native%20Node%20Modules/)
|
||||
|
||||
### Build tools
|
||||
|
||||
* [gulp-responsive](https://www.npmjs.com/package/gulp-responsive)
|
||||
* [grunt-sharp](https://www.npmjs.com/package/grunt-sharp)
|
||||
|
||||
### Coding tools
|
||||
|
||||
* [Sharp TypeScript Types](https://www.npmjs.com/package/@types/sharp)
|
||||
|
||||
### CLI tools
|
||||
|
||||
* [sharp-cli](https://www.npmjs.com/package/sharp-cli)
|
||||
|
||||
### Security
|
||||
|
||||
Many users of this module process untrusted, user-supplied images,
|
||||
but there are aspects of security to consider when doing so.
|
||||
|
||||
It is possible to compile libvips with support for various third-party image loaders.
|
||||
Each of these libraries has undergone differing levels of security testing.
|
||||
|
||||
Whilst tools such as [American Fuzzy Lop](http://lcamtuf.coredump.cx/afl/)
|
||||
and [Valgrind](http://valgrind.org/) have been used to test
|
||||
the most popular web-based formats, as well as libvips itself,
|
||||
you are advised to perform your own testing and sandboxing.
|
||||
|
||||
### Pre-compiled libvips binaries
|
||||
|
||||
This module will attempt to download a pre-compiled bundle of libvips
|
||||
and its dependencies on Linux and Windows machines under either of these
|
||||
conditions:
|
||||
|
||||
1. If a global installation of libvips that meets the
|
||||
minimum version requirement cannot be found;
|
||||
1. If `SHARP_IGNORE_GLOBAL_LIBVIPS` environment variable is set.
|
||||
|
||||
```sh
|
||||
SHARP_IGNORE_GLOBAL_LIBVIPS=1 npm install sharp
|
||||
```
|
||||
|
||||
Should you need to manually download and inspect these files,
|
||||
you can do so via
|
||||
[https://github.com/lovell/sharp-libvips/releases](https://github.com/lovell/sharp-libvips/releases)
|
||||
|
||||
Should you wish to install these from your own location,
|
||||
set the `sharp_dist_base_url` npm config option, e.g.
|
||||
|
||||
```sh
|
||||
npm config set sharp_dist_base_url "https://hostname/path/"
|
||||
npm install sharp
|
||||
```
|
||||
|
||||
or set the `SHARP_DIST_BASE_URL` environment variable, e.g.
|
||||
|
||||
```sh
|
||||
SHARP_DIST_BASE_URL="https://hostname/path/" npm install sharp
|
||||
```
|
||||
|
||||
to use `https://hostname/path/libvips-x.y.z-platform.tar.gz`.
|
||||
|
||||
To install the prebuilt sharp binaries from a custom URL, please see
|
||||
[https://github.com/prebuild/prebuild-install#custom-binaries](https://github.com/prebuild/prebuild-install#custom-binaries)
|
||||
|
||||
### Licences
|
||||
|
||||
This module is licensed under the terms of the
|
||||
[Apache 2.0 Licence](https://github.com/lovell/sharp/blob/master/LICENSE).
|
||||
|
||||
The libraries downloaded and used by this module
|
||||
are done so under the terms of the following licences,
|
||||
all of which are compatible with the Apache 2.0 Licence.
|
||||
|
||||
Use of libraries under the terms of the LGPLv3 is via the
|
||||
"any later version" clause of the LGPLv2 or LGPLv2.1.
|
||||
|
||||
| Library | Used under the terms of |
|
||||
|---------------|----------------------------------------------------------------------------------------------------------|
|
||||
| cairo | Mozilla Public License 2.0 |
|
||||
| expat | MIT Licence |
|
||||
| fontconfig | [fontconfig Licence](https://cgit.freedesktop.org/fontconfig/tree/COPYING) (BSD-like) |
|
||||
| freetype | [freetype Licence](http://git.savannah.gnu.org/cgit/freetype/freetype2.git/tree/docs/FTL.TXT) (BSD-like) |
|
||||
| fribidi | LGPLv3 |
|
||||
| gettext | LGPLv3 |
|
||||
| giflib | MIT Licence |
|
||||
| glib | LGPLv3 |
|
||||
| harfbuzz | MIT Licence |
|
||||
| lcms | MIT Licence |
|
||||
| libcroco | LGPLv3 |
|
||||
| libexif | LGPLv3 |
|
||||
| libffi | MIT Licence |
|
||||
| libgsf | LGPLv3 |
|
||||
| libjpeg-turbo | [zlib License, IJG License](https://github.com/libjpeg-turbo/libjpeg-turbo/blob/master/LICENSE.md) |
|
||||
| libpng | [libpng License](http://www.libpng.org/pub/png/src/libpng-LICENSE.txt) |
|
||||
| librsvg | LGPLv3 |
|
||||
| libtiff | [libtiff License](http://www.libtiff.org/misc.html) (BSD-like) |
|
||||
| libvips | LGPLv3 |
|
||||
| libwebp | New BSD License |
|
||||
| libxml2 | MIT Licence |
|
||||
| pango | LGPLv3 |
|
||||
| pixman | MIT Licence |
|
||||
| zlib | [zlib Licence](https://github.com/madler/zlib/blob/master/zlib.h) |
|
||||
Further help can be found at
|
||||
[https://electronjs.org/docs/tutorial/using-native-node-modules](https://electronjs.org/docs/tutorial/using-native-node-modules)
|
||||
|
||||
@@ -1,44 +1,46 @@
|
||||
# Performance
|
||||
|
||||
### Test environment
|
||||
A test to benchmark the performance of this module relative to alternatives.
|
||||
|
||||
* AWS EC2 eu-west-1 [c5.large](https://aws.amazon.com/ec2/instance-types/c5/) (2x Xeon Platinum 8124M CPU @ 3.00GHz)
|
||||
* Ubuntu 18.04 (hvm-ssd/ubuntu-bionic-18.04-amd64-server-20180912 ami-00035f41c82244dab)
|
||||
* Node.js v12.10.0
|
||||
## The contenders
|
||||
|
||||
### The contenders
|
||||
|
||||
* [jimp](https://www.npmjs.com/package/jimp) v0.8.4 - Image processing in pure JavaScript. Provides bicubic interpolation.
|
||||
* [jimp](https://www.npmjs.com/package/jimp) v0.9.3 - Image processing in pure JavaScript. Provides bicubic interpolation.
|
||||
* [mapnik](https://www.npmjs.org/package/mapnik) v4.3.1 - Whilst primarily a map renderer, Mapnik contains bitmap image utilities.
|
||||
* [imagemagick](https://www.npmjs.com/package/imagemagick) v0.1.3 - Supports filesystem only and "*has been unmaintained for a long time*".
|
||||
* [gm](https://www.npmjs.com/package/gm) v1.23.1 - Fully featured wrapper around GraphicsMagick's `gm` command line utility.
|
||||
* sharp v0.23.1 / libvips v8.8.1 - Caching within libvips disabled to ensure a fair comparison.
|
||||
* sharp v0.24.0 / libvips v8.9.0 - Caching within libvips disabled to ensure a fair comparison.
|
||||
|
||||
### The task
|
||||
## The task
|
||||
|
||||
Decompress a 2725x2225 JPEG image,
|
||||
resize to 720x588 using Lanczos 3 resampling (where available),
|
||||
then compress to JPEG at a "quality" setting of 80.
|
||||
|
||||
### Results
|
||||
## Test environment
|
||||
|
||||
* AWS EC2 eu-west-1 [c5.large](https://aws.amazon.com/ec2/instance-types/c5/) (2x Xeon Platinum 8124M CPU @ 3.00GHz)
|
||||
* Ubuntu 18.04 (hvm-ssd/ubuntu-bionic-18.04-amd64-server-20180912 ami-00035f41c82244dab)
|
||||
* Node.js v12.14.1
|
||||
|
||||
## Results
|
||||
|
||||
| Module | Input | Output | Ops/sec | Speed-up |
|
||||
| :----------------- | :----- | :----- | ------: | -------: |
|
||||
| jimp | buffer | buffer | 0.66 | 1.0 |
|
||||
| mapnik | buffer | buffer | 3.31 | 5.0 |
|
||||
| gm | buffer | buffer | 3.79 | 5.7 |
|
||||
| gm | file | file | 3.82 | 5.8 |
|
||||
| imagemagick | file | file | 4.17 | 6.3 |
|
||||
| sharp | stream | stream | 25.81 | 39.1 |
|
||||
| sharp | file | file | 26.76 | 40.5 |
|
||||
| sharp | buffer | buffer | 28.06 | 42.5 |
|
||||
| jimp | buffer | buffer | 0.72 | 1.0 |
|
||||
| mapnik | buffer | buffer | 3.02 | 4.2 |
|
||||
| gm | buffer | buffer | 3.90 | 5.4 |
|
||||
| gm | file | file | 3.94 | 5.5 |
|
||||
| imagemagick | file | file | 4.30 | 6.0 |
|
||||
| sharp | stream | stream | 23.65 | 32.8 |
|
||||
| sharp | file | file | 24.66 | 34.3 |
|
||||
| sharp | buffer | buffer | 25.14 | 34.9 |
|
||||
|
||||
Greater libvips performance can be expected with caching enabled (default)
|
||||
and using 8+ core machines, especially those with larger L1/L2 CPU caches.
|
||||
|
||||
The I/O limits of the relevant (de)compression library will generally determine maximum throughput.
|
||||
|
||||
### Benchmark test prerequisites
|
||||
## Running the benchmark test
|
||||
|
||||
Requires _ImageMagick_, _GraphicsMagick_ and _Mapnik_:
|
||||
|
||||
@@ -56,8 +58,6 @@ sudo apt-get install imagemagick libmagick++-dev graphicsmagick libmapnik-dev
|
||||
sudo yum install ImageMagick-devel ImageMagick-c++-devel GraphicsMagick mapnik-devel
|
||||
```
|
||||
|
||||
### Running the benchmark test
|
||||
|
||||
```sh
|
||||
git clone https://github.com/lovell/sharp.git
|
||||
cd sharp
|
||||
|
||||
@@ -23,7 +23,7 @@ const fail = function (err) {
|
||||
npmLog.info('sharp', 'Are you trying to install as a root or sudo user? Try again with the --unsafe-perm flag');
|
||||
}
|
||||
npmLog.info('sharp', 'Attempting to build from source via node-gyp but this may fail due to the above error');
|
||||
npmLog.info('sharp', 'Please see https://sharp.pixelplumbing.com/page/install for required dependencies');
|
||||
npmLog.info('sharp', 'Please see https://sharp.pixelplumbing.com/install for required dependencies');
|
||||
process.exit(1);
|
||||
};
|
||||
|
||||
@@ -66,8 +66,11 @@ try {
|
||||
if (platformAndArch === 'freebsd-x64' || platformAndArch === 'openbsd-x64' || platformAndArch === 'sunos-x64') {
|
||||
throw new Error(`BSD/SunOS systems require manual installation of libvips >= ${minimumLibvipsVersion}`);
|
||||
}
|
||||
if (detectLibc.family === detectLibc.GLIBC && detectLibc.version && semver.lt(`${detectLibc.version}.0`, '2.17.0')) {
|
||||
throw new Error(`Use with glibc version ${detectLibc.version} requires manual installation of libvips >= ${minimumLibvipsVersion}`);
|
||||
if (detectLibc.family === detectLibc.GLIBC && detectLibc.version) {
|
||||
const minimumGlibcVersion = arch === 'arm64' ? '2.29.0' : '2.17.0';
|
||||
if (semver.lt(`${detectLibc.version}.0`, minimumGlibcVersion)) {
|
||||
throw new Error(`Use with glibc ${detectLibc.version} requires manual installation of libvips >= ${minimumLibvipsVersion}`);
|
||||
}
|
||||
}
|
||||
// Download to per-process temporary file
|
||||
const tarFilename = ['libvips', minimumLibvipsVersion, platformAndArch].join('-') + '.tar.gz';
|
||||
@@ -84,7 +87,7 @@ try {
|
||||
if (err) {
|
||||
fail(err);
|
||||
} else if (response.statusCode === 404) {
|
||||
fail(new Error(`Prebuilt libvips binaries are not yet available for ${platformAndArch}`));
|
||||
fail(new Error(`Prebuilt libvips ${minimumLibvipsVersion} binaries are not yet available for ${platformAndArch}`));
|
||||
} else if (response.statusCode !== 200) {
|
||||
fail(new Error(`Status ${response.statusCode} ${response.statusMessage}`));
|
||||
} else {
|
||||
|
||||
@@ -32,6 +32,8 @@ function removeAlpha () {
|
||||
/**
|
||||
* Ensure alpha channel, if missing. The added alpha channel will be fully opaque. This is a no-op if the image already has an alpha channel.
|
||||
*
|
||||
* @since 0.21.2
|
||||
*
|
||||
* @example
|
||||
* sharp('rgb.jpg')
|
||||
* .ensureAlpha()
|
||||
|
||||
@@ -53,6 +53,8 @@ const blend = {
|
||||
* https://libvips.github.io/libvips/API/current/libvips-conversion.html#VipsBlendMode
|
||||
* and https://www.cairographics.org/operators/
|
||||
*
|
||||
* @since 0.22.0
|
||||
*
|
||||
* @example
|
||||
* sharp('input.png')
|
||||
* .rotate(180)
|
||||
|
||||
@@ -2,15 +2,13 @@
|
||||
|
||||
const util = require('util');
|
||||
const stream = require('stream');
|
||||
const events = require('events');
|
||||
const is = require('./is');
|
||||
|
||||
require('./libvips').hasVendoredLibvips();
|
||||
|
||||
let sharp;
|
||||
/* istanbul ignore next */
|
||||
try {
|
||||
sharp = require('../build/Release/sharp.node');
|
||||
require('../build/Release/sharp.node');
|
||||
} catch (err) {
|
||||
// Bail early if bindings aren't available
|
||||
const help = ['', 'Something went wrong installing the "sharp" module', '', err.message, ''];
|
||||
@@ -18,22 +16,27 @@ try {
|
||||
help.push('- Ensure the version of Node.js used at install time matches that used at runtime');
|
||||
} else if (/invalid ELF header/.test(err.message)) {
|
||||
help.push(`- Ensure "${process.platform}" is used at install time as well as runtime`);
|
||||
} else if (/Cannot find module/.test(err.message)) {
|
||||
help.push('- Run "npm rebuild --verbose sharp" and look for errors');
|
||||
} else {
|
||||
help.push('- Remove the "node_modules/sharp" directory, run "npm install" and look for errors');
|
||||
help.push(
|
||||
'- Remove the "node_modules/sharp" directory then run',
|
||||
' "npm install --ignore-scripts=false --verbose" and look for errors'
|
||||
);
|
||||
}
|
||||
help.push(
|
||||
'- Consult the installation documentation at https://sharp.pixelplumbing.com/en/stable/install/',
|
||||
'- Consult the installation documentation at https://sharp.pixelplumbing.com/install',
|
||||
'- Search for this error at https://github.com/lovell/sharp/issues', ''
|
||||
);
|
||||
console.error(help.join('\n'));
|
||||
process.exit(1);
|
||||
const error = help.join('\n');
|
||||
throw new Error(error);
|
||||
}
|
||||
|
||||
// Use NODE_DEBUG=sharp to enable libvips warnings
|
||||
const debuglog = util.debuglog('sharp');
|
||||
|
||||
/**
|
||||
* @class Sharp
|
||||
* @constructs sharp
|
||||
*
|
||||
* Constructor factory to create an instance of `sharp`, to which further methods are chained.
|
||||
*
|
||||
@@ -83,6 +86,11 @@ const debuglog = util.debuglog('sharp');
|
||||
* @param {Object} [options] - if present, is an Object with optional attributes.
|
||||
* @param {Boolean} [options.failOnError=true] - by default halt processing and raise an error when loading invalid images.
|
||||
* Set this flag to `false` if you'd rather apply a "best effort" to decode images, even if the data is corrupt or invalid.
|
||||
* @param {Number|Boolean} [options.limitInputPixels=268402689] - Do not process input images where the number of pixels
|
||||
* (width x height) exceeds this limit. Assumes image dimensions contained in the input metadata can be trusted.
|
||||
* An integral Number of pixels, zero or false to remove limit, true to use default limit of 268402689 (0x3FFF x 0x3FFF).
|
||||
* @param {Boolean} [options.sequentialRead=false] - Set this to `true` to use sequential rather than random access where possible.
|
||||
* This can reduce memory usage and might improve performance on some systems.
|
||||
* @param {Number} [options.density=72] - number representing the DPI for vector images.
|
||||
* @param {Number} [options.pages=1] - number of pages to extract for multi-page input (GIF, TIFF, PDF), use -1 for all pages.
|
||||
* @param {Number} [options.page=0] - page number to start extracting from for multi-page input (GIF, TIFF, PDF), zero based.
|
||||
@@ -107,9 +115,6 @@ const Sharp = function (input, options) {
|
||||
}
|
||||
stream.Duplex.call(this);
|
||||
this.options = {
|
||||
// input options
|
||||
sequentialRead: false,
|
||||
limitInputPixels: Math.pow(0x3FFF, 2),
|
||||
// resize options
|
||||
topOffsetPre: -1,
|
||||
leftOffsetPre: -1,
|
||||
@@ -220,7 +225,7 @@ const Sharp = function (input, options) {
|
||||
debuglog: debuglog,
|
||||
// Function to notify of queue length changes
|
||||
queueListener: function (queueLength) {
|
||||
queue.emit('change', queueLength);
|
||||
Sharp.queue.emit('change', queueLength);
|
||||
}
|
||||
};
|
||||
this.options.input = this._createInputDescriptor(input, options, { allowStream: true });
|
||||
@@ -229,38 +234,36 @@ const Sharp = function (input, options) {
|
||||
util.inherits(Sharp, stream.Duplex);
|
||||
|
||||
/**
|
||||
* An EventEmitter that emits a `change` event when a task is either:
|
||||
* - queued, waiting for _libuv_ to provide a worker thread
|
||||
* - complete
|
||||
* @member
|
||||
* 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
|
||||
* sharp.queue.on('change', function(queueLength) {
|
||||
* console.log('Queue contains ' + queueLength + ' task(s)');
|
||||
* });
|
||||
* 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 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 = {
|
||||
vips: sharp.libvipsVersion()
|
||||
};
|
||||
try {
|
||||
Sharp.versions = require('../vendor/versions.json');
|
||||
} catch (err) {}
|
||||
function clone () {
|
||||
// Clone existing options
|
||||
const clone = this.constructor.call();
|
||||
clone.options = Object.assign({}, this.options);
|
||||
// Pass 'finish' event to clone for Stream-based input
|
||||
if (this._isStreamInput()) {
|
||||
this.on('finish', () => {
|
||||
// Clone inherits input data
|
||||
this._flattenBufferIn();
|
||||
clone.options.bufferIn = this.options.bufferIn;
|
||||
clone.emit('finish');
|
||||
});
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
Object.assign(Sharp.prototype, { clone });
|
||||
|
||||
/**
|
||||
* Export constructor.
|
||||
|
||||
100
lib/input.js
100
lib/input.js
@@ -1,5 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const util = require('util');
|
||||
const color = require('color');
|
||||
const is = require('./is');
|
||||
const sharp = require('../build/Release/sharp.node');
|
||||
@@ -9,7 +10,11 @@ const sharp = require('../build/Release/sharp.node');
|
||||
* @private
|
||||
*/
|
||||
function _createInputDescriptor (input, inputOptions, containerOptions) {
|
||||
const inputDescriptor = { failOnError: true };
|
||||
const inputDescriptor = {
|
||||
failOnError: true,
|
||||
limitInputPixels: Math.pow(0x3FFF, 2),
|
||||
sequentialRead: false
|
||||
};
|
||||
if (is.string(input)) {
|
||||
// filesystem
|
||||
inputDescriptor.file = input;
|
||||
@@ -23,11 +28,13 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
||||
// Raw Stream
|
||||
inputDescriptor.buffer = [];
|
||||
}
|
||||
} else if (!is.defined(input) && is.object(containerOptions) && containerOptions.allowStream) {
|
||||
} else if (!is.defined(input) && !is.defined(inputOptions) && is.object(containerOptions) && containerOptions.allowStream) {
|
||||
// Stream
|
||||
inputDescriptor.buffer = [];
|
||||
} else {
|
||||
throw new Error('Unsupported input ' + typeof input);
|
||||
throw new Error(`Unsupported input '${input}' of type ${typeof input}${
|
||||
is.defined(inputOptions) ? ` when also providing options of type ${typeof inputOptions}` : ''
|
||||
}`);
|
||||
}
|
||||
if (is.object(inputOptions)) {
|
||||
// Fail on error
|
||||
@@ -46,6 +53,26 @@ function _createInputDescriptor (input, inputOptions, containerOptions) {
|
||||
throw is.invalidParameterError('density', 'number between 1 and 2400', inputOptions.density);
|
||||
}
|
||||
}
|
||||
// limitInputPixels
|
||||
if (is.defined(inputOptions.limitInputPixels)) {
|
||||
if (is.bool(inputOptions.limitInputPixels)) {
|
||||
inputDescriptor.limitInputPixels = inputOptions.limitInputPixels
|
||||
? Math.pow(0x3FFF, 2)
|
||||
: 0;
|
||||
} else if (is.integer(inputOptions.limitInputPixels) && inputOptions.limitInputPixels >= 0) {
|
||||
inputDescriptor.limitInputPixels = inputOptions.limitInputPixels;
|
||||
} else {
|
||||
throw is.invalidParameterError('limitInputPixels', 'integer >= 0', inputOptions.limitInputPixels);
|
||||
}
|
||||
}
|
||||
// sequentialRead
|
||||
if (is.defined(inputOptions.sequentialRead)) {
|
||||
if (is.bool(inputOptions.sequentialRead)) {
|
||||
inputDescriptor.sequentialRead = inputOptions.sequentialRead;
|
||||
} else {
|
||||
throw is.invalidParameterError('sequentialRead', 'boolean', inputOptions.sequentialRead);
|
||||
}
|
||||
}
|
||||
// Raw pixel input
|
||||
if (is.defined(inputOptions.raw)) {
|
||||
if (
|
||||
@@ -152,37 +179,6 @@ 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}
|
||||
*/
|
||||
function clone () {
|
||||
// Clone existing options
|
||||
const clone = this.constructor.call();
|
||||
clone.options = Object.assign({}, this.options);
|
||||
// Pass 'finish' event to clone for Stream-based input
|
||||
if (this._isStreamInput()) {
|
||||
this.on('finish', () => {
|
||||
// Clone inherits input data
|
||||
this._flattenBufferIn();
|
||||
clone.options.bufferIn = this.options.bufferIn;
|
||||
clone.emit('finish');
|
||||
});
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast access to (uncached) image metadata without decoding any compressed image data.
|
||||
* A `Promise` is returned when `callback` is not provided.
|
||||
@@ -198,7 +194,9 @@ function clone () {
|
||||
* - `chromaSubsampling`: String containing JPEG chroma subsampling, `4:2:0` or `4:4:4` for RGB, `4:2:0:4` or `4:4:4:4` for CMYK
|
||||
* - `isProgressive`: Boolean indicating whether the image is interlaced using a progressive scan
|
||||
* - `pages`: Number of pages/frames contained within the image, with support for TIFF, HEIF, PDF, animated GIF and animated WebP
|
||||
* - `pageHeight`: Number of pixels high each page in this PDF image will be.
|
||||
* - `pageHeight`: Number of pixels high each page in a multi-page image will be.
|
||||
* - `loop`: Number of times to loop an animated image, zero refers to a continuous loop.
|
||||
* - `delay`: Delay in ms between each page in an animated image, provided as an array of integers.
|
||||
* - `pagePrimary`: Number of the primary page in a HEIF image
|
||||
* - `hasProfile`: Boolean indicating the presence of an embedded ICC profile
|
||||
* - `hasAlpha`: Boolean indicating the presence of an alpha transparency channel
|
||||
@@ -207,6 +205,7 @@ function clone () {
|
||||
* - `icc`: Buffer containing raw [ICC](https://www.npmjs.com/package/icc) profile data, if present
|
||||
* - `iptc`: Buffer containing raw IPTC data, if present
|
||||
* - `xmp`: Buffer containing raw XMP data, if present
|
||||
* - `tifftagPhotoshop`: Buffer containing raw TIFFTAG_PHOTOSHOP data, if present
|
||||
*
|
||||
* @example
|
||||
* const image = sharp(inputJpg);
|
||||
@@ -333,14 +332,9 @@ function stats (callback) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not process input images where the number of pixels (width x height) exceeds this limit.
|
||||
* Assumes image dimensions contained in the input metadata can be trusted.
|
||||
* The default limit is 268402689 (0x3FFF x 0x3FFF) pixels.
|
||||
* @param {(Number|Boolean)} limit - an integral Number of pixels, zero or false to remove limit, true to use default limit.
|
||||
* @returns {Sharp}
|
||||
* @throws {Error} Invalid limit
|
||||
*/
|
||||
function limitInputPixels (limit) {
|
||||
* @private
|
||||
*/
|
||||
const limitInputPixels = util.deprecate(function limitInputPixels (limit) {
|
||||
// if we pass in false we represent the integer as 0 to disable
|
||||
if (limit === false) {
|
||||
limit = 0;
|
||||
@@ -348,26 +342,20 @@ function limitInputPixels (limit) {
|
||||
limit = Math.pow(0x3FFF, 2);
|
||||
}
|
||||
if (is.integer(limit) && limit >= 0) {
|
||||
this.options.limitInputPixels = limit;
|
||||
this.options.input.limitInputPixels = limit;
|
||||
} else {
|
||||
throw is.invalidParameterError('limitInputPixels', 'integer', limit);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}, 'limitInputPixels is deprecated, use sharp(input, { limitInputPixels: false }) instead');
|
||||
|
||||
/**
|
||||
* An advanced setting that switches the libvips access method to `VIPS_ACCESS_SEQUENTIAL`.
|
||||
* This will reduce memory usage and can improve performance on some systems.
|
||||
*
|
||||
* The default behaviour *before* function call is `false`, meaning the libvips access method is not sequential.
|
||||
*
|
||||
* @param {Boolean} [sequentialRead=true]
|
||||
* @returns {Sharp}
|
||||
* @private
|
||||
*/
|
||||
function sequentialRead (sequentialRead) {
|
||||
this.options.sequentialRead = is.bool(sequentialRead) ? sequentialRead : true;
|
||||
const sequentialRead = util.deprecate(function sequentialRead (sequentialRead) {
|
||||
this.options.input.sequentialRead = is.bool(sequentialRead) ? sequentialRead : true;
|
||||
return this;
|
||||
}
|
||||
}, 'sequentialRead is deprecated, use sharp(input, { sequentialRead: true }) instead');
|
||||
|
||||
/**
|
||||
* Decorate the Sharp prototype with input-related functions.
|
||||
@@ -381,9 +369,9 @@ module.exports = function (Sharp) {
|
||||
_flattenBufferIn,
|
||||
_isStreamInput,
|
||||
// Public
|
||||
clone,
|
||||
metadata,
|
||||
stats,
|
||||
// Deprecated
|
||||
limitInputPixels,
|
||||
sequentialRead
|
||||
});
|
||||
|
||||
@@ -379,6 +379,8 @@ function linear (a, b) {
|
||||
/**
|
||||
* Recomb the image with the specified matrix.
|
||||
*
|
||||
* @since 0.21.1
|
||||
*
|
||||
* @example
|
||||
* sharp(input)
|
||||
* .recomb([
|
||||
@@ -416,6 +418,8 @@ function recomb (inputMatrix) {
|
||||
/**
|
||||
* Transforms the image using brightness, saturation and hue rotation.
|
||||
*
|
||||
* @since 0.22.1
|
||||
*
|
||||
* @example
|
||||
* sharp(input)
|
||||
* .modulate({
|
||||
|
||||
@@ -3,6 +3,17 @@
|
||||
const is = require('./is');
|
||||
const sharp = require('../build/Release/sharp.node');
|
||||
|
||||
const formats = new Map([
|
||||
['heic', 'heif'],
|
||||
['heif', 'heif'],
|
||||
['jpeg', 'jpeg'],
|
||||
['jpg', 'jpeg'],
|
||||
['png', 'png'],
|
||||
['raw', 'raw'],
|
||||
['tiff', 'tiff'],
|
||||
['webp', 'webp']
|
||||
]);
|
||||
|
||||
/**
|
||||
* Write output image data to a file.
|
||||
*
|
||||
@@ -135,6 +146,28 @@ function withMetadata (options) {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force output to a given format.
|
||||
*
|
||||
* @example
|
||||
* // Convert any input to PNG output
|
||||
* const data = await sharp(input)
|
||||
* .toFormat('png')
|
||||
* .toBuffer();
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
function toFormat (format, options) {
|
||||
const actualFormat = formats.get(is.object(format) && is.string(format.id) ? format.id : format);
|
||||
if (!actualFormat) {
|
||||
throw is.invalidParameterError('format', `one of: ${[...formats.keys()].join(', ')}`, format);
|
||||
}
|
||||
return this[actualFormat](options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use these JPEG options for output image.
|
||||
*
|
||||
@@ -444,6 +477,8 @@ function tiff (options) {
|
||||
*
|
||||
* Most versions of libheif support only the patent-encumbered HEVC compression format.
|
||||
*
|
||||
* @since 0.23.0
|
||||
*
|
||||
* @param {Object} [options] - output options
|
||||
* @param {Number} [options.quality=80] - quality, integer 1-100
|
||||
* @param {Boolean} [options.compression='hevc'] - compression format: hevc, avc, jpeg, av1
|
||||
@@ -496,39 +531,6 @@ function raw () {
|
||||
return this._updateFormatOut('raw');
|
||||
}
|
||||
|
||||
const formats = new Map([
|
||||
['heic', 'heif'],
|
||||
['heif', 'heif'],
|
||||
['jpeg', 'jpeg'],
|
||||
['jpg', 'jpeg'],
|
||||
['png', 'png'],
|
||||
['raw', 'raw'],
|
||||
['tiff', 'tiff'],
|
||||
['webp', 'webp']
|
||||
]);
|
||||
|
||||
/**
|
||||
* Force output to a given format.
|
||||
*
|
||||
* @example
|
||||
* // Convert any input to PNG output
|
||||
* const data = await sharp(input)
|
||||
* .toFormat('png')
|
||||
* .toBuffer();
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
function toFormat (format, options) {
|
||||
const actualFormat = formats.get(is.object(format) && is.string(format.id) ? format.id : format);
|
||||
if (!actualFormat) {
|
||||
throw is.invalidParameterError('format', `one of: ${[...formats.keys()].join(', ')}`, format);
|
||||
}
|
||||
return this[actualFormat](options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use tile-based deep zoom (image pyramid) output.
|
||||
* Set the format and options for tile images via the `toFormat`, `jpeg`, `png` or `webp` functions.
|
||||
@@ -777,13 +779,13 @@ module.exports = function (Sharp) {
|
||||
toFile,
|
||||
toBuffer,
|
||||
withMetadata,
|
||||
toFormat,
|
||||
jpeg,
|
||||
png,
|
||||
webp,
|
||||
tiff,
|
||||
heif,
|
||||
raw,
|
||||
toFormat,
|
||||
tile,
|
||||
// Private
|
||||
_updateFormatOut,
|
||||
|
||||
@@ -173,6 +173,14 @@ const mapFitToCanvas = {
|
||||
* // and no larger than the input image
|
||||
* });
|
||||
*
|
||||
* @example
|
||||
* const scaleByHalf = await sharp(input)
|
||||
* .metadata()
|
||||
* .then(({ width }) => sharp(input)
|
||||
* .resize(Math.round(width * 0.5))
|
||||
* .toBuffer()
|
||||
* );
|
||||
*
|
||||
* @param {Number} [width] - pixels wide the resultant image should be. Use `null` or `undefined` to auto-scale the width to match the height.
|
||||
* @param {Number} [height] - pixels high the resultant image should be. Use `null` or `undefined` to auto-scale the height to match the width.
|
||||
* @param {Object} [options]
|
||||
|
||||
@@ -1,8 +1,31 @@
|
||||
'use strict';
|
||||
|
||||
const events = require('events');
|
||||
const is = require('./is');
|
||||
const sharp = require('../build/Release/sharp.node');
|
||||
|
||||
/**
|
||||
* An Object containing nested boolean values representing the available input and output formats/methods.
|
||||
* @member
|
||||
* @example
|
||||
* console.log(sharp.format);
|
||||
* @returns {Object}
|
||||
*/
|
||||
const format = sharp.format();
|
||||
|
||||
/**
|
||||
* An Object containing the version numbers of libvips and its dependencies.
|
||||
* @member
|
||||
* @example
|
||||
* console.log(sharp.versions);
|
||||
*/
|
||||
let versions = {
|
||||
vips: sharp.libvipsVersion()
|
||||
};
|
||||
try {
|
||||
versions = require('../vendor/versions.json');
|
||||
} catch (err) {}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -61,6 +84,18 @@ function concurrency (concurrency) {
|
||||
return sharp.concurrency(is.integer(concurrency) ? concurrency : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -110,4 +145,7 @@ module.exports = function (Sharp) {
|
||||
].forEach(function (f) {
|
||||
Sharp[f.name] = f;
|
||||
});
|
||||
Sharp.format = format;
|
||||
Sharp.versions = versions;
|
||||
Sharp.queue = queue;
|
||||
};
|
||||
|
||||
27
mkdocs.yml
27
mkdocs.yml
@@ -1,27 +0,0 @@
|
||||
site_name: sharp
|
||||
site_url: https://sharp.pixelplumbing.com/
|
||||
repo_url: https://github.com/lovell/sharp
|
||||
site_description: High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP and TIFF images
|
||||
copyright: <a href="https://pixelplumbing.com/">pixelplumbing.com</a>
|
||||
google_analytics: ['UA-13034748-12', 'sharp.pixelplumbing.com']
|
||||
theme: readthedocs
|
||||
extra_css:
|
||||
- css/extra.css
|
||||
markdown_extensions:
|
||||
- toc:
|
||||
permalink: True
|
||||
pages:
|
||||
- Home: index.md
|
||||
- Installation: install.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
|
||||
- Changelog: changelog.md
|
||||
25
package.json
25
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "sharp",
|
||||
"description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP and TIFF images",
|
||||
"version": "0.23.3",
|
||||
"version": "0.24.0",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://github.com/lovell/sharp",
|
||||
"contributors": [
|
||||
@@ -64,7 +64,8 @@
|
||||
"Ilya Ovdin <iovdin@gmail.com>",
|
||||
"Andargor <andargor@yahoo.com>",
|
||||
"Paul Neave <paul.neave@gmail.com>",
|
||||
"Brendan Kennedy <brenwken@gmail.com>"
|
||||
"Brendan Kennedy <brenwken@gmail.com>",
|
||||
"Brychan Bennett-Odlum <git@brychan.io>"
|
||||
],
|
||||
"scripts": {
|
||||
"install": "(node install/libvips && node install/dll-copy && prebuild-install) || (node-gyp rebuild && node install/dll-copy)",
|
||||
@@ -74,13 +75,13 @@
|
||||
"test-licensing": "license-checker --production --summary --onlyAllow=\"Apache-2.0;BSD;ISC;MIT\"",
|
||||
"test-coverage": "./test/coverage/report.sh",
|
||||
"test-leak": "./test/leak/leak.sh",
|
||||
"docs": "for m in constructor input resize composite operation colour channel output utility; do documentation build --shallow --format=md --markdown-toc=false lib/$m.js >docs/api-$m.md; done"
|
||||
"docs-build": "for m in constructor input resize composite operation colour channel output utility; do documentation build --shallow --format=md --markdown-toc=false lib/$m.js >docs/api-$m.md; done",
|
||||
"docs-serve": "cd docs && npx serve",
|
||||
"docs-publish": "cd docs && npx firebase-tools deploy --project pixelplumbing --only hosting:pixelplumbing-sharp"
|
||||
},
|
||||
"main": "lib/index.js",
|
||||
"files": [
|
||||
"binding.gyp",
|
||||
"docs/**",
|
||||
"!docs/css/**",
|
||||
"install/**",
|
||||
"lib/**",
|
||||
"src/**"
|
||||
@@ -111,7 +112,7 @@
|
||||
"nan": "^2.14.0",
|
||||
"npmlog": "^4.1.2",
|
||||
"prebuild-install": "^5.3.3",
|
||||
"semver": "^6.3.0",
|
||||
"semver": "^7.1.1",
|
||||
"simple-get": "^3.1.0",
|
||||
"tar": "^5.0.5",
|
||||
"tunnel-agent": "^0.6.0"
|
||||
@@ -124,20 +125,20 @@
|
||||
"exif-reader": "^1.0.3",
|
||||
"icc": "^1.0.0",
|
||||
"license-checker": "^25.0.1",
|
||||
"mocha": "^6.2.2",
|
||||
"mock-fs": "^4.10.3",
|
||||
"nyc": "^14.1.1",
|
||||
"prebuild": "^9.1.1",
|
||||
"mocha": "^7.0.0",
|
||||
"mock-fs": "^4.10.4",
|
||||
"nyc": "^15.0.0",
|
||||
"prebuild": "^10.0.0",
|
||||
"prebuild-ci": "^3.1.0",
|
||||
"rimraf": "^3.0.0",
|
||||
"semistandard": "^14.2.0"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"config": {
|
||||
"libvips": "8.8.1"
|
||||
"libvips": "8.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.5.0"
|
||||
"node": ">=10.13.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019 Lovell Fuller and contributors.
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Lovell Fuller and contributors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -58,6 +58,7 @@ namespace sharp {
|
||||
v8::Local<v8::Object> buffer = AttrAs<v8::Object>(input, "buffer");
|
||||
descriptor->bufferLength = node::Buffer::Length(buffer);
|
||||
descriptor->buffer = node::Buffer::Data(buffer);
|
||||
descriptor->isBuffer = TRUE;
|
||||
buffersToPersist.push_back(buffer);
|
||||
}
|
||||
descriptor->failOnError = AttrTo<bool>(input, "failOnError");
|
||||
@@ -85,6 +86,10 @@ namespace sharp {
|
||||
descriptor->createHeight = AttrTo<uint32_t>(input, "createHeight");
|
||||
descriptor->createBackground = AttrAsRgba(input, "createBackground");
|
||||
}
|
||||
// Limit input images to a given number of pixels, where pixels = width * height
|
||||
descriptor->limitInputPixels = AttrTo<uint32_t>(input, "limitInputPixels");
|
||||
// Allow switch from random to sequential access
|
||||
descriptor->access = AttrTo<bool>(input, "sequentialRead") ? VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
@@ -196,7 +201,7 @@ namespace sharp {
|
||||
std::string const loader = load;
|
||||
if (EndsWith(loader, "JpegFile")) {
|
||||
imageType = ImageType::JPEG;
|
||||
} else if (EndsWith(loader, "Png")) {
|
||||
} else if (EndsWith(loader, "PngFile")) {
|
||||
imageType = ImageType::PNG;
|
||||
} else if (EndsWith(loader, "WebpFile")) {
|
||||
imageType = ImageType::WEBP;
|
||||
@@ -243,10 +248,10 @@ namespace sharp {
|
||||
/*
|
||||
Open an image from the given InputDescriptor (filesystem, compressed buffer, raw pixel data)
|
||||
*/
|
||||
std::tuple<VImage, ImageType> OpenInput(InputDescriptor *descriptor, VipsAccess accessMethod) {
|
||||
std::tuple<VImage, ImageType> OpenInput(InputDescriptor *descriptor) {
|
||||
VImage image;
|
||||
ImageType imageType;
|
||||
if (descriptor->buffer != nullptr) {
|
||||
if (descriptor->isBuffer) {
|
||||
if (descriptor->rawChannels > 0) {
|
||||
// Raw, uncompressed pixel data
|
||||
image = VImage::new_from_memory(descriptor->buffer, descriptor->bufferLength,
|
||||
@@ -263,7 +268,7 @@ namespace sharp {
|
||||
if (imageType != ImageType::UNKNOWN) {
|
||||
try {
|
||||
vips::VOption *option = VImage::option()
|
||||
->set("access", accessMethod)
|
||||
->set("access", descriptor->access)
|
||||
->set("fail", descriptor->failOnError);
|
||||
if (imageType == ImageType::SVG || imageType == ImageType::PDF) {
|
||||
option->set("dpi", descriptor->density);
|
||||
@@ -277,7 +282,7 @@ namespace sharp {
|
||||
}
|
||||
image = VImage::new_from_buffer(descriptor->buffer, descriptor->bufferLength, nullptr, option);
|
||||
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
||||
SetDensity(image, descriptor->density);
|
||||
image = SetDensity(image, descriptor->density);
|
||||
}
|
||||
} catch (vips::VError const &err) {
|
||||
throw vips::VError(std::string("Input buffer has corrupt header: ") + err.what());
|
||||
@@ -309,7 +314,7 @@ namespace sharp {
|
||||
if (imageType != ImageType::UNKNOWN) {
|
||||
try {
|
||||
vips::VOption *option = VImage::option()
|
||||
->set("access", accessMethod)
|
||||
->set("access", descriptor->access)
|
||||
->set("fail", descriptor->failOnError);
|
||||
if (imageType == ImageType::SVG || imageType == ImageType::PDF) {
|
||||
option->set("dpi", descriptor->density);
|
||||
@@ -323,7 +328,7 @@ namespace sharp {
|
||||
}
|
||||
image = VImage::new_from_file(descriptor->file.data(), option);
|
||||
if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) {
|
||||
SetDensity(image, descriptor->density);
|
||||
image = SetDensity(image, descriptor->density);
|
||||
}
|
||||
} catch (vips::VError const &err) {
|
||||
throw vips::VError(std::string("Input file has corrupt header: ") + err.what());
|
||||
@@ -333,6 +338,11 @@ namespace sharp {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Limit input images to a given number of pixels, where pixels = width * height
|
||||
if (descriptor->limitInputPixels > 0 &&
|
||||
static_cast<uint64_t>(image.width() * image.height()) > static_cast<uint64_t>(descriptor->limitInputPixels)) {
|
||||
throw vips::VError("Input image exceeds pixel limit");
|
||||
}
|
||||
return std::make_tuple(image, imageType);
|
||||
}
|
||||
|
||||
@@ -370,15 +380,19 @@ namespace sharp {
|
||||
/*
|
||||
Set EXIF Orientation of image.
|
||||
*/
|
||||
void SetExifOrientation(VImage image, int const orientation) {
|
||||
image.set(VIPS_META_ORIENTATION, orientation);
|
||||
VImage SetExifOrientation(VImage image, int const orientation) {
|
||||
VImage copy = image.copy();
|
||||
copy.set(VIPS_META_ORIENTATION, orientation);
|
||||
return copy;
|
||||
}
|
||||
|
||||
/*
|
||||
Remove EXIF Orientation from image.
|
||||
*/
|
||||
void RemoveExifOrientation(VImage image) {
|
||||
vips_image_remove(image.get_image(), VIPS_META_ORIENTATION);
|
||||
VImage RemoveExifOrientation(VImage image) {
|
||||
VImage copy = image.copy();
|
||||
copy.remove(VIPS_META_ORIENTATION);
|
||||
return copy;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -398,11 +412,13 @@ namespace sharp {
|
||||
/*
|
||||
Set pixels/mm resolution based on a pixels/inch density.
|
||||
*/
|
||||
void SetDensity(VImage image, const double density) {
|
||||
VImage SetDensity(VImage image, const double density) {
|
||||
const double pixelsPerMm = density / 25.4;
|
||||
image.set("Xres", pixelsPerMm);
|
||||
image.set("Yres", pixelsPerMm);
|
||||
image.set(VIPS_META_RESOLUTION_UNIT, "in");
|
||||
VImage copy = image.copy();
|
||||
copy.set("Xres", pixelsPerMm);
|
||||
copy.set("Yres", pixelsPerMm);
|
||||
copy.set(VIPS_META_RESOLUTION_UNIT, "in");
|
||||
return copy;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
24
src/common.h
24
src/common.h
@@ -1,4 +1,4 @@
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019 Lovell Fuller and contributors.
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Lovell Fuller and contributors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -25,17 +25,17 @@
|
||||
|
||||
// Verify platform and compiler compatibility
|
||||
|
||||
#if (VIPS_MAJOR_VERSION < 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 8))
|
||||
#error libvips version 8.8.0+ is required - see sharp.pixelplumbing.com/page/install
|
||||
#if (VIPS_MAJOR_VERSION < 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 9))
|
||||
#error "libvips version 8.9.0+ is required - please see https://sharp.pixelplumbing.com/install"
|
||||
#endif
|
||||
|
||||
#if ((!defined(__clang__)) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)))
|
||||
#error GCC version 4.6+ is required for C++11 features - see sharp.pixelplumbing.com/page/install#prerequisites
|
||||
#error "GCC version 4.6+ is required for C++11 features - please see https://sharp.pixelplumbing.com/install"
|
||||
#endif
|
||||
|
||||
#if (defined(__clang__) && defined(__has_feature))
|
||||
#if (!__has_feature(cxx_range_for))
|
||||
#error clang version 3.0+ is required for C++11 features - see sharp.pixelplumbing.com/page/install#prerequisites
|
||||
#error "clang version 3.0+ is required for C++11 features - please see https://sharp.pixelplumbing.com/install"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -48,7 +48,10 @@ namespace sharp {
|
||||
std::string file;
|
||||
char *buffer;
|
||||
bool failOnError;
|
||||
int limitInputPixels;
|
||||
VipsAccess access;
|
||||
size_t bufferLength;
|
||||
bool isBuffer;
|
||||
double density;
|
||||
int rawChannels;
|
||||
int rawWidth;
|
||||
@@ -63,7 +66,10 @@ namespace sharp {
|
||||
InputDescriptor():
|
||||
buffer(nullptr),
|
||||
failOnError(TRUE),
|
||||
limitInputPixels(0x3FFF * 0x3FFF),
|
||||
access(VIPS_ACCESS_RANDOM),
|
||||
bufferLength(0),
|
||||
isBuffer(FALSE),
|
||||
density(72.0),
|
||||
rawChannels(0),
|
||||
rawWidth(0),
|
||||
@@ -154,7 +160,7 @@ namespace sharp {
|
||||
/*
|
||||
Open an image from the given InputDescriptor (filesystem, compressed buffer, raw pixel data)
|
||||
*/
|
||||
std::tuple<VImage, ImageType> OpenInput(InputDescriptor *descriptor, VipsAccess accessMethod);
|
||||
std::tuple<VImage, ImageType> OpenInput(InputDescriptor *descriptor);
|
||||
|
||||
/*
|
||||
Does this image have an embedded profile?
|
||||
@@ -175,12 +181,12 @@ namespace sharp {
|
||||
/*
|
||||
Set EXIF Orientation of image.
|
||||
*/
|
||||
void SetExifOrientation(VImage image, int const orientation);
|
||||
VImage SetExifOrientation(VImage image, int const orientation);
|
||||
|
||||
/*
|
||||
Remove EXIF Orientation from image.
|
||||
*/
|
||||
void RemoveExifOrientation(VImage image);
|
||||
VImage RemoveExifOrientation(VImage image);
|
||||
|
||||
/*
|
||||
Does this image have a non-default density?
|
||||
@@ -195,7 +201,7 @@ namespace sharp {
|
||||
/*
|
||||
Set pixels/mm resolution based on a pixels/inch density.
|
||||
*/
|
||||
void SetDensity(VImage image, const double density);
|
||||
VImage SetDensity(VImage image, const double density);
|
||||
|
||||
/*
|
||||
Check the proposed format supports the current dimensions.
|
||||
|
||||
178
src/libvips/cplusplus/VConnection.cpp
Normal file
178
src/libvips/cplusplus/VConnection.cpp
Normal file
@@ -0,0 +1,178 @@
|
||||
/* Object part of the VSource and VTarget class
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Copyright (C) 1991-2001 The National Gallery
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
|
||||
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif /*HAVE_CONFIG_H*/
|
||||
#include <vips/intl.h>
|
||||
|
||||
#include <vips/vips8>
|
||||
|
||||
#include <vips/debug.h>
|
||||
|
||||
/*
|
||||
#define VIPS_DEBUG
|
||||
#define VIPS_DEBUG_VERBOSE
|
||||
*/
|
||||
|
||||
VIPS_NAMESPACE_START
|
||||
|
||||
VSource
|
||||
VSource::new_from_descriptor( int descriptor )
|
||||
{
|
||||
VipsSource *input;
|
||||
|
||||
if( !(input = vips_source_new_from_descriptor( descriptor )) )
|
||||
throw VError();
|
||||
|
||||
VSource out( input );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VSource
|
||||
VSource::new_from_file( const char *filename )
|
||||
{
|
||||
VipsSource *input;
|
||||
|
||||
if( !(input = vips_source_new_from_file( filename )) )
|
||||
throw VError();
|
||||
|
||||
VSource out( input );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VSource
|
||||
VSource::new_from_blob( VipsBlob *blob )
|
||||
{
|
||||
VipsSource *input;
|
||||
|
||||
if( !(input = vips_source_new_from_blob( blob )) )
|
||||
throw VError();
|
||||
|
||||
VSource out( input );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VSource
|
||||
VSource::new_from_memory( const void *data,
|
||||
size_t size )
|
||||
{
|
||||
VipsSource *input;
|
||||
|
||||
if( !(input = vips_source_new_from_memory( data, size )) )
|
||||
throw VError();
|
||||
|
||||
VSource out( input );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VSource
|
||||
VSource::new_from_options( const char *options )
|
||||
{
|
||||
VipsSource *input;
|
||||
|
||||
if( !(input = vips_source_new_from_options( options )) )
|
||||
throw VError();
|
||||
|
||||
VSource out( input );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VOption *
|
||||
VOption::set( const char *name, const VSource value )
|
||||
{
|
||||
Pair *pair = new Pair( name );
|
||||
|
||||
pair->input = true;
|
||||
g_value_init( &pair->value, VIPS_TYPE_SOURCE );
|
||||
g_value_set_object( &pair->value, value.get_source() );
|
||||
options.push_back( pair );
|
||||
|
||||
return( this );
|
||||
}
|
||||
|
||||
VTarget
|
||||
VTarget::new_to_descriptor( int descriptor )
|
||||
{
|
||||
VipsTarget *output;
|
||||
|
||||
if( !(output = vips_target_new_to_descriptor( descriptor )) )
|
||||
throw VError();
|
||||
|
||||
VTarget out( output );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VTarget
|
||||
VTarget::new_to_file( const char *filename )
|
||||
{
|
||||
VipsTarget *output;
|
||||
|
||||
if( !(output = vips_target_new_to_file( filename )) )
|
||||
throw VError();
|
||||
|
||||
VTarget out( output );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VTarget
|
||||
VTarget::new_to_memory()
|
||||
{
|
||||
VipsTarget *output;
|
||||
|
||||
if( !(output = vips_target_new_to_memory()) )
|
||||
throw VError();
|
||||
|
||||
VTarget out( output );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VOption *
|
||||
VOption::set( const char *name, const VTarget value )
|
||||
{
|
||||
Pair *pair = new Pair( name );
|
||||
|
||||
pair->input = true;
|
||||
g_value_init( &pair->value, VIPS_TYPE_TARGET );
|
||||
g_value_set_object( &pair->value, value.get_target() );
|
||||
options.push_back( pair );
|
||||
|
||||
return( this );
|
||||
}
|
||||
|
||||
VIPS_NAMESPACE_END
|
||||
@@ -169,7 +169,7 @@ VOption::set( const char *name, const char *value )
|
||||
|
||||
// input image
|
||||
VOption *
|
||||
VOption::set( const char *name, VImage value )
|
||||
VOption::set( const char *name, const VImage value )
|
||||
{
|
||||
Pair *pair = new Pair( name );
|
||||
|
||||
@@ -592,7 +592,30 @@ VImage
|
||||
VImage::new_from_buffer( const std::string &buf, const char *option_string,
|
||||
VOption *options )
|
||||
{
|
||||
return( new_from_buffer( buf.c_str(), buf.size(), option_string, options ) );
|
||||
return( new_from_buffer( buf.c_str(), buf.size(),
|
||||
option_string, options ) );
|
||||
}
|
||||
|
||||
VImage
|
||||
VImage::new_from_source( VSource source, const char *option_string,
|
||||
VOption *options )
|
||||
{
|
||||
const char *operation_name;
|
||||
VImage out;
|
||||
|
||||
if( !(operation_name = vips_foreign_find_load_source(
|
||||
source.get_source() )) ) {
|
||||
delete options;
|
||||
throw( VError() );
|
||||
}
|
||||
|
||||
options = (options ? options : VImage::option())->
|
||||
set( "source", source )->
|
||||
set( "out", &out );
|
||||
|
||||
call_option_string( operation_name, option_string, options );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage
|
||||
@@ -679,6 +702,26 @@ VImage::write_to_buffer( const char *suffix, void **buf, size_t *size,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VImage::write_to_target( const char *suffix, VTarget target,
|
||||
VOption *options ) const
|
||||
{
|
||||
char filename[VIPS_PATH_MAX];
|
||||
char option_string[VIPS_PATH_MAX];
|
||||
const char *operation_name;
|
||||
|
||||
vips__filename_split8( suffix, filename, option_string );
|
||||
if( !(operation_name = vips_foreign_find_save_target( filename )) ) {
|
||||
delete options;
|
||||
throw VError();
|
||||
}
|
||||
|
||||
call_option_string( operation_name, option_string,
|
||||
(options ? options : VImage::option())->
|
||||
set( "in", *this )->
|
||||
set( "target", target ) );
|
||||
}
|
||||
|
||||
#include "vips-operators.cpp"
|
||||
|
||||
std::vector<VImage>
|
||||
|
||||
@@ -61,7 +61,7 @@ VInterpolate::new_from_name( const char *name, VOption *options )
|
||||
}
|
||||
|
||||
VOption *
|
||||
VOption::set( const char *name, VInterpolate value )
|
||||
VOption::set( const char *name, const VInterpolate value )
|
||||
{
|
||||
Pair *pair = new Pair( name );
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// bodies for vips operations
|
||||
// Wed Apr 24 15:50:21 CEST 2019
|
||||
// Wed 01 Jan 2020 12:22:12 PM CET
|
||||
// this file is generated automatically, do not edit!
|
||||
|
||||
VImage VImage::CMC2LCh( VOption *options ) const
|
||||
@@ -491,6 +491,19 @@ VImage VImage::canny( VOption *options ) const
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage VImage::case_image( std::vector<VImage> cases, VOption *options ) const
|
||||
{
|
||||
VImage out;
|
||||
|
||||
call( "case",
|
||||
(options ? options : VImage::option())->
|
||||
set( "index", *this )->
|
||||
set( "out", &out )->
|
||||
set( "cases", cases ) );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage VImage::cast( VipsBandFormat format, VOption *options ) const
|
||||
{
|
||||
VImage out;
|
||||
@@ -1615,6 +1628,18 @@ VImage VImage::jpegload_buffer( VipsBlob *buffer, VOption *options )
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage VImage::jpegload_source( VSource source, VOption *options )
|
||||
{
|
||||
VImage out;
|
||||
|
||||
call( "jpegload_source",
|
||||
(options ? options : VImage::option())->
|
||||
set( "out", &out )->
|
||||
set( "source", source ) );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
void VImage::jpegsave( const char *filename, VOption *options ) const
|
||||
{
|
||||
call( "jpegsave",
|
||||
@@ -1642,6 +1667,14 @@ void VImage::jpegsave_mime( VOption *options ) const
|
||||
set( "in", *this ) );
|
||||
}
|
||||
|
||||
void VImage::jpegsave_target( VTarget target, VOption *options ) const
|
||||
{
|
||||
call( "jpegsave_target",
|
||||
(options ? options : VImage::option())->
|
||||
set( "in", *this )->
|
||||
set( "target", target ) );
|
||||
}
|
||||
|
||||
VImage VImage::labelregions( VOption *options ) const
|
||||
{
|
||||
VImage mask;
|
||||
@@ -2286,6 +2319,18 @@ VImage VImage::pngload_buffer( VipsBlob *buffer, VOption *options )
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage VImage::pngload_source( VSource source, VOption *options )
|
||||
{
|
||||
VImage out;
|
||||
|
||||
call( "pngload_source",
|
||||
(options ? options : VImage::option())->
|
||||
set( "out", &out )->
|
||||
set( "source", source ) );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
void VImage::pngsave( const char *filename, VOption *options ) const
|
||||
{
|
||||
call( "pngsave",
|
||||
@@ -2306,6 +2351,14 @@ VipsBlob *VImage::pngsave_buffer( VOption *options ) const
|
||||
return( buffer );
|
||||
}
|
||||
|
||||
void VImage::pngsave_target( VTarget target, VOption *options ) const
|
||||
{
|
||||
call( "pngsave_target",
|
||||
(options ? options : VImage::option())->
|
||||
set( "in", *this )->
|
||||
set( "target", target ) );
|
||||
}
|
||||
|
||||
VImage VImage::ppmload( const char *filename, VOption *options )
|
||||
{
|
||||
VImage out;
|
||||
@@ -2413,6 +2466,30 @@ VImage VImage::radload( const char *filename, VOption *options )
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage VImage::radload_buffer( VipsBlob *buffer, VOption *options )
|
||||
{
|
||||
VImage out;
|
||||
|
||||
call( "radload_buffer",
|
||||
(options ? options : VImage::option())->
|
||||
set( "out", &out )->
|
||||
set( "buffer", buffer ) );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage VImage::radload_source( VSource source, VOption *options )
|
||||
{
|
||||
VImage out;
|
||||
|
||||
call( "radload_source",
|
||||
(options ? options : VImage::option())->
|
||||
set( "out", &out )->
|
||||
set( "source", source ) );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
void VImage::radsave( const char *filename, VOption *options ) const
|
||||
{
|
||||
call( "radsave",
|
||||
@@ -2433,6 +2510,14 @@ VipsBlob *VImage::radsave_buffer( VOption *options ) const
|
||||
return( buffer );
|
||||
}
|
||||
|
||||
void VImage::radsave_target( VTarget target, VOption *options ) const
|
||||
{
|
||||
call( "radsave_target",
|
||||
(options ? options : VImage::option())->
|
||||
set( "in", *this )->
|
||||
set( "target", target ) );
|
||||
}
|
||||
|
||||
VImage VImage::rank( int width, int height, int index, VOption *options ) const
|
||||
{
|
||||
VImage out;
|
||||
@@ -2977,6 +3062,30 @@ VImage VImage::svgload_buffer( VipsBlob *buffer, VOption *options )
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage VImage::svgload_source( VSource source, VOption *options )
|
||||
{
|
||||
VImage out;
|
||||
|
||||
call( "svgload_source",
|
||||
(options ? options : VImage::option())->
|
||||
set( "out", &out )->
|
||||
set( "source", source ) );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage VImage::switch_image( std::vector<VImage> tests, VOption *options )
|
||||
{
|
||||
VImage out;
|
||||
|
||||
call( "switch",
|
||||
(options ? options : VImage::option())->
|
||||
set( "out", &out )->
|
||||
set( "tests", tests ) );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
void VImage::system( const char *cmd_format, VOption *options )
|
||||
{
|
||||
call( "system",
|
||||
@@ -3035,6 +3144,19 @@ VImage VImage::thumbnail_image( int width, VOption *options ) const
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage VImage::thumbnail_source( VSource source, int width, VOption *options )
|
||||
{
|
||||
VImage out;
|
||||
|
||||
call( "thumbnail_source",
|
||||
(options ? options : VImage::option())->
|
||||
set( "out", &out )->
|
||||
set( "source", source )->
|
||||
set( "width", width ) );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage VImage::tiffload( const char *filename, VOption *options )
|
||||
{
|
||||
VImage out;
|
||||
@@ -3059,6 +3181,18 @@ VImage VImage::tiffload_buffer( VipsBlob *buffer, VOption *options )
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage VImage::tiffload_source( VSource source, VOption *options )
|
||||
{
|
||||
VImage out;
|
||||
|
||||
call( "tiffload_source",
|
||||
(options ? options : VImage::option())->
|
||||
set( "out", &out )->
|
||||
set( "source", source ) );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
void VImage::tiffsave( const char *filename, VOption *options ) const
|
||||
{
|
||||
call( "tiffsave",
|
||||
@@ -3170,6 +3304,18 @@ VImage VImage::webpload_buffer( VipsBlob *buffer, VOption *options )
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage VImage::webpload_source( VSource source, VOption *options )
|
||||
{
|
||||
VImage out;
|
||||
|
||||
call( "webpload_source",
|
||||
(options ? options : VImage::option())->
|
||||
set( "out", &out )->
|
||||
set( "source", source ) );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
void VImage::webpsave( const char *filename, VOption *options ) const
|
||||
{
|
||||
call( "webpsave",
|
||||
@@ -3190,6 +3336,14 @@ VipsBlob *VImage::webpsave_buffer( VOption *options ) const
|
||||
return( buffer );
|
||||
}
|
||||
|
||||
void VImage::webpsave_target( VTarget target, VOption *options ) const
|
||||
{
|
||||
call( "webpsave_target",
|
||||
(options ? options : VImage::option())->
|
||||
set( "in", *this )->
|
||||
set( "target", target ) );
|
||||
}
|
||||
|
||||
VImage VImage::worley( int width, int height, VOption *options )
|
||||
{
|
||||
VImage out;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019 Lovell Fuller and contributors.
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Lovell Fuller and contributors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -46,7 +46,7 @@ class MetadataWorker : public Nan::AsyncWorker {
|
||||
vips::VImage image;
|
||||
sharp::ImageType imageType = sharp::ImageType::UNKNOWN;
|
||||
try {
|
||||
std::tie(image, imageType) = OpenInput(baton->input, VIPS_ACCESS_SEQUENTIAL);
|
||||
std::tie(image, imageType) = OpenInput(baton->input);
|
||||
} catch (vips::VError const &err) {
|
||||
(baton->err).append(err.what());
|
||||
}
|
||||
@@ -77,6 +77,12 @@ class MetadataWorker : public Nan::AsyncWorker {
|
||||
if (image.get_typeof(VIPS_META_PAGE_HEIGHT) == G_TYPE_INT) {
|
||||
baton->pageHeight = image.get_int(VIPS_META_PAGE_HEIGHT);
|
||||
}
|
||||
if (image.get_typeof("loop") == G_TYPE_INT) {
|
||||
baton->loop = image.get_int("loop");
|
||||
}
|
||||
if (image.get_typeof("delay") == VIPS_TYPE_ARRAY_INT) {
|
||||
baton->delay = image.get_array_int("delay");
|
||||
}
|
||||
if (image.get_typeof("heif-primary") == G_TYPE_INT) {
|
||||
baton->pagePrimary = image.get_int("heif-primary");
|
||||
}
|
||||
@@ -116,6 +122,14 @@ class MetadataWorker : public Nan::AsyncWorker {
|
||||
memcpy(baton->xmp, xmp, xmpLength);
|
||||
baton->xmpLength = xmpLength;
|
||||
}
|
||||
// TIFFTAG_PHOTOSHOP
|
||||
if (image.get_typeof(VIPS_META_PHOTOSHOP_NAME) == VIPS_TYPE_BLOB) {
|
||||
size_t tifftagPhotoshopLength;
|
||||
void const *tifftagPhotoshop = image.get_blob(VIPS_META_PHOTOSHOP_NAME, &tifftagPhotoshopLength);
|
||||
baton->tifftagPhotoshop = static_cast<char *>(g_malloc(tifftagPhotoshopLength));
|
||||
memcpy(baton->tifftagPhotoshop, tifftagPhotoshop, tifftagPhotoshopLength);
|
||||
baton->tifftagPhotoshopLength = tifftagPhotoshopLength;
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up
|
||||
@@ -161,6 +175,17 @@ class MetadataWorker : public Nan::AsyncWorker {
|
||||
if (baton->pageHeight > 0) {
|
||||
Set(info, New("pageHeight").ToLocalChecked(), New<v8::Uint32>(baton->pageHeight));
|
||||
}
|
||||
if (baton->loop >= 0) {
|
||||
Set(info, New("loop").ToLocalChecked(), New<v8::Uint32>(baton->loop));
|
||||
}
|
||||
if (!baton->delay.empty()) {
|
||||
int i = 0;
|
||||
v8::Local<v8::Array> delay = New<v8::Array>(baton->delay.size());
|
||||
for (int const d : baton->delay) {
|
||||
Set(delay, i++, New<v8::Number>(d));
|
||||
}
|
||||
Set(info, New("delay").ToLocalChecked(), delay);
|
||||
}
|
||||
if (baton->pagePrimary > -1) {
|
||||
Set(info, New("pagePrimary").ToLocalChecked(), New<v8::Uint32>(baton->pagePrimary));
|
||||
}
|
||||
@@ -189,6 +214,12 @@ class MetadataWorker : public Nan::AsyncWorker {
|
||||
New("xmp").ToLocalChecked(),
|
||||
Nan::NewBuffer(baton->xmp, baton->xmpLength, sharp::FreeCallback, nullptr).ToLocalChecked());
|
||||
}
|
||||
if (baton->tifftagPhotoshopLength > 0) {
|
||||
Set(info,
|
||||
New("tifftagPhotoshop").ToLocalChecked(),
|
||||
Nan::NewBuffer(baton->tifftagPhotoshop, baton->tifftagPhotoshopLength, sharp::FreeCallback, nullptr)
|
||||
.ToLocalChecked());
|
||||
}
|
||||
argv[1] = info;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019 Lovell Fuller and contributors.
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Lovell Fuller and contributors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -36,6 +36,8 @@ struct MetadataBaton {
|
||||
int paletteBitDepth;
|
||||
int pages;
|
||||
int pageHeight;
|
||||
int loop;
|
||||
std::vector<int> delay;
|
||||
int pagePrimary;
|
||||
bool hasProfile;
|
||||
bool hasAlpha;
|
||||
@@ -48,6 +50,8 @@ struct MetadataBaton {
|
||||
size_t iptcLength;
|
||||
char *xmp;
|
||||
size_t xmpLength;
|
||||
char *tifftagPhotoshop;
|
||||
size_t tifftagPhotoshopLength;
|
||||
std::string err;
|
||||
|
||||
MetadataBaton():
|
||||
@@ -60,6 +64,7 @@ struct MetadataBaton {
|
||||
paletteBitDepth(0),
|
||||
pages(0),
|
||||
pageHeight(0),
|
||||
loop(-1),
|
||||
pagePrimary(-1),
|
||||
hasProfile(false),
|
||||
hasAlpha(false),
|
||||
@@ -71,7 +76,9 @@ struct MetadataBaton {
|
||||
iptc(nullptr),
|
||||
iptcLength(0),
|
||||
xmp(nullptr),
|
||||
xmpLength(0) {}
|
||||
xmpLength(0),
|
||||
tifftagPhotoshop(nullptr),
|
||||
tifftagPhotoshopLength(0) {}
|
||||
};
|
||||
|
||||
NAN_METHOD(metadata);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019 Lovell Fuller and contributors.
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Lovell Fuller and contributors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019 Lovell Fuller and contributors.
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Lovell Fuller and contributors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
||||
115
src/pipeline.cc
115
src/pipeline.cc
@@ -1,4 +1,4 @@
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019 Lovell Fuller and contributors.
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Lovell Fuller and contributors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -77,15 +77,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
||||
// Open input
|
||||
vips::VImage image;
|
||||
ImageType inputImageType;
|
||||
std::tie(image, inputImageType) = sharp::OpenInput(baton->input, baton->accessMethod);
|
||||
|
||||
// Limit input images to a given number of pixels, where pixels = width * height
|
||||
// Ignore if 0
|
||||
if (baton->limitInputPixels > 0 &&
|
||||
static_cast<uint64_t>(image.width() * image.height()) > static_cast<uint64_t>(baton->limitInputPixels)) {
|
||||
(baton->err).append("Input image exceeds pixel limit");
|
||||
return Error();
|
||||
}
|
||||
std::tie(image, inputImageType) = sharp::OpenInput(baton->input);
|
||||
|
||||
// Calculate angle of rotation
|
||||
VipsAngle rotation;
|
||||
@@ -104,7 +96,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
||||
if (baton->rotateBeforePreExtract) {
|
||||
if (rotation != VIPS_ANGLE_D0) {
|
||||
image = image.rot(rotation);
|
||||
sharp::RemoveExifOrientation(image);
|
||||
image = sharp::RemoveExifOrientation(image);
|
||||
}
|
||||
if (baton->rotationAngle != 0.0) {
|
||||
std::vector<double> background;
|
||||
@@ -134,6 +126,17 @@ class PipelineWorker : public Nan::AsyncWorker {
|
||||
std::swap(inputWidth, inputHeight);
|
||||
}
|
||||
|
||||
// If withoutEnlargement is specified,
|
||||
// Override target width and height if exceeds respective value from input file
|
||||
if (baton->withoutEnlargement) {
|
||||
if (baton->width > inputWidth) {
|
||||
baton->width = inputWidth;
|
||||
}
|
||||
if (baton->height > inputHeight) {
|
||||
baton->height = inputHeight;
|
||||
}
|
||||
}
|
||||
|
||||
// Scaling calculations
|
||||
double xfactor = 1.0;
|
||||
double yfactor = 1.0;
|
||||
@@ -221,21 +224,6 @@ class PipelineWorker : public Nan::AsyncWorker {
|
||||
double xresidual = static_cast<double>(xshrink) / xfactor;
|
||||
double yresidual = static_cast<double>(yshrink) / yfactor;
|
||||
|
||||
// Do not enlarge the output if the input width *or* height
|
||||
// are already less than the required dimensions
|
||||
if (baton->withoutEnlargement) {
|
||||
if (inputWidth < baton->width || inputHeight < baton->height) {
|
||||
xfactor = 1.0;
|
||||
yfactor = 1.0;
|
||||
xshrink = 1;
|
||||
yshrink = 1;
|
||||
xresidual = 1.0;
|
||||
yresidual = 1.0;
|
||||
baton->width = inputWidth;
|
||||
baton->height = inputHeight;
|
||||
}
|
||||
}
|
||||
|
||||
// If integral x and y shrink are equal, try to use shrink-on-load for JPEG and WebP,
|
||||
// but not when applying gamma correction, pre-resize extract or trim
|
||||
int shrink_on_load = 1;
|
||||
@@ -274,7 +262,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
||||
if (shrink_on_load > 1) {
|
||||
// Reload input using shrink-on-load
|
||||
vips::VOption *option = VImage::option()
|
||||
->set("access", baton->accessMethod)
|
||||
->set("access", baton->input->access)
|
||||
->set("shrink", shrink_on_load)
|
||||
->set("fail", baton->input->failOnError);
|
||||
if (baton->input->buffer != nullptr) {
|
||||
@@ -311,11 +299,16 @@ class PipelineWorker : public Nan::AsyncWorker {
|
||||
}
|
||||
|
||||
// Ensure we're using a device-independent colour space
|
||||
if (sharp::HasProfile(image) && image.interpretation() != VIPS_INTERPRETATION_LABS) {
|
||||
if (
|
||||
sharp::HasProfile(image) &&
|
||||
image.interpretation() != VIPS_INTERPRETATION_LABS &&
|
||||
image.interpretation() != VIPS_INTERPRETATION_GREY16
|
||||
) {
|
||||
// Convert to sRGB using embedded profile
|
||||
try {
|
||||
image = image.icc_transform("srgb", VImage::option()
|
||||
->set("embedded", TRUE)
|
||||
->set("depth", image.interpretation() == VIPS_INTERPRETATION_RGB16 ? 16 : 8)
|
||||
->set("intent", VIPS_INTENT_PERCEPTUAL));
|
||||
} catch(...) {
|
||||
// Ignore failure of embedded profile
|
||||
@@ -404,20 +397,20 @@ class PipelineWorker : public Nan::AsyncWorker {
|
||||
// Rotate post-extract 90-angle
|
||||
if (!baton->rotateBeforePreExtract && rotation != VIPS_ANGLE_D0) {
|
||||
image = image.rot(rotation);
|
||||
sharp::RemoveExifOrientation(image);
|
||||
image = sharp::RemoveExifOrientation(image);
|
||||
}
|
||||
|
||||
|
||||
// Flip (mirror about Y axis)
|
||||
if (baton->flip) {
|
||||
image = image.flip(VIPS_DIRECTION_VERTICAL);
|
||||
sharp::RemoveExifOrientation(image);
|
||||
image = sharp::RemoveExifOrientation(image);
|
||||
}
|
||||
|
||||
// Flop (mirror about X axis)
|
||||
if (baton->flop) {
|
||||
image = image.flip(VIPS_DIRECTION_HORIZONTAL);
|
||||
sharp::RemoveExifOrientation(image);
|
||||
image = sharp::RemoveExifOrientation(image);
|
||||
}
|
||||
|
||||
// Join additional color channels to the image
|
||||
@@ -426,7 +419,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
||||
ImageType joinImageType = ImageType::UNKNOWN;
|
||||
|
||||
for (unsigned int i = 0; i < baton->joinChannelIn.size(); i++) {
|
||||
std::tie(joinImage, joinImageType) = sharp::OpenInput(baton->joinChannelIn[i], baton->accessMethod);
|
||||
std::tie(joinImage, joinImageType) = sharp::OpenInput(baton->joinChannelIn[i]);
|
||||
image = image.bandjoin(joinImage);
|
||||
}
|
||||
image = image.copy(VImage::option()->set("interpretation", baton->colourspace));
|
||||
@@ -479,7 +472,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
||||
baton->height = image.height();
|
||||
}
|
||||
image = image.tilecache(VImage::option()
|
||||
->set("access", baton->accessMethod)
|
||||
->set("access", VIPS_ACCESS_RANDOM)
|
||||
->set("threaded", TRUE));
|
||||
image = image.smartcrop(baton->width, baton->height, VImage::option()
|
||||
->set("interesting", baton->position == 16 ? VIPS_INTERESTING_ENTROPY : VIPS_INTERESTING_ATTENTION));
|
||||
@@ -556,7 +549,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
||||
for (Composite *composite : baton->composite) {
|
||||
VImage compositeImage;
|
||||
ImageType compositeImageType = ImageType::UNKNOWN;
|
||||
std::tie(compositeImage, compositeImageType) = OpenInput(composite->input, baton->accessMethod);
|
||||
std::tie(compositeImage, compositeImageType) = OpenInput(composite->input);
|
||||
// Verify within current dimensions
|
||||
if (compositeImage.width() > image.width() || compositeImage.height() > image.height()) {
|
||||
throw vips::VError("Image to composite must have same dimensions or smaller");
|
||||
@@ -646,7 +639,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
||||
if (baton->boolean != nullptr) {
|
||||
VImage booleanImage;
|
||||
ImageType booleanImageType = ImageType::UNKNOWN;
|
||||
std::tie(booleanImage, booleanImageType) = sharp::OpenInput(baton->boolean, baton->accessMethod);
|
||||
std::tie(booleanImage, booleanImageType) = sharp::OpenInput(baton->boolean);
|
||||
image = sharp::Boolean(image, booleanImage, baton->booleanOp);
|
||||
}
|
||||
|
||||
@@ -700,7 +693,7 @@ class PipelineWorker : public Nan::AsyncWorker {
|
||||
|
||||
// Override EXIF Orientation tag
|
||||
if (baton->withMetadata && baton->withMetadataOrientation != -1) {
|
||||
sharp::SetExifOrientation(image, baton->withMetadataOrientation);
|
||||
image = sharp::SetExifOrientation(image, baton->withMetadataOrientation);
|
||||
}
|
||||
|
||||
// Number of channels used in output image
|
||||
@@ -912,11 +905,9 @@ class PipelineWorker : public Nan::AsyncWorker {
|
||||
} else if (baton->formatOut == "heif" || (mightMatchInput && isHeif) ||
|
||||
(willMatchInput && inputImageType == ImageType::HEIF)) {
|
||||
// Write HEIF to file
|
||||
#ifdef VIPS_TYPE_FOREIGN_HEIF_COMPRESSION
|
||||
if (sharp::IsAvif(baton->fileOut)) {
|
||||
baton->heifCompression = VIPS_FOREIGN_HEIF_COMPRESSION_AV1;
|
||||
}
|
||||
#endif
|
||||
image.heifsave(const_cast<char*>(baton->fileOut.data()), VImage::option()
|
||||
->set("strip", !baton->withMetadata)
|
||||
->set("Q", baton->heifQuality)
|
||||
@@ -962,29 +953,26 @@ class PipelineWorker : public Nan::AsyncWorker {
|
||||
};
|
||||
suffix = AssembleSuffixString(extname, options);
|
||||
}
|
||||
|
||||
// Remove alpha channel from tile background if image does not contain an alpha channel
|
||||
if (!HasAlpha(image)) {
|
||||
baton->tileBackground.pop_back();
|
||||
}
|
||||
// Write DZ to file
|
||||
vips::VOption *options = VImage::option()
|
||||
->set("strip", !baton->withMetadata)
|
||||
->set("tile_size", baton->tileSize)
|
||||
->set("overlap", baton->tileOverlap)
|
||||
->set("container", baton->tileContainer)
|
||||
->set("layout", baton->tileLayout)
|
||||
->set("suffix", const_cast<char*>(suffix.data()))
|
||||
->set("angle", CalculateAngleRotation(baton->tileAngle))
|
||||
->set("background", baton->tileBackground)
|
||||
->set("skip_blanks", baton->tileSkipBlanks);
|
||||
|
||||
->set("strip", !baton->withMetadata)
|
||||
->set("tile_size", baton->tileSize)
|
||||
->set("overlap", baton->tileOverlap)
|
||||
->set("container", baton->tileContainer)
|
||||
->set("layout", baton->tileLayout)
|
||||
->set("suffix", const_cast<char*>(suffix.data()))
|
||||
->set("angle", CalculateAngleRotation(baton->tileAngle))
|
||||
->set("background", baton->tileBackground)
|
||||
->set("skip_blanks", baton->tileSkipBlanks);
|
||||
// libvips chooses a default depth based on layout. Instead of replicating that logic here by
|
||||
// not passing anything - libvips will handle choice
|
||||
if (baton->tileDepth < VIPS_FOREIGN_DZ_DEPTH_LAST) {
|
||||
options->set("depth", baton->tileDepth);
|
||||
}
|
||||
|
||||
image.dzsave(const_cast<char*>(baton->fileOut.data()), options);
|
||||
baton->formatOut = "dz";
|
||||
} else if (baton->formatOut == "v" || (mightMatchInput && isV) ||
|
||||
@@ -1000,7 +988,12 @@ class PipelineWorker : public Nan::AsyncWorker {
|
||||
}
|
||||
}
|
||||
} catch (vips::VError const &err) {
|
||||
(baton->err).append(err.what());
|
||||
char const *what = err.what();
|
||||
if (what && what[0]) {
|
||||
(baton->err).append(what);
|
||||
} else {
|
||||
(baton->err).append("Unknown error");
|
||||
}
|
||||
}
|
||||
// Clean up libvips' per-request data and threads
|
||||
vips_error_clear();
|
||||
@@ -1193,10 +1186,6 @@ NAN_METHOD(pipeline) {
|
||||
|
||||
// Input
|
||||
baton->input = CreateInputDescriptor(AttrAs<v8::Object>(options, "input"), buffersToPersist);
|
||||
baton->accessMethod = AttrTo<bool>(options, "sequentialRead") ?
|
||||
VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
|
||||
// Limit input images to a given number of pixels, where pixels = width * height
|
||||
baton->limitInputPixels = AttrTo<int32_t>(options, "limitInputPixels");
|
||||
// Extract image options
|
||||
baton->topOffsetPre = AttrTo<int32_t>(options, "topOffsetPre");
|
||||
baton->leftOffsetPre = AttrTo<int32_t>(options, "leftOffsetPre");
|
||||
@@ -1373,11 +1362,9 @@ NAN_METHOD(pipeline) {
|
||||
AttrAsStr(options, "tiffPredictor").data()));
|
||||
baton->heifQuality = AttrTo<uint32_t>(options, "heifQuality");
|
||||
baton->heifLossless = AttrTo<bool>(options, "heifLossless");
|
||||
#ifdef VIPS_TYPE_FOREIGN_HEIF_COMPRESSION
|
||||
baton->heifCompression = static_cast<VipsForeignHeifCompression>(
|
||||
vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_HEIF_COMPRESSION,
|
||||
AttrAsStr(options, "heifCompression").data()));
|
||||
#endif
|
||||
// Tile output
|
||||
baton->tileSize = AttrTo<uint32_t>(options, "tileSize");
|
||||
baton->tileOverlap = AttrTo<uint32_t>(options, "tileOverlap");
|
||||
@@ -1410,11 +1397,17 @@ NAN_METHOD(pipeline) {
|
||||
// signal that we do not want to pass any value to dzSave
|
||||
baton->tileDepth = VIPS_FOREIGN_DZ_DEPTH_LAST;
|
||||
}
|
||||
|
||||
// Force random access for certain operations
|
||||
if (baton->accessMethod == VIPS_ACCESS_SEQUENTIAL && (
|
||||
baton->trimThreshold > 0.0 || baton->normalise ||
|
||||
baton->position == 16 || baton->position == 17)) {
|
||||
baton->accessMethod = VIPS_ACCESS_RANDOM;
|
||||
if (baton->input->access == VIPS_ACCESS_SEQUENTIAL) {
|
||||
if (
|
||||
baton->trimThreshold > 0.0 ||
|
||||
baton->normalise ||
|
||||
baton->position == 16 || baton->position == 17 ||
|
||||
baton->angle != 0 || baton->rotationAngle != 0.0
|
||||
) {
|
||||
baton->input->access = VIPS_ACCESS_RANDOM;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to notify of libvips warnings
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019 Lovell Fuller and contributors.
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Lovell Fuller and contributors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -55,7 +55,6 @@ struct Composite {
|
||||
|
||||
struct PipelineBaton {
|
||||
sharp::InputDescriptor *input;
|
||||
int limitInputPixels;
|
||||
std::string formatOut;
|
||||
std::string fileOut;
|
||||
void *bufferOut;
|
||||
@@ -119,7 +118,6 @@ struct PipelineBaton {
|
||||
int extendRight;
|
||||
std::vector<double> extendBackground;
|
||||
bool withoutEnlargement;
|
||||
VipsAccess accessMethod;
|
||||
int jpegQuality;
|
||||
bool jpegProgressive;
|
||||
std::string jpegChromaSubsampling;
|
||||
@@ -182,7 +180,6 @@ struct PipelineBaton {
|
||||
|
||||
PipelineBaton():
|
||||
input(nullptr),
|
||||
limitInputPixels(0),
|
||||
bufferOutLength(0),
|
||||
topOffsetPre(-1),
|
||||
topOffsetPost(-1),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019 Lovell Fuller and contributors.
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Lovell Fuller and contributors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019 Lovell Fuller and contributors.
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Lovell Fuller and contributors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -62,7 +62,7 @@ class StatsWorker : public Nan::AsyncWorker {
|
||||
sharp::ImageType imageType = sharp::ImageType::UNKNOWN;
|
||||
|
||||
try {
|
||||
std::tie(image, imageType) = OpenInput(baton->input, baton->accessMethod);
|
||||
std::tie(image, imageType) = OpenInput(baton->input);
|
||||
} catch (vips::VError const &err) {
|
||||
(baton->err).append(err.what());
|
||||
}
|
||||
@@ -178,7 +178,6 @@ NAN_METHOD(stats) {
|
||||
|
||||
// Input
|
||||
baton->input = sharp::CreateInputDescriptor(sharp::AttrAs<v8::Object>(options, "input"), buffersToPersist);
|
||||
baton->accessMethod = AttrTo<bool>(options, "sequentialRead") ? VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
|
||||
|
||||
// Function to notify of libvips warnings
|
||||
Nan::Callback *debuglog = new Nan::Callback(sharp::AttrAs<v8::Function>(options, "debuglog"));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019 Lovell Fuller and contributors.
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Lovell Fuller and contributors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -46,7 +46,6 @@ struct ChannelStats {
|
||||
struct StatsBaton {
|
||||
// Input
|
||||
sharp::InputDescriptor *input;
|
||||
VipsAccess accessMethod;
|
||||
|
||||
// Output
|
||||
std::vector<ChannelStats> channelStats;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019 Lovell Fuller and contributors.
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Lovell Fuller and contributors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019 Lovell Fuller and contributors.
|
||||
// Copyright 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Lovell Fuller and contributors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
"benchmark": "^2.1.4",
|
||||
"gm": "^1.23.1",
|
||||
"imagemagick": "^0.1.3",
|
||||
"jimp": "^0.8.4",
|
||||
"jimp": "^0.9.3",
|
||||
"mapnik": "^4.3.1",
|
||||
"semver": "^6.3.0"
|
||||
"semver": "^7.1.1"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
|
||||
@@ -460,8 +460,7 @@ async.series({
|
||||
}).add('sharp-sequentialRead', {
|
||||
defer: true,
|
||||
fn: function (deferred) {
|
||||
sharp(inputJpgBuffer)
|
||||
.sequentialRead()
|
||||
sharp(inputJpgBuffer, { sequentialRead: true })
|
||||
.resize(width, height)
|
||||
.toBuffer(function (err, buffer) {
|
||||
if (err) {
|
||||
|
||||
BIN
test/fixtures/16-bit-grey-alpha.png
vendored
Normal file
BIN
test/fixtures/16-bit-grey-alpha.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
BIN
test/fixtures/animated-loop-3.gif
vendored
Normal file
BIN
test/fixtures/animated-loop-3.gif
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.6 KiB |
BIN
test/fixtures/expected/16-bit-grey-alpha-identity.png
vendored
Normal file
BIN
test/fixtures/expected/16-bit-grey-alpha-identity.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.7 KiB |
3
test/fixtures/index.js
vendored
3
test/fixtures/index.js
vendored
@@ -79,6 +79,7 @@ module.exports = {
|
||||
inputPngWithGreyAlpha: getPath('grey-8bit-alpha.png'),
|
||||
inputPngWithOneColor: getPath('2x2_fdcce6.png'),
|
||||
inputPngWithTransparency16bit: getPath('tbgn2c16.png'), // http://www.schaik.com/pngsuite/tbgn2c16.png
|
||||
inputPng16BitGreyAlpha: getPath('16-bit-grey-alpha.png'), // CC-BY-NC-SA florc http://www.colourlovers.com/pattern/50713/pat
|
||||
inputPngOverlayLayer0: getPath('alpha-layer-0-background.png'),
|
||||
inputPngOverlayLayer1: getPath('alpha-layer-1-fill.png'),
|
||||
inputPngAlphaPremultiplicationSmall: getPath('alpha-premultiply-1024x768-paper.png'),
|
||||
@@ -97,9 +98,11 @@ module.exports = {
|
||||
inputTiffCielab: getPath('cielab-dagams.tiff'), // https://github.com/lovell/sharp/issues/646
|
||||
inputTiffUncompressed: getPath('uncompressed_tiff.tiff'), // https://code.google.com/archive/p/imagetestsuite/wikis/TIFFTestSuite.wiki file: 0c84d07e1b22b76f24cccc70d8788e4a.tif
|
||||
inputTiff8BitDepth: getPath('8bit_depth.tiff'),
|
||||
inputTifftagPhotoshop: getPath('tifftag-photoshop.tiff'), // https://github.com/lovell/sharp/issues/1600
|
||||
inputGif: getPath('Crash_test.gif'), // http://upload.wikimedia.org/wikipedia/commons/e/e3/Crash_test.gif
|
||||
inputGifGreyPlusAlpha: getPath('grey-plus-alpha.gif'), // http://i.imgur.com/gZ5jlmE.gif
|
||||
inputGifAnimated: getPath('rotating-squares.gif'), // CC0 https://loading.io/spinner/blocks/-rotating-squares-preloader-gif
|
||||
inputGifAnimatedLoop3: getPath('animated-loop-3.gif'), // CC-BY-SA-4.0 Petrus3743 https://commons.wikimedia.org/wiki/File:01-Goldener_Schnitt_Formel-Animation.gif
|
||||
inputSvg: getPath('check.svg'), // http://dev.w3.org/SVG/tools/svgweb/samples/svg-files/check.svg
|
||||
inputSvgWithEmbeddedImages: getPath('struct-image-04-t.svg'), // https://dev.w3.org/SVG/profiles/1.2T/test/svg/struct-image-04-t.svg
|
||||
|
||||
|
||||
BIN
test/fixtures/tifftag-photoshop.tiff
vendored
Normal file
BIN
test/fixtures/tifftag-photoshop.tiff
vendored
Normal file
Binary file not shown.
@@ -5,7 +5,7 @@ if ! type valgrind >/dev/null; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
curl -s -o ./test/leak/libvips.supp https://raw.githubusercontent.com/libvips/libvips/master/libvips.supp
|
||||
curl -s -o ./test/leak/libvips.supp https://raw.githubusercontent.com/libvips/libvips/master/suppressions/valgrind.supp
|
||||
|
||||
for test in ./test/unit/*.js; do
|
||||
G_SLICE=always-malloc G_DEBUG=gc-friendly valgrind \
|
||||
|
||||
@@ -196,6 +196,18 @@
|
||||
...
|
||||
fun:FcInitLoadConfigAndFonts
|
||||
}
|
||||
{
|
||||
leak_fontconfig_doContent
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: definite
|
||||
fun:malloc
|
||||
...
|
||||
fun:doContent
|
||||
fun:doProlog
|
||||
fun:prologInitProcessor
|
||||
fun:XML_ParseBuffer
|
||||
obj:*/libfontconfig.so.*
|
||||
}
|
||||
|
||||
# libvips
|
||||
{
|
||||
@@ -342,6 +354,12 @@
|
||||
...
|
||||
obj:/usr/bin/iojs
|
||||
}
|
||||
{
|
||||
value_node_invoke_params
|
||||
Memcheck:Value8
|
||||
...
|
||||
fun:_ZN2v88internal12_GLOBAL__N_16InvokeEPNS0_7IsolateERKNS1_12InvokeParamsE
|
||||
}
|
||||
{
|
||||
leak_nodejs_ImmutableAsciiSource_CreateFromLiteral
|
||||
Memcheck:Leak
|
||||
@@ -538,6 +556,13 @@
|
||||
...
|
||||
fun:_ZN4node9inspector5Agent5StartERKSsSt10shared_ptrINS_12DebugOptionsEEb
|
||||
}
|
||||
{
|
||||
leak_nodejs_debug_host_port
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: possible
|
||||
...
|
||||
fun:_ZN4node9inspector5Agent5StartERKSsRKNS_12DebugOptionsESt10shared_ptrINS_8HostPortEEb
|
||||
}
|
||||
{
|
||||
leak_nodejs_start
|
||||
Memcheck:Leak
|
||||
|
||||
135
test/unit/io.js
135
test/unit/io.js
@@ -214,7 +214,27 @@ describe('Input/output', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('Sequential read, force JPEG', function (done) {
|
||||
it('Invalid sequential read option throws', () => {
|
||||
assert.throws(() => {
|
||||
sharp({ sequentialRead: 'fail' });
|
||||
}, /Expected boolean for sequentialRead but received fail of type string/);
|
||||
});
|
||||
|
||||
it('Sequential read, force JPEG', () =>
|
||||
sharp(fixtures.inputJpg, { sequentialRead: true })
|
||||
.resize(320, 240)
|
||||
.toFormat(sharp.format.jpeg)
|
||||
.toBuffer({ resolveWithObject: true })
|
||||
.then(({ data, info }) => {
|
||||
assert.strictEqual(data.length > 0, true);
|
||||
assert.strictEqual(data.length, info.size);
|
||||
assert.strictEqual(info.format, 'jpeg');
|
||||
assert.strictEqual(info.width, 320);
|
||||
assert.strictEqual(info.height, 240);
|
||||
})
|
||||
);
|
||||
|
||||
it('Sequential read, force JPEG - deprecated', function (done) {
|
||||
sharp(fixtures.inputJpg)
|
||||
.sequentialRead()
|
||||
.resize(320, 240)
|
||||
@@ -230,7 +250,21 @@ describe('Input/output', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('Not sequential read, force JPEG', function (done) {
|
||||
it('Not sequential read, force JPEG', () =>
|
||||
sharp(fixtures.inputJpg, { sequentialRead: false })
|
||||
.resize(320, 240)
|
||||
.toFormat('jpeg')
|
||||
.toBuffer({ resolveWithObject: true })
|
||||
.then(({ data, info }) => {
|
||||
assert.strictEqual(data.length > 0, true);
|
||||
assert.strictEqual(data.length, info.size);
|
||||
assert.strictEqual(info.format, 'jpeg');
|
||||
assert.strictEqual(info.width, 320);
|
||||
assert.strictEqual(info.height, 240);
|
||||
})
|
||||
);
|
||||
|
||||
it('Not sequential read, force JPEG - deprecated', function (done) {
|
||||
sharp(fixtures.inputJpg)
|
||||
.sequentialRead(false)
|
||||
.resize(320, 240)
|
||||
@@ -559,7 +593,67 @@ describe('Input/output', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Limit pixel count of input image', function () {
|
||||
describe('Limit pixel count of input image', () => {
|
||||
it('Invalid fails - negative', () => {
|
||||
assert.throws(() => {
|
||||
sharp({ limitInputPixels: -1 });
|
||||
});
|
||||
});
|
||||
|
||||
it('Invalid fails - float', () => {
|
||||
assert.throws(() => {
|
||||
sharp({ limitInputPixels: 12.3 });
|
||||
});
|
||||
});
|
||||
|
||||
it('Invalid fails - string', () => {
|
||||
assert.throws(() => {
|
||||
sharp({ limitInputPixels: 'fail' });
|
||||
});
|
||||
});
|
||||
|
||||
it('Same size as input works', () =>
|
||||
sharp(fixtures.inputJpg)
|
||||
.metadata()
|
||||
.then(({ width, height }) =>
|
||||
sharp(fixtures.inputJpg, { limitInputPixels: width * height }).toBuffer()
|
||||
)
|
||||
);
|
||||
|
||||
it('Disabling limit works', () =>
|
||||
sharp(fixtures.inputJpgLarge, { limitInputPixels: false })
|
||||
.resize(2)
|
||||
.toBuffer()
|
||||
);
|
||||
|
||||
it('Enabling default limit works and fails with a large image', () =>
|
||||
sharp(fixtures.inputJpgLarge, { limitInputPixels: true })
|
||||
.toBuffer()
|
||||
.then(() => {
|
||||
assert.fail('Expected to fail');
|
||||
})
|
||||
.catch(err => {
|
||||
assert.strictEqual(err.message, 'Input image exceeds pixel limit');
|
||||
})
|
||||
);
|
||||
|
||||
it('Smaller than input fails', () =>
|
||||
sharp(fixtures.inputJpg)
|
||||
.metadata()
|
||||
.then(({ width, height }) =>
|
||||
sharp(fixtures.inputJpg, { limitInputPixels: width * height - 1 })
|
||||
.toBuffer()
|
||||
.then(() => {
|
||||
assert.fail('Expected to fail');
|
||||
})
|
||||
.catch(err => {
|
||||
assert.strictEqual(err.message, 'Input image exceeds pixel limit');
|
||||
})
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
describe('Limit pixel count of input image - deprecated', function () {
|
||||
it('Invalid fails - negative', function (done) {
|
||||
let isValid = false;
|
||||
try {
|
||||
@@ -635,27 +729,40 @@ describe('Input/output', function () {
|
||||
});
|
||||
|
||||
describe('Input options', function () {
|
||||
it('Option-less', function () {
|
||||
sharp();
|
||||
});
|
||||
it('Ignore unknown attribute', function () {
|
||||
sharp({ unknown: true });
|
||||
});
|
||||
it('undefined with options fails', function () {
|
||||
assert.throws(function () {
|
||||
sharp(undefined, {});
|
||||
}, /Unsupported input 'undefined' of type undefined when also providing options of type object/);
|
||||
});
|
||||
it('null with options fails', function () {
|
||||
assert.throws(function () {
|
||||
sharp(null, {});
|
||||
}, /Unsupported input 'null' of type object when also providing options of type object/);
|
||||
});
|
||||
it('Non-Object options fails', function () {
|
||||
assert.throws(function () {
|
||||
sharp(null, 'zoinks');
|
||||
});
|
||||
sharp('test', 'zoinks');
|
||||
}, /Invalid input options zoinks/);
|
||||
});
|
||||
it('Invalid density: string', function () {
|
||||
assert.throws(function () {
|
||||
sharp(null, { density: 'zoinks' });
|
||||
});
|
||||
});
|
||||
it('Ignore unknown attribute', function () {
|
||||
sharp(null, { unknown: true });
|
||||
sharp({ density: 'zoinks' });
|
||||
}, /Expected number between 1 and 2400 for density but received zoinks of type string/);
|
||||
});
|
||||
it('Invalid page property throws', function () {
|
||||
assert.throws(function () {
|
||||
sharp(null, { page: -1 });
|
||||
sharp({ page: -1 });
|
||||
}, /Expected integer between 0 and 100000 for page but received -1 of type number/);
|
||||
});
|
||||
it('Invalid pages property throws', function () {
|
||||
assert.throws(function () {
|
||||
sharp(null, { pages: '1' });
|
||||
sharp({ pages: '1' });
|
||||
}, /Expected integer between -1 and 100000 for pages but received 1 of type string/);
|
||||
});
|
||||
});
|
||||
@@ -749,7 +856,7 @@ describe('Input/output', function () {
|
||||
assert.strictEqual(472, info.height);
|
||||
assert.strictEqual(3, info.channels);
|
||||
});
|
||||
const badPipeline = sharp(null, { raw: { width: 840, height: 500, channels: 3 } })
|
||||
const badPipeline = sharp({ raw: { width: 840, height: 500, channels: 3 } })
|
||||
.toFormat('jpeg')
|
||||
.toBuffer(function (err, data, info) {
|
||||
assert.strictEqual(err.message.indexOf('memory area too small') > 0, true);
|
||||
@@ -757,7 +864,7 @@ describe('Input/output', function () {
|
||||
const inPipeline = sharp()
|
||||
.resize(840, 472)
|
||||
.raw();
|
||||
const goodPipeline = sharp(null, { raw: { width: 840, height: 472, channels: 3 } })
|
||||
const goodPipeline = sharp({ raw: { width: 840, height: 472, channels: 3 } })
|
||||
.toFormat('jpeg')
|
||||
.toBuffer(function (err, data, info) {
|
||||
if (err) throw err;
|
||||
|
||||
@@ -232,6 +232,55 @@ describe('Image metadata', function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Animated GIF', () =>
|
||||
sharp(fixtures.inputGifAnimated)
|
||||
.metadata()
|
||||
.then(({
|
||||
format, width, height, space, channels, depth,
|
||||
isProgressive, pages, pageHeight, loop, delay,
|
||||
hasProfile, hasAlpha
|
||||
}) => {
|
||||
assert.strictEqual(format, 'gif');
|
||||
assert.strictEqual(width, 80);
|
||||
assert.strictEqual(height, 80);
|
||||
assert.strictEqual(space, 'srgb');
|
||||
assert.strictEqual(channels, 4);
|
||||
assert.strictEqual(depth, 'uchar');
|
||||
assert.strictEqual(isProgressive, false);
|
||||
assert.strictEqual(pages, 30);
|
||||
assert.strictEqual(pageHeight, 80);
|
||||
assert.strictEqual(loop, 0);
|
||||
assert.deepStrictEqual(delay, Array(30).fill(30));
|
||||
assert.strictEqual(hasProfile, false);
|
||||
assert.strictEqual(hasAlpha, true);
|
||||
})
|
||||
);
|
||||
|
||||
it('Animated GIF with limited looping', () =>
|
||||
sharp(fixtures.inputGifAnimatedLoop3)
|
||||
.metadata()
|
||||
.then(({
|
||||
format, width, height, space, channels, depth,
|
||||
isProgressive, pages, pageHeight, loop, delay,
|
||||
hasProfile, hasAlpha
|
||||
}) => {
|
||||
assert.strictEqual(format, 'gif');
|
||||
assert.strictEqual(width, 370);
|
||||
assert.strictEqual(height, 285);
|
||||
assert.strictEqual(space, 'srgb');
|
||||
assert.strictEqual(channels, 4);
|
||||
assert.strictEqual(depth, 'uchar');
|
||||
assert.strictEqual(isProgressive, false);
|
||||
assert.strictEqual(pages, 10);
|
||||
assert.strictEqual(pageHeight, 285);
|
||||
assert.strictEqual(loop, 3);
|
||||
assert.deepStrictEqual(delay, [...Array(9).fill(3000), 15000]);
|
||||
assert.strictEqual(hasProfile, false);
|
||||
assert.strictEqual(hasAlpha, true);
|
||||
})
|
||||
);
|
||||
|
||||
it('vips', () =>
|
||||
sharp(fixtures.inputV)
|
||||
.metadata()
|
||||
@@ -515,6 +564,21 @@ describe('Image metadata', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('16-bit TIFF with TIFFTAG_PHOTOSHOP metadata', () =>
|
||||
sharp(fixtures.inputTifftagPhotoshop)
|
||||
.metadata()
|
||||
.then(metadata => {
|
||||
assert.strictEqual(metadata.format, 'tiff');
|
||||
assert.strictEqual(metadata.width, 317);
|
||||
assert.strictEqual(metadata.height, 211);
|
||||
assert.strictEqual(metadata.space, 'rgb16');
|
||||
assert.strictEqual(metadata.channels, 3);
|
||||
assert.strictEqual(typeof metadata.tifftagPhotoshop, 'object');
|
||||
assert.strictEqual(metadata.tifftagPhotoshop instanceof Buffer, true);
|
||||
assert.strictEqual(metadata.tifftagPhotoshop.length, 6634);
|
||||
})
|
||||
);
|
||||
|
||||
it('File input with corrupt header fails gracefully', function (done) {
|
||||
sharp(fixtures.inputJpgWithCorruptHeader)
|
||||
.metadata(function (err) {
|
||||
|
||||
@@ -103,6 +103,15 @@ describe('PNG', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('16-bit grey+alpha PNG identity transform', function () {
|
||||
const actual = fixtures.path('output.16-bit-grey-alpha-identity.png');
|
||||
return sharp(fixtures.inputPng16BitGreyAlpha)
|
||||
.toFile(actual)
|
||||
.then(function () {
|
||||
fixtures.assertMaxColourDistance(actual, fixtures.expected('16-bit-grey-alpha-identity.png'));
|
||||
});
|
||||
});
|
||||
|
||||
it('Valid PNG libimagequant palette value does not throw error', function () {
|
||||
assert.doesNotThrow(function () {
|
||||
sharp().png({ palette: false });
|
||||
|
||||
@@ -307,6 +307,40 @@ describe('Resize dimensions', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('Do crop when fit = cover and withoutEnlargement = true and width >= outputWidth, and height < outputHeight', function (done) {
|
||||
sharp(fixtures.inputJpg)
|
||||
.resize({
|
||||
width: 3000,
|
||||
height: 1000,
|
||||
withoutEnlargement: true
|
||||
})
|
||||
.toBuffer(function (err, data, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(true, data.length > 0);
|
||||
assert.strictEqual('jpeg', info.format);
|
||||
assert.strictEqual(2725, info.width);
|
||||
assert.strictEqual(1000, info.height);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Do crop when fit = cover and withoutEnlargement = true and width < outputWidth, and height >= outputHeight', function (done) {
|
||||
sharp(fixtures.inputJpg)
|
||||
.resize({
|
||||
width: 1500,
|
||||
height: 2226,
|
||||
withoutEnlargement: true
|
||||
})
|
||||
.toBuffer(function (err, data, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(true, data.length > 0);
|
||||
assert.strictEqual('jpeg', info.format);
|
||||
assert.strictEqual(1500, info.width);
|
||||
assert.strictEqual(2225, info.height);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Do enlarge when input width is less than output width', function (done) {
|
||||
sharp(fixtures.inputJpg)
|
||||
.resize({
|
||||
|
||||
@@ -242,11 +242,11 @@ describe('Image Stats', function () {
|
||||
|
||||
// red channel
|
||||
assert.strictEqual(0, stats.channels[0].min);
|
||||
assert.strictEqual(255, stats.channels[0].max);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0].sum, 83291370));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0].squaresSum, 11379783198));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0].mean, 105.36169496842616));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0].stdev, 57.39412151419967));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0].max, 254, 255));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0].sum, 82506996));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0].squaresSum, 11213984832));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0].mean, 104.36947963892487));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[0].stdev, 57.379896254993135));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0].minX));
|
||||
assert.strictEqual(true, isInRange(stats.channels[0].minX, 0, 1024));
|
||||
assert.strictEqual(true, isInteger(stats.channels[0].minY));
|
||||
@@ -258,11 +258,11 @@ describe('Image Stats', function () {
|
||||
|
||||
// green channel
|
||||
assert.strictEqual(0, stats.channels[1].min);
|
||||
assert.strictEqual(255, stats.channels[1].max);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1].sum, 120877425));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1].squaresSum, 20774687595));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1].mean, 152.9072025279307));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1].stdev, 53.84143349689916));
|
||||
assert.strictEqual(true, isInRange(stats.channels[1].max, 254, 255));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1].sum, 120089056));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1].squaresSum, 20533721114));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1].mean, 151.90993361398964));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[1].stdev, 53.83370206587037));
|
||||
assert.strictEqual(true, isInteger(stats.channels[1].minX));
|
||||
assert.strictEqual(true, isInRange(stats.channels[1].minX, 0, 1024));
|
||||
assert.strictEqual(true, isInteger(stats.channels[1].minY));
|
||||
@@ -274,11 +274,11 @@ describe('Image Stats', function () {
|
||||
|
||||
// blue channel
|
||||
assert.strictEqual(0, stats.channels[2].min);
|
||||
assert.strictEqual(255, stats.channels[2].max);
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2].sum, 138938859));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2].squaresSum, 28449125593));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2].mean, 175.75450711423252));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2].stdev, 71.39929031070358));
|
||||
assert.strictEqual(true, isInRange(stats.channels[2].max, 254, 255));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2].sum, 138153653));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2].squaresSum, 28172033081));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2].mean, 174.76123932359133));
|
||||
assert.strictEqual(true, isInAcceptableRange(stats.channels[2].stdev, 71.38276338513747));
|
||||
assert.strictEqual(true, isInteger(stats.channels[2].minX));
|
||||
assert.strictEqual(true, isInRange(stats.channels[2].minX, 0, 1024));
|
||||
assert.strictEqual(true, isInteger(stats.channels[2].minY));
|
||||
|
||||
@@ -10,8 +10,8 @@ describe('toBuffer', () => {
|
||||
const image = sharp(fixtures.inputJpg);
|
||||
image.toBuffer({ resolveWithObject: true }).then((obj) => {
|
||||
image.toBuffer().then((buff) => {
|
||||
assert.strict.equal(Buffer.isBuffer(buff), true);
|
||||
assert.strict.equal(typeof obj, 'object');
|
||||
assert.strictEqual(Buffer.isBuffer(buff), true);
|
||||
assert.strictEqual(typeof obj, 'object');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user