Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f59a2aebf | ||
|
|
26fb75bf3f | ||
|
|
25e5f27785 | ||
|
|
ef62daccf9 | ||
|
|
9067c0a000 | ||
|
|
79470d2e07 | ||
|
|
3cefa6f2bf | ||
|
|
75d954a6bc | ||
|
|
1b7e3746cc | ||
|
|
29252d9dbb | ||
|
|
23e14861be | ||
|
|
97960b5f91 | ||
|
|
18c4ad9adf | ||
|
|
b240c53633 | ||
|
|
660f3d58be | ||
|
|
b6d75cda8e | ||
|
|
e07356c11c | ||
|
|
82e215a42e | ||
|
|
cc1c36d891 | ||
|
|
a1a2d7de5c | ||
|
|
6dce2deb82 | ||
|
|
cdad84edc6 | ||
|
|
de842a67d8 | ||
|
|
918bbe88c6 | ||
|
|
7d3891989c | ||
|
|
168fe7c8d9 | ||
|
|
29ab8408fb | ||
|
|
692e2d4df4 | ||
|
|
85d86dbede | ||
|
|
ce2d7b8efc | ||
|
|
be00d72d82 | ||
|
|
5b376364f5 | ||
|
|
409d15c624 | ||
|
|
ce22388c3b | ||
|
|
30143cf509 | ||
|
|
78f31d2b0d | ||
|
|
4e67a5025a | ||
|
|
b7e0a6f277 | ||
|
|
045680fba5 | ||
|
|
692347cc6b | ||
|
|
faa515d969 |
4
.gitignore
vendored
@@ -4,6 +4,6 @@ coverage
|
|||||||
test/bench/node_modules
|
test/bench/node_modules
|
||||||
test/fixtures/output*
|
test/fixtures/output*
|
||||||
test/leak/libvips.supp
|
test/leak/libvips.supp
|
||||||
|
lib
|
||||||
# Mac OS X
|
include
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|||||||
@@ -8,3 +8,5 @@ test
|
|||||||
.travis.yml
|
.travis.yml
|
||||||
appveyor.yml
|
appveyor.yml
|
||||||
mkdocs.yml
|
mkdocs.yml
|
||||||
|
lib
|
||||||
|
include
|
||||||
|
|||||||
11
.travis.yml
@@ -2,9 +2,18 @@ language: node_js
|
|||||||
node_js:
|
node_js:
|
||||||
- "0.10"
|
- "0.10"
|
||||||
- "0.12"
|
- "0.12"
|
||||||
- "iojs-v1"
|
|
||||||
- "iojs-v2"
|
- "iojs-v2"
|
||||||
|
- "iojs-v3"
|
||||||
|
- "4"
|
||||||
|
sudo: 9000
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- ubuntu-toolchain-r-test
|
||||||
|
packages:
|
||||||
|
- g++-4.8
|
||||||
before_install:
|
before_install:
|
||||||
|
- sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 90
|
||||||
- curl -s https://raw.githubusercontent.com/lovell/sharp/master/preinstall.sh | sudo bash -
|
- curl -s https://raw.githubusercontent.com/lovell/sharp/master/preinstall.sh | sudo bash -
|
||||||
after_success:
|
after_success:
|
||||||
- cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js
|
- cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js
|
||||||
|
|||||||
12
appveyor.yml
@@ -3,16 +3,18 @@ version: "{build}"
|
|||||||
build: off
|
build: off
|
||||||
platform: x64
|
platform: x64
|
||||||
environment:
|
environment:
|
||||||
VIPS_VERSION_MAJOR_MINOR: 8.0
|
VIPS_VERSION_MAJOR_MINOR: 8.1
|
||||||
VIPS_VERSION_PATCH: 2
|
VIPS_VERSION_PATCH: 1
|
||||||
VIPS_WARNING: 0
|
VIPS_WARNING: 0
|
||||||
matrix:
|
matrix:
|
||||||
- nodejs_version: "0.10"
|
|
||||||
nodejs_exec: "node"
|
|
||||||
- nodejs_version: "0.12"
|
- nodejs_version: "0.12"
|
||||||
nodejs_exec: "node"
|
nodejs_exec: "node"
|
||||||
- nodejs_version: "2"
|
- nodejs_version: "2"
|
||||||
nodejs_exec: "iojs"
|
nodejs_exec: "iojs"
|
||||||
|
- nodejs_version: "3"
|
||||||
|
nodejs_exec: "iojs"
|
||||||
|
- nodejs_version: "4"
|
||||||
|
nodejs_exec: "node"
|
||||||
install:
|
install:
|
||||||
- ps: $env:VIPS_VERSION = "$env:VIPS_VERSION_MAJOR_MINOR.$env:VIPS_VERSION_PATCH"
|
- ps: $env:VIPS_VERSION = "$env:VIPS_VERSION_MAJOR_MINOR.$env:VIPS_VERSION_PATCH"
|
||||||
- ps: Write-Output "Fetching http://www.vips.ecs.soton.ac.uk/supported/$env:VIPS_VERSION_MAJOR_MINOR/win32/vips-dev-$env:VIPS_VERSION.zip"
|
- ps: Write-Output "Fetching http://www.vips.ecs.soton.ac.uk/supported/$env:VIPS_VERSION_MAJOR_MINOR/win32/vips-dev-$env:VIPS_VERSION.zip"
|
||||||
@@ -21,6 +23,6 @@ install:
|
|||||||
- ps: $env:VIPS_HOME = "c:\vips-dev-$env:VIPS_VERSION"
|
- ps: $env:VIPS_HOME = "c:\vips-dev-$env:VIPS_VERSION"
|
||||||
- ps: $env:PATH = "$env:VIPS_HOME\bin;$env:PATH"
|
- ps: $env:PATH = "$env:VIPS_HOME\bin;$env:PATH"
|
||||||
- ps: Install-Product node $env:nodejs_version x86
|
- ps: Install-Product node $env:nodejs_version x86
|
||||||
- npm install --arch=ia32 --msvs_version=2013
|
- npm install --arch=ia32
|
||||||
test_script:
|
test_script:
|
||||||
- npm run-script test-win32-%nodejs_exec%
|
- npm run-script test-win32-%nodejs_exec%
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
{
|
{
|
||||||
'targets': [{
|
'targets': [{
|
||||||
'target_name': 'sharp',
|
'target_name': 'sharp',
|
||||||
|
'variables': {
|
||||||
|
'runtime_link%':'shared',
|
||||||
|
},
|
||||||
'sources': [
|
'sources': [
|
||||||
'src/common.cc',
|
'src/common.cc',
|
||||||
'src/metadata.cc',
|
'src/metadata.cc',
|
||||||
@@ -51,6 +54,11 @@
|
|||||||
'include_dirs': [
|
'include_dirs': [
|
||||||
'<!(PKG_CONFIG_PATH="<(PKG_CONFIG_PATH)" pkg-config --cflags vips glib-2.0)',
|
'<!(PKG_CONFIG_PATH="<(PKG_CONFIG_PATH)" pkg-config --cflags vips glib-2.0)',
|
||||||
'<!(node -e "require(\'nan\')")'
|
'<!(node -e "require(\'nan\')")'
|
||||||
|
],
|
||||||
|
'conditions': [
|
||||||
|
['runtime_link == "static"', {
|
||||||
|
'libraries': ['<!(PKG_CONFIG_PATH="<(PKG_CONFIG_PATH)" pkg-config --libs vips --static)']
|
||||||
|
}]
|
||||||
]
|
]
|
||||||
}]
|
}]
|
||||||
],
|
],
|
||||||
|
|||||||
19
docs/api.md
@@ -11,7 +11,7 @@ var sharp = require('sharp');
|
|||||||
Constructor to which further methods are chained. `input`, if present, can be one of:
|
Constructor to which further methods are chained. `input`, if present, can be one of:
|
||||||
|
|
||||||
* Buffer containing JPEG, PNG, WebP, GIF* or TIFF image data, or
|
* Buffer containing JPEG, PNG, WebP, GIF* or TIFF image data, or
|
||||||
* String containing the filename of an image, with most major formats supported.
|
* String containing the path to an image file, with most major formats supported.
|
||||||
|
|
||||||
The object returned implements the
|
The object returned implements the
|
||||||
[stream.Duplex](http://nodejs.org/api/stream.html#stream_class_stream_duplex) class.
|
[stream.Duplex](http://nodejs.org/api/stream.html#stream_class_stream_duplex) class.
|
||||||
@@ -109,9 +109,10 @@ Scale output to `width` x `height`. By default, the resized image is cropped to
|
|||||||
|
|
||||||
Crop the resized image to the exact size specified, the default behaviour.
|
Crop the resized image to the exact size specified, the default behaviour.
|
||||||
|
|
||||||
`gravity`, if present, is an attribute of the `sharp.gravity` Object e.g. `sharp.gravity.north`.
|
`gravity`, if present, is a String or an attribute of the `sharp.gravity` Object e.g. `sharp.gravity.north`.
|
||||||
|
|
||||||
Possible values are `north`, `east`, `south`, `west`, `center` and `centre`. The default gravity is `center`/`centre`.
|
Possible values are `north`, `northeast`, `east`, `southeast`, `south`, `southwest`, `west`, `northwest`, `center` and `centre`.
|
||||||
|
The default gravity is `center`/`centre`.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var transformer = sharp()
|
var transformer = sharp()
|
||||||
@@ -327,7 +328,7 @@ When a `radius` is provided, performs a slower, more accurate sharpen of the L c
|
|||||||
|
|
||||||
Apply a gamma correction by reducing the encoding (darken) pre-resize at a factor of `1/gamma` then increasing the encoding (brighten) post-resize at a factor of `gamma`.
|
Apply a gamma correction by reducing the encoding (darken) pre-resize at a factor of `1/gamma` then increasing the encoding (brighten) post-resize at a factor of `gamma`.
|
||||||
|
|
||||||
`gamma`, if present, is a Number betweem 1 and 3. The default value is `2.2`, a suitable approximation for sRGB images.
|
`gamma`, if present, is a Number between 1 and 3. The default value is `2.2`, a suitable approximation for sRGB images.
|
||||||
|
|
||||||
This can improve the perceived brightness of a resized image in non-linear colour spaces.
|
This can improve the perceived brightness of a resized image in non-linear colour spaces.
|
||||||
|
|
||||||
@@ -345,13 +346,13 @@ The output image will still be web-friendly sRGB and contain three (identical) c
|
|||||||
|
|
||||||
Enhance output image contrast by stretching its luminance to cover the full dynamic range. This typically reduces performance by 30%.
|
Enhance output image contrast by stretching its luminance to cover the full dynamic range. This typically reduces performance by 30%.
|
||||||
|
|
||||||
#### overlayWith(filename)
|
#### overlayWith(path)
|
||||||
|
|
||||||
_Experimental_
|
_Experimental_
|
||||||
|
|
||||||
Alpha composite `filename` over the processed (resized, extracted) image. The dimensions of the two images must match.
|
Alpha composite image at `path` over the processed (resized, extracted) image. The dimensions of the two images must match.
|
||||||
|
|
||||||
* `filename` is a String containing the filename of an image with an alpha channel.
|
* `path` is a String containing the path to an image file with an alpha channel.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
sharp('input.png')
|
sharp('input.png')
|
||||||
@@ -374,9 +375,9 @@ sharp('input.png')
|
|||||||
|
|
||||||
### Output
|
### Output
|
||||||
|
|
||||||
#### toFile(filename, [callback])
|
#### toFile(path, [callback])
|
||||||
|
|
||||||
`filename` is a String containing the filename to write the image data to. The format is inferred from the extension, with JPEG, PNG, WebP, TIFF and DZI supported.
|
`path` is a String containing the path to write the image data to. The format is inferred from the extension, with JPEG, PNG, WebP, TIFF and DZI supported.
|
||||||
|
|
||||||
`callback`, if present, is called with two arguments `(err, info)` where:
|
`callback`, if present, is called with two arguments `(err, info)` where:
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,34 @@
|
|||||||
|
|
||||||
### v0.11 - "*knife*"
|
### v0.11 - "*knife*"
|
||||||
|
|
||||||
|
#### 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)
|
||||||
|
[@brandonaaron](https://github.com/brandonaaron)
|
||||||
|
|
||||||
|
* Ensure correct auto-rotation for EXIF Orientation values 2 and 4.
|
||||||
|
[#288](https://github.com/lovell/sharp/pull/288)
|
||||||
|
[@brandonaaron](https://github.com/brandonaaron)
|
||||||
|
|
||||||
|
* Make static linking possible via `--runtime_link` install option.
|
||||||
|
[#287](https://github.com/lovell/sharp/pull/287)
|
||||||
|
[@vlapo](https://github.com/vlapo)
|
||||||
|
|
||||||
|
#### 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
|
||||||
|
|
||||||
|
* Allow crop gravity to be provided as a String.
|
||||||
|
[#255](https://github.com/lovell/sharp/pull/255)
|
||||||
|
[@papandreou](https://github.com/papandreou)
|
||||||
|
* 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".
|
* Silence MSVC warning: "C4530: C++ exception handler used, but unwind semantics are not enabled".
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ npm install sharp
|
|||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
* Node.js v0.10+ or io.js
|
* Node.js v0.10+ or io.js
|
||||||
* [libvips](https://github.com/jcupitt/libvips) v7.40.0+ (7.42.0+ recommended)
|
* [libvips](https://github.com/jcupitt/libvips) v7.40.0+ (8.1.1+ recommended)
|
||||||
* C++11 compatible compiler such as gcc 4.6+, clang 3.0+ or MSVC 2013
|
* C++11 compatible compiler such as gcc 4.6+, clang 3.0+ or MSVC 2013 (Node v4+ requires gcc 4.8+)
|
||||||
|
|
||||||
### Linux
|
### Linux
|
||||||
|
|
||||||
@@ -19,11 +19,12 @@ For a system-wide installation of the most suitable version of
|
|||||||
libvips and its dependencies on the following Operating Systems:
|
libvips and its dependencies on the following Operating Systems:
|
||||||
|
|
||||||
* Debian 7, 8
|
* Debian 7, 8
|
||||||
* Ubuntu 12.04, 14.04, 14.10, 15.04
|
* Ubuntu 12.04, 14.04, 14.10, 15.04, 15.10
|
||||||
* Mint 13, 17
|
* Mint 13, 17
|
||||||
|
* Elementary 0.3
|
||||||
* RHEL/Centos/Scientific 6, 7
|
* RHEL/Centos/Scientific 6, 7
|
||||||
* Fedora 21, 22
|
* Fedora 21, 22
|
||||||
* Amazon Linux 2014.09, 2015.03
|
* Amazon Linux 2015.03, 2015.09
|
||||||
* OpenSuse 13
|
* OpenSuse 13
|
||||||
|
|
||||||
run the following as a user with `sudo` access:
|
run the following as a user with `sudo` access:
|
||||||
|
|||||||
@@ -3,18 +3,17 @@
|
|||||||
### Test environment
|
### Test environment
|
||||||
|
|
||||||
* AWS EC2 [c4.xlarge](http://aws.amazon.com/ec2/instance-types/#c4)
|
* AWS EC2 [c4.xlarge](http://aws.amazon.com/ec2/instance-types/#c4)
|
||||||
* Ubuntu 15.04
|
* Amazon Linux AMI 2015.09
|
||||||
* Node.js 0.12.7
|
* Node.js v4.1.2
|
||||||
* libvips 8.0.2
|
|
||||||
* liborc 0.4.22
|
|
||||||
|
|
||||||
### The contenders
|
### The contenders
|
||||||
|
|
||||||
* [lwip](https://www.npmjs.com/package/lwip) 0.0.7 - Wrapper around CImg, compiles dependencies from source
|
* [jimp](https://www.npmjs.com/package/jimp) v0.2.8 - Image processing in pure JavaScript.
|
||||||
* [imagemagick-native](https://www.npmjs.com/package/imagemagick-native) git@45d4e2e - Wrapper around libmagick++, supports Buffers only.
|
* [lwip](https://www.npmjs.com/package/lwip) v0.0.8 - Wrapper around CImg, compiles dependencies from source.
|
||||||
* [imagemagick](https://www.npmjs.com/package/imagemagick) 0.1.3 - Supports filesystem only and "*has been unmaintained for a long time*".
|
* ~~[imagemagick-native](https://www.npmjs.com/package/imagemagick-native)~~ - Wrapper around libmagick++, supports Buffers only. Does not currently work with Node.js v4.
|
||||||
* [gm](https://www.npmjs.com/package/gm) 1.18.1 - Fully featured wrapper around GraphicsMagick's `convert` command line utility.
|
* [imagemagick](https://www.npmjs.com/package/imagemagick) v0.1.3 - Supports filesystem only and "*has been unmaintained for a long time*".
|
||||||
* sharp 0.11.0 - Caching within libvips disabled to ensure a fair comparison.
|
* [gm](https://www.npmjs.com/package/gm) v1.20.0 - Fully featured wrapper around GraphicsMagick's `convert` command line utility.
|
||||||
|
* sharp v0.11.3 / libvips v8.1.0 - Caching within libvips disabled to ensure a fair comparison.
|
||||||
|
|
||||||
### The task
|
### The task
|
||||||
|
|
||||||
@@ -23,18 +22,19 @@ Decompress a 2725x2225 JPEG image, resize to 720x480 using bilinear interpolatio
|
|||||||
### Results
|
### Results
|
||||||
|
|
||||||
| Module | Input | Output | Ops/sec | Speed-up |
|
| Module | Input | Output | Ops/sec | Speed-up |
|
||||||
| :----------------- | :----- | :----- | ------: | -------: |
|
| :---------- | :----- | :----- | ------: | -------: |
|
||||||
| lwip | file | file | 1.75 | 1 |
|
| jimp | file | file | 0.94 | 1.0 |
|
||||||
| lwip | buffer | buffer | 2.21 | 1.3 |
|
| jimp | buffer | buffer | 1.12 | 1.2 |
|
||||||
| imagemagick-native | buffer | buffer | 7.13 | 4.1 |
|
| lwip | file | file | 1.12 | 1.2 |
|
||||||
| gm | buffer | buffer | 7.27 | 4.2 |
|
| lwip | buffer | buffer | 1.13 | 1.2 |
|
||||||
| gm | file | file | 7.33 | 4.2 |
|
| gm | buffer | buffer | 5.50 | 5.9 |
|
||||||
| imagemagick | file | file | 10.04 | 5.7 |
|
| gm | file | file | 5.55 | 5.9 |
|
||||||
| sharp | stream | stream | 23.12 | 13.2 |
|
| imagemagick | file | file | 8.66 | 9.2 |
|
||||||
| sharp | file | file | 24.43 | 14.0 |
|
| sharp | stream | stream | 16.33 | 17.4 |
|
||||||
| sharp | file | buffer | 24.55 | 14.0 |
|
| sharp | file | file | 16.88 | 18.0 |
|
||||||
| sharp | buffer | file | 24.86 | 14.2 |
|
| sharp | file | buffer | 16.90 | 18.1 |
|
||||||
| sharp | buffer | buffer | 24.92 | 14.2 |
|
| sharp | buffer | file | 16.99 | 18.1 |
|
||||||
|
| sharp | buffer | buffer | 17.06 | 18.1 |
|
||||||
|
|
||||||
Greater performance can be expected with caching enabled (default) and using 8+ core machines.
|
Greater performance can be expected with caching enabled (default) and using 8+ core machines.
|
||||||
|
|
||||||
@@ -57,7 +57,9 @@ sudo apt-get install imagemagick graphicsmagick libmagick++-dev
|
|||||||
|
|
||||||
```sh
|
```sh
|
||||||
git clone https://github.com/lovell/sharp.git
|
git clone https://github.com/lovell/sharp.git
|
||||||
cd sharp/test/bench
|
cd sharp
|
||||||
|
npm install
|
||||||
|
cd test/bench
|
||||||
npm install
|
npm install
|
||||||
npm test
|
npm test
|
||||||
```
|
```
|
||||||
|
|||||||
6
index.js
@@ -137,12 +137,14 @@ Sharp.prototype._write = function(chunk, encoding, callback) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Crop this part of the resized image (Center/Centre, North, East, South, West)
|
// Crop this part of the resized image (Center/Centre, North, East, South, West)
|
||||||
module.exports.gravity = {'center': 0, 'centre': 0, 'north': 1, 'east': 2, 'south': 3, 'west': 4};
|
module.exports.gravity = {'center': 0, 'centre': 0, 'north': 1, 'east': 2, 'south': 3, 'west': 4, 'northeast': 5, 'southeast': 6, 'southwest': 7, 'northwest': 8};
|
||||||
|
|
||||||
Sharp.prototype.crop = function(gravity) {
|
Sharp.prototype.crop = function(gravity) {
|
||||||
this.options.canvas = 'crop';
|
this.options.canvas = 'crop';
|
||||||
if (typeof gravity === 'number' && !Number.isNaN(gravity) && gravity >= 0 && gravity <= 4) {
|
if (typeof gravity === 'number' && !Number.isNaN(gravity) && gravity >= 0 && gravity <= 8) {
|
||||||
this.options.gravity = gravity;
|
this.options.gravity = gravity;
|
||||||
|
} else if (typeof gravity === 'string' && typeof module.exports.gravity[gravity] === 'number') {
|
||||||
|
this.options.gravity = module.exports.gravity[gravity];
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Unsupported crop gravity ' + gravity);
|
throw new Error('Unsupported crop gravity ' + gravity);
|
||||||
}
|
}
|
||||||
|
|||||||
26
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sharp",
|
"name": "sharp",
|
||||||
"version": "0.11.1",
|
"version": "0.11.4",
|
||||||
"author": "Lovell Fuller <npm@lovell.info>",
|
"author": "Lovell Fuller <npm@lovell.info>",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
"Pierre Inglebert <pierre.inglebert@gmail.com>",
|
"Pierre Inglebert <pierre.inglebert@gmail.com>",
|
||||||
@@ -16,14 +16,15 @@
|
|||||||
"Linus Unnebäck <linus@folkdatorn.se>",
|
"Linus Unnebäck <linus@folkdatorn.se>",
|
||||||
"Victor Mateevitsi <mvictoras@gmail.com>",
|
"Victor Mateevitsi <mvictoras@gmail.com>",
|
||||||
"Alaric Holloway <alaric.holloway@gmail.com>",
|
"Alaric Holloway <alaric.holloway@gmail.com>",
|
||||||
"Bernhard K. Weisshuhn <bkw@codingforce.com>"
|
"Bernhard K. Weisshuhn <bkw@codingforce.com>",
|
||||||
|
"Chris Riley <criley@primedia.com>"
|
||||||
],
|
],
|
||||||
"description": "High performance Node.js module to resize JPEG, PNG, WebP and TIFF images using the libvips library",
|
"description": "High performance Node.js module to resize JPEG, PNG, WebP and TIFF images using the libvips library",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"clean": "rm -rf test/fixtures/output.*",
|
"clean": "rm -rf test/fixtures/output.*",
|
||||||
"test": "VIPS_WARNING=0 node ./node_modules/istanbul/lib/cli.js cover ./node_modules/mocha/bin/_mocha -- --slow=5000 --timeout=20000 ./test/unit/*.js",
|
"test": "VIPS_WARNING=0 node ./node_modules/istanbul/lib/cli.js cover ./node_modules/mocha/bin/_mocha -- --slow=5000 --timeout=20000 ./test/unit/*.js",
|
||||||
"test-clean": "npm run clean && npm install && npm test",
|
"test-clean": "npm run clean && npm install && npm test",
|
||||||
"test-leak": "cd test/leak; ./leak.sh; cd - > /dev/null",
|
"test-leak": "./test/leak/leak.sh",
|
||||||
"test-win32-node": "node ./node_modules/mocha/bin/mocha --slow=5000 --timeout=30000 ./test/unit/*.js",
|
"test-win32-node": "node ./node_modules/mocha/bin/mocha --slow=5000 --timeout=30000 ./test/unit/*.js",
|
||||||
"test-win32-iojs": "iojs ./node_modules/mocha/bin/mocha --slow=5000 --timeout=30000 ./test/unit/*.js"
|
"test-win32-iojs": "iojs ./node_modules/mocha/bin/mocha --slow=5000 --timeout=30000 ./test/unit/*.js"
|
||||||
},
|
},
|
||||||
@@ -45,21 +46,22 @@
|
|||||||
"vips"
|
"vips"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bluebird": "^2.9.33",
|
"bluebird": "^3.0.5",
|
||||||
"color": "^0.10.1",
|
"color": "^0.10.1",
|
||||||
"nan": "^1.8.4",
|
"nan": "^2.1.0",
|
||||||
"semver": "^5.0.1"
|
"semver": "^5.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"async": "^1.4.2",
|
"async": "^1.5.0",
|
||||||
"coveralls": "^2.11.2",
|
"coveralls": "^2.11.4",
|
||||||
"exif-reader": "1.0.0",
|
"exif-reader": "1.0.0",
|
||||||
"icc": "^0.0.2",
|
"icc": "^0.0.2",
|
||||||
"istanbul": "^0.3.17",
|
"istanbul": "^0.4.0",
|
||||||
"mocha": "^2.2.5",
|
"mocha": "^2.3.3",
|
||||||
"mocha-jshint": "^2.2.3",
|
"mocha-jshint": "^2.2.5",
|
||||||
"node-cpplint": "^0.4.0",
|
"node-cpplint": "^0.4.0",
|
||||||
"rimraf": "^2.4.1"
|
"rimraf": "^2.4.3",
|
||||||
|
"bufferutil": "^1.2.1"
|
||||||
},
|
},
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
@@ -4,16 +4,18 @@
|
|||||||
# Currently supports:
|
# Currently supports:
|
||||||
# * Debian Linux
|
# * Debian Linux
|
||||||
# * Debian 7, 8
|
# * Debian 7, 8
|
||||||
# * Ubuntu 12.04, 14.04, 14.10, 15.04
|
# * Ubuntu 12.04, 14.04, 14.10, 15.04, 15.10
|
||||||
# * Mint 13, 17
|
# * Mint 13, 17
|
||||||
|
# * Elementary 0.3
|
||||||
# * Red Hat Linux
|
# * Red Hat Linux
|
||||||
# * RHEL/Centos/Scientific 6, 7
|
# * RHEL/Centos/Scientific 6, 7
|
||||||
# * Fedora 21, 22
|
# * Fedora 21, 22
|
||||||
# * Amazon Linux 2014.09, 2015.03
|
# * Amazon Linux 2015.03, 2015.09
|
||||||
|
# * OpenSuse 13
|
||||||
|
|
||||||
vips_version_minimum=7.40.0
|
vips_version_minimum=7.40.0
|
||||||
vips_version_latest_major_minor=8.0
|
vips_version_latest_major_minor=8.1
|
||||||
vips_version_latest_patch=2
|
vips_version_latest_patch=1
|
||||||
|
|
||||||
openslide_version_minimum=3.4.0
|
openslide_version_minimum=3.4.0
|
||||||
openslide_version_latest_major_minor=3.4
|
openslide_version_latest_major_minor=3.4
|
||||||
@@ -24,7 +26,7 @@ install_libvips_from_source() {
|
|||||||
curl -O http://www.vips.ecs.soton.ac.uk/supported/$vips_version_latest_major_minor/vips-$vips_version_latest_major_minor.$vips_version_latest_patch.tar.gz
|
curl -O http://www.vips.ecs.soton.ac.uk/supported/$vips_version_latest_major_minor/vips-$vips_version_latest_major_minor.$vips_version_latest_patch.tar.gz
|
||||||
tar zvxf vips-$vips_version_latest_major_minor.$vips_version_latest_patch.tar.gz
|
tar zvxf vips-$vips_version_latest_major_minor.$vips_version_latest_patch.tar.gz
|
||||||
cd vips-$vips_version_latest_major_minor.$vips_version_latest_patch
|
cd vips-$vips_version_latest_major_minor.$vips_version_latest_patch
|
||||||
./configure --disable-debug --disable-docs --disable-static --disable-introspection --enable-cxx=yes --without-python --without-orc --without-fftw $1
|
./configure --disable-debug --disable-docs --disable-static --disable-introspection --disable-dependency-tracking --enable-cxx=yes --without-python --without-orc --without-fftw $1
|
||||||
make
|
make
|
||||||
make install
|
make install
|
||||||
cd ..
|
cd ..
|
||||||
@@ -125,12 +127,12 @@ if [ $enable_openslide -eq 1 ] && [ -z $vips_with_openslide ] && [ $openslide_ex
|
|||||||
DISTRO=$(lsb_release -c -s)
|
DISTRO=$(lsb_release -c -s)
|
||||||
echo "Detected Debian Linux '$DISTRO'"
|
echo "Detected Debian Linux '$DISTRO'"
|
||||||
case "$DISTRO" in
|
case "$DISTRO" in
|
||||||
jessie|vivid)
|
jessie|vivid|wily)
|
||||||
# Debian 8, Ubuntu 15
|
# Debian 8, Ubuntu 15
|
||||||
echo "Installing libopenslide via apt-get"
|
echo "Installing libopenslide via apt-get"
|
||||||
apt-get install -y libopenslide-dev
|
apt-get install -y libopenslide-dev
|
||||||
;;
|
;;
|
||||||
trusty|utopic|qiana|rebecca|rafaela)
|
trusty|utopic|qiana|rebecca|rafaela|freya)
|
||||||
# Ubuntu 14, Mint 17
|
# Ubuntu 14, Mint 17
|
||||||
echo "Installing libopenslide dependencies via apt-get"
|
echo "Installing libopenslide dependencies via apt-get"
|
||||||
apt-get install -y automake build-essential curl zlib1g-dev libopenjpeg-dev libpng12-dev libjpeg-dev libtiff5-dev libgdk-pixbuf2.0-dev libxml2-dev libsqlite3-dev libcairo2-dev libglib2.0-dev sqlite3 libsqlite3-dev
|
apt-get install -y automake build-essential curl zlib1g-dev libopenjpeg-dev libpng12-dev libjpeg-dev libtiff5-dev libgdk-pixbuf2.0-dev libxml2-dev libsqlite3-dev libcairo2-dev libglib2.0-dev sqlite3 libsqlite3-dev
|
||||||
@@ -209,7 +211,7 @@ if [ -f /etc/debian_version ]; then
|
|||||||
DISTRO=$(lsb_release -c -s)
|
DISTRO=$(lsb_release -c -s)
|
||||||
echo "Detected Debian Linux '$DISTRO'"
|
echo "Detected Debian Linux '$DISTRO'"
|
||||||
case "$DISTRO" in
|
case "$DISTRO" in
|
||||||
jessie|vivid)
|
jessie|vivid|wily)
|
||||||
# Debian 8, Ubuntu 15
|
# Debian 8, Ubuntu 15
|
||||||
if [ $enable_openslide -eq 1 ]; then
|
if [ $enable_openslide -eq 1 ]; then
|
||||||
echo "Recompiling vips with openslide support"
|
echo "Recompiling vips with openslide support"
|
||||||
@@ -219,7 +221,7 @@ if [ -f /etc/debian_version ]; then
|
|||||||
apt-get install -y libvips-dev libgsf-1-dev
|
apt-get install -y libvips-dev libgsf-1-dev
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
trusty|utopic|qiana|rebecca|rafaela)
|
trusty|utopic|qiana|rebecca|rafaela|freya)
|
||||||
# Ubuntu 14, Mint 17
|
# Ubuntu 14, Mint 17
|
||||||
echo "Installing libvips dependencies via apt-get"
|
echo "Installing libvips dependencies via apt-get"
|
||||||
apt-get install -y automake build-essential gobject-introspection gtk-doc-tools libglib2.0-dev libjpeg-dev libpng12-dev libwebp-dev libtiff5-dev libexif-dev libgsf-1-dev liblcms2-dev libxml2-dev swig libmagickcore-dev curl
|
apt-get install -y automake build-essential gobject-introspection gtk-doc-tools libglib2.0-dev libjpeg-dev libpng12-dev libwebp-dev libtiff5-dev libexif-dev libgsf-1-dev liblcms2-dev libxml2-dev swig libmagickcore-dev curl
|
||||||
@@ -247,7 +249,7 @@ elif [ -f /etc/redhat-release ]; then
|
|||||||
# RHEL/CentOS 7
|
# RHEL/CentOS 7
|
||||||
echo "Installing libvips dependencies via yum"
|
echo "Installing libvips dependencies via yum"
|
||||||
yum groupinstall -y "Development Tools"
|
yum groupinstall -y "Development Tools"
|
||||||
yum install -y gtk-doc libxml2-devel libjpeg-turbo-devel libpng-devel libtiff-devel libexif-devel libgsf-devel lcms-devel ImageMagick-devel gobject-introspection-devel libwebp-devel curl
|
yum install -y gtk-doc libxml2-devel libjpeg-turbo-devel libpng-devel libtiff-devel libexif-devel libgsf-devel lcms2-devel ImageMagick-devel gobject-introspection-devel libwebp-devel curl
|
||||||
install_libvips_from_source "--prefix=/usr"
|
install_libvips_from_source "--prefix=/usr"
|
||||||
;;
|
;;
|
||||||
"Red Hat Enterprise Linux release 6."*|"CentOS release 6."*|"Scientific Linux release 6."*)
|
"Red Hat Enterprise Linux release 6."*|"CentOS release 6."*|"Scientific Linux release 6."*)
|
||||||
@@ -283,12 +285,12 @@ elif [ -f /etc/system-release ]; then
|
|||||||
# Probably Amazon Linux
|
# Probably Amazon Linux
|
||||||
RELEASE=$(cat /etc/system-release)
|
RELEASE=$(cat /etc/system-release)
|
||||||
case $RELEASE in
|
case $RELEASE in
|
||||||
"Amazon Linux AMI release 2014.09"|"Amazon Linux AMI release 2015.03")
|
"Amazon Linux AMI release 2015.03"|"Amazon Linux AMI release 2015.09")
|
||||||
# Amazon Linux
|
# Amazon Linux
|
||||||
echo "Detected '$RELEASE'"
|
echo "Detected '$RELEASE'"
|
||||||
echo "Installing libvips dependencies via yum"
|
echo "Installing libvips dependencies via yum"
|
||||||
yum groupinstall -y "Development Tools"
|
yum groupinstall -y "Development Tools"
|
||||||
yum install -y gtk-doc libxml2-devel libjpeg-turbo-devel libpng-devel libtiff-devel libexif-devel libgsf-devel lcms-devel ImageMagick-devel gobject-introspection-devel libwebp-devel curl
|
yum install -y gtk-doc libxml2-devel libjpeg-turbo-devel libpng-devel libtiff-devel libexif-devel libgsf-devel lcms2-devel ImageMagick-devel gobject-introspection-devel libwebp-devel curl
|
||||||
install_libvips_from_source "--prefix=/usr"
|
install_libvips_from_source "--prefix=/usr"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ namespace sharp {
|
|||||||
Remove EXIF Orientation from image.
|
Remove EXIF Orientation from image.
|
||||||
*/
|
*/
|
||||||
void RemoveExifOrientation(VipsImage *image) {
|
void RemoveExifOrientation(VipsImage *image) {
|
||||||
vips_image_remove(image, EXIF_IFD0_ORIENTATION);
|
SetExifOrientation(image, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -16,6 +16,19 @@ using v8::Boolean;
|
|||||||
using v8::Function;
|
using v8::Function;
|
||||||
using v8::Exception;
|
using v8::Exception;
|
||||||
|
|
||||||
|
using Nan::AsyncQueueWorker;
|
||||||
|
using Nan::AsyncWorker;
|
||||||
|
using Nan::Callback;
|
||||||
|
using Nan::HandleScope;
|
||||||
|
using Nan::Utf8String;
|
||||||
|
using Nan::Has;
|
||||||
|
using Nan::Get;
|
||||||
|
using Nan::Set;
|
||||||
|
using Nan::New;
|
||||||
|
using Nan::NewBuffer;
|
||||||
|
using Nan::Null;
|
||||||
|
using Nan::Error;
|
||||||
|
|
||||||
using sharp::ImageType;
|
using sharp::ImageType;
|
||||||
using sharp::DetermineImageType;
|
using sharp::DetermineImageType;
|
||||||
using sharp::InitImage;
|
using sharp::InitImage;
|
||||||
@@ -61,10 +74,10 @@ static void DeleteBuffer(VipsObject *object, char *buffer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MetadataWorker : public NanAsyncWorker {
|
class MetadataWorker : public AsyncWorker {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MetadataWorker(NanCallback *callback, MetadataBaton *baton) : NanAsyncWorker(callback), baton(baton) {}
|
MetadataWorker(Callback *callback, MetadataBaton *baton) : AsyncWorker(callback), baton(baton) {}
|
||||||
~MetadataWorker() {}
|
~MetadataWorker() {}
|
||||||
|
|
||||||
void Execute() {
|
void Execute() {
|
||||||
@@ -129,7 +142,7 @@ class MetadataWorker : public NanAsyncWorker {
|
|||||||
size_t exifLength;
|
size_t exifLength;
|
||||||
if (!vips_image_get_blob(image, VIPS_META_EXIF_NAME, &exif, &exifLength)) {
|
if (!vips_image_get_blob(image, VIPS_META_EXIF_NAME, &exif, &exifLength)) {
|
||||||
baton->exifLength = exifLength;
|
baton->exifLength = exifLength;
|
||||||
baton->exif = new char[exifLength];
|
baton->exif = static_cast<char*>(malloc(exifLength));
|
||||||
memcpy(baton->exif, exif, exifLength);
|
memcpy(baton->exif, exif, exifLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -139,7 +152,7 @@ class MetadataWorker : public NanAsyncWorker {
|
|||||||
size_t iccLength;
|
size_t iccLength;
|
||||||
if (!vips_image_get_blob(image, VIPS_META_ICC_NAME, &icc, &iccLength)) {
|
if (!vips_image_get_blob(image, VIPS_META_ICC_NAME, &icc, &iccLength)) {
|
||||||
baton->iccLength = iccLength;
|
baton->iccLength = iccLength;
|
||||||
baton->icc = new char[iccLength];
|
baton->icc = static_cast<char*>(malloc(iccLength));
|
||||||
memcpy(baton->icc, icc, iccLength);
|
memcpy(baton->icc, icc, iccLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -152,30 +165,30 @@ class MetadataWorker : public NanAsyncWorker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HandleOKCallback () {
|
void HandleOKCallback () {
|
||||||
NanScope();
|
HandleScope();
|
||||||
|
|
||||||
Handle<Value> argv[2] = { NanNull(), NanNull() };
|
Local<Value> argv[2] = { Null(), Null() };
|
||||||
if (!baton->err.empty()) {
|
if (!baton->err.empty()) {
|
||||||
// Error
|
// Error
|
||||||
argv[0] = Exception::Error(NanNew<String>(baton->err.data(), baton->err.size()));
|
argv[0] = Error(baton->err.c_str());
|
||||||
} else {
|
} else {
|
||||||
// Metadata Object
|
// Metadata Object
|
||||||
Local<Object> info = NanNew<Object>();
|
Local<Object> info = New<Object>();
|
||||||
info->Set(NanNew<String>("format"), NanNew<String>(baton->format));
|
Set(info, New("format").ToLocalChecked(), New<String>(baton->format).ToLocalChecked());
|
||||||
info->Set(NanNew<String>("width"), NanNew<Number>(baton->width));
|
Set(info, New("width").ToLocalChecked(), New<Number>(baton->width));
|
||||||
info->Set(NanNew<String>("height"), NanNew<Number>(baton->height));
|
Set(info, New("height").ToLocalChecked(), New<Number>(baton->height));
|
||||||
info->Set(NanNew<String>("space"), NanNew<String>(baton->space));
|
Set(info, New("space").ToLocalChecked(), New<String>(baton->space).ToLocalChecked());
|
||||||
info->Set(NanNew<String>("channels"), NanNew<Number>(baton->channels));
|
Set(info, New("channels").ToLocalChecked(), New<Number>(baton->channels));
|
||||||
info->Set(NanNew<String>("hasProfile"), NanNew<Boolean>(baton->hasProfile));
|
Set(info, New("hasProfile").ToLocalChecked(), New<Boolean>(baton->hasProfile));
|
||||||
info->Set(NanNew<String>("hasAlpha"), NanNew<Boolean>(baton->hasAlpha));
|
Set(info, New("hasAlpha").ToLocalChecked(), New<Boolean>(baton->hasAlpha));
|
||||||
if (baton->orientation > 0) {
|
if (baton->orientation > 0) {
|
||||||
info->Set(NanNew<String>("orientation"), NanNew<Number>(baton->orientation));
|
Set(info, New("orientation").ToLocalChecked(), New<Number>(baton->orientation));
|
||||||
}
|
}
|
||||||
if (baton->exifLength > 0) {
|
if (baton->exifLength > 0) {
|
||||||
info->Set(NanNew<String>("exif"), NanBufferUse(baton->exif, baton->exifLength));
|
Set(info, New("exif").ToLocalChecked(), NewBuffer(baton->exif, baton->exifLength).ToLocalChecked());
|
||||||
}
|
}
|
||||||
if (baton->iccLength > 0) {
|
if (baton->iccLength > 0) {
|
||||||
info->Set(NanNew<String>("icc"), NanBufferUse(baton->icc, baton->iccLength));
|
Set(info, New("icc").ToLocalChecked(), NewBuffer(baton->icc, baton->iccLength).ToLocalChecked());
|
||||||
}
|
}
|
||||||
argv[1] = info;
|
argv[1] = info;
|
||||||
}
|
}
|
||||||
@@ -193,17 +206,17 @@ class MetadataWorker : public NanAsyncWorker {
|
|||||||
metadata(options, callback)
|
metadata(options, callback)
|
||||||
*/
|
*/
|
||||||
NAN_METHOD(metadata) {
|
NAN_METHOD(metadata) {
|
||||||
NanScope();
|
HandleScope();
|
||||||
|
|
||||||
// V8 objects are converted to non-V8 types held in the baton struct
|
// V8 objects are converted to non-V8 types held in the baton struct
|
||||||
MetadataBaton *baton = new MetadataBaton;
|
MetadataBaton *baton = new MetadataBaton;
|
||||||
Local<Object> options = args[0]->ToObject();
|
Local<Object> options = info[0].As<Object>();
|
||||||
|
|
||||||
// Input filename
|
// Input filename
|
||||||
baton->fileIn = *String::Utf8Value(options->Get(NanNew<String>("fileIn"))->ToString());
|
baton->fileIn = *Utf8String(Get(options, New("fileIn").ToLocalChecked()).ToLocalChecked());
|
||||||
// Input Buffer object
|
// Input Buffer object
|
||||||
if (options->Get(NanNew<String>("bufferIn"))->IsObject()) {
|
if (node::Buffer::HasInstance(Get(options, New("bufferIn").ToLocalChecked()).ToLocalChecked())) {
|
||||||
Local<Object> buffer = options->Get(NanNew<String>("bufferIn"))->ToObject();
|
Local<Object> buffer = Get(options, New("bufferIn").ToLocalChecked()).ToLocalChecked().As<Object>();
|
||||||
// Take a copy of the input Buffer to avoid problems with V8 heap compaction
|
// Take a copy of the input Buffer to avoid problems with V8 heap compaction
|
||||||
baton->bufferInLength = node::Buffer::Length(buffer);
|
baton->bufferInLength = node::Buffer::Length(buffer);
|
||||||
baton->bufferIn = new char[baton->bufferInLength];
|
baton->bufferIn = new char[baton->bufferInLength];
|
||||||
@@ -211,11 +224,9 @@ NAN_METHOD(metadata) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Join queue for worker thread
|
// Join queue for worker thread
|
||||||
NanCallback *callback = new NanCallback(args[1].As<v8::Function>());
|
Callback *callback = new Callback(info[1].As<Function>());
|
||||||
NanAsyncQueueWorker(new MetadataWorker(callback, baton));
|
AsyncQueueWorker(new MetadataWorker(callback, baton));
|
||||||
|
|
||||||
// Increment queued task counter
|
// Increment queued task counter
|
||||||
g_atomic_int_inc(&counterQueue);
|
g_atomic_int_inc(&counterQueue);
|
||||||
|
|
||||||
NanReturnUndefined();
|
|
||||||
}
|
}
|
||||||
|
|||||||
194
src/pipeline.cc
@@ -22,6 +22,20 @@ using v8::Array;
|
|||||||
using v8::Function;
|
using v8::Function;
|
||||||
using v8::Exception;
|
using v8::Exception;
|
||||||
|
|
||||||
|
using Nan::AsyncQueueWorker;
|
||||||
|
using Nan::AsyncWorker;
|
||||||
|
using Nan::Callback;
|
||||||
|
using Nan::HandleScope;
|
||||||
|
using Nan::Utf8String;
|
||||||
|
using Nan::Has;
|
||||||
|
using Nan::Get;
|
||||||
|
using Nan::Set;
|
||||||
|
using Nan::To;
|
||||||
|
using Nan::New;
|
||||||
|
using Nan::CopyBuffer;
|
||||||
|
using Nan::Null;
|
||||||
|
using Nan::Equals;
|
||||||
|
|
||||||
using sharp::Composite;
|
using sharp::Composite;
|
||||||
using sharp::Premultiply;
|
using sharp::Premultiply;
|
||||||
using sharp::Unpremultiply;
|
using sharp::Unpremultiply;
|
||||||
@@ -165,11 +179,11 @@ static void DeleteBuffer(VipsObject *object, char *buffer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PipelineWorker : public NanAsyncWorker {
|
class PipelineWorker : public AsyncWorker {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PipelineWorker(NanCallback *callback, PipelineBaton *baton, NanCallback *queueListener) :
|
PipelineWorker(Callback *callback, PipelineBaton *baton, Callback *queueListener) :
|
||||||
NanAsyncWorker(callback), baton(baton), queueListener(queueListener) {}
|
AsyncWorker(callback), baton(baton), queueListener(queueListener) {}
|
||||||
~PipelineWorker() {}
|
~PipelineWorker() {}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -236,11 +250,16 @@ class PipelineWorker : public NanAsyncWorker {
|
|||||||
// Calculate angle of rotation
|
// Calculate angle of rotation
|
||||||
Angle rotation;
|
Angle rotation;
|
||||||
bool flip;
|
bool flip;
|
||||||
std::tie(rotation, flip) = CalculateRotationAndFlip(baton->angle, image);
|
bool flop;
|
||||||
|
std::tie(rotation, flip, flop) = CalculateRotationAndFlip(baton->angle, image);
|
||||||
if (flip && !baton->flip) {
|
if (flip && !baton->flip) {
|
||||||
// Add flip operation due to EXIF mirroring
|
// Add flip operation due to EXIF mirroring
|
||||||
baton->flip = TRUE;
|
baton->flip = TRUE;
|
||||||
}
|
}
|
||||||
|
if (flop && !baton->flop) {
|
||||||
|
// Add flip operation due to EXIF mirroring
|
||||||
|
baton->flop = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
// Rotate pre-extract
|
// Rotate pre-extract
|
||||||
if (baton->rotateBeforePreExtract && rotation != Angle::D0) {
|
if (baton->rotateBeforePreExtract && rotation != Angle::D0) {
|
||||||
@@ -963,12 +982,12 @@ class PipelineWorker : public NanAsyncWorker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HandleOKCallback () {
|
void HandleOKCallback () {
|
||||||
NanScope();
|
HandleScope();
|
||||||
|
|
||||||
Handle<Value> argv[3] = { NanNull(), NanNull(), NanNull() };
|
Local<Value> argv[3] = { Null(), Null(), Null() };
|
||||||
if (!baton->err.empty()) {
|
if (!baton->err.empty()) {
|
||||||
// Error
|
// Error
|
||||||
argv[0] = Exception::Error(NanNew<String>(baton->err.data(), baton->err.size()));
|
argv[0] = Nan::Error(baton->err.c_str());
|
||||||
} else {
|
} else {
|
||||||
int width = baton->width;
|
int width = baton->width;
|
||||||
int height = baton->height;
|
int height = baton->height;
|
||||||
@@ -981,32 +1000,33 @@ class PipelineWorker : public NanAsyncWorker {
|
|||||||
height = baton->heightPost;
|
height = baton->heightPost;
|
||||||
}
|
}
|
||||||
// Info Object
|
// Info Object
|
||||||
Local<Object> info = NanNew<Object>();
|
Local<Object> info = New<Object>();
|
||||||
info->Set(NanNew<String>("format"), NanNew<String>(baton->outputFormat));
|
Set(info, New("format").ToLocalChecked(), New<String>(baton->outputFormat).ToLocalChecked());
|
||||||
info->Set(NanNew<String>("width"), NanNew<Uint32>(static_cast<uint32_t>(width)));
|
Set(info, New("width").ToLocalChecked(), New<Uint32>(static_cast<uint32_t>(width)));
|
||||||
info->Set(NanNew<String>("height"), NanNew<Uint32>(static_cast<uint32_t>(height)));
|
Set(info, New("height").ToLocalChecked(), New<Uint32>(static_cast<uint32_t>(height)));
|
||||||
|
|
||||||
if (baton->bufferOutLength > 0) {
|
if (baton->bufferOutLength > 0) {
|
||||||
// Copy data to new Buffer
|
// Copy data to new Buffer
|
||||||
argv[1] = NanNewBufferHandle(static_cast<char*>(baton->bufferOut), baton->bufferOutLength);
|
argv[1] = CopyBuffer(static_cast<char*>(baton->bufferOut), baton->bufferOutLength).ToLocalChecked();
|
||||||
// bufferOut was allocated via g_malloc
|
// bufferOut was allocated via g_malloc
|
||||||
g_free(baton->bufferOut);
|
g_free(baton->bufferOut);
|
||||||
// Add buffer size to info
|
// Add buffer size to info
|
||||||
info->Set(NanNew<String>("size"), NanNew<Uint32>(static_cast<uint32_t>(baton->bufferOutLength)));
|
Set(info, New("size").ToLocalChecked(), New<Uint32>(static_cast<uint32_t>(baton->bufferOutLength)));
|
||||||
argv[2] = info;
|
argv[2] = info;
|
||||||
} else {
|
} else {
|
||||||
// Add file size to info
|
// Add file size to info
|
||||||
GStatBuf st;
|
GStatBuf st;
|
||||||
g_stat(baton->output.c_str(), &st);
|
g_stat(baton->output.c_str(), &st);
|
||||||
info->Set(NanNew<String>("size"), NanNew<Uint32>(static_cast<uint32_t>(st.st_size)));
|
Set(info, New("size").ToLocalChecked(), New<Uint32>(static_cast<uint32_t>(st.st_size)));
|
||||||
argv[1] = info;
|
argv[1] = info;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete baton;
|
delete baton;
|
||||||
|
// to here
|
||||||
|
|
||||||
// Decrement processing task counter
|
// Decrement processing task counter
|
||||||
g_atomic_int_dec_and_test(&counterProcess);
|
g_atomic_int_dec_and_test(&counterProcess);
|
||||||
Handle<Value> queueLength[1] = { NanNew<Uint32>(counterQueue) };
|
Local<Value> queueLength[1] = { New<Uint32>(counterQueue) };
|
||||||
queueListener->Call(1, queueLength);
|
queueListener->Call(1, queueLength);
|
||||||
delete queueListener;
|
delete queueListener;
|
||||||
|
|
||||||
@@ -1016,7 +1036,7 @@ class PipelineWorker : public NanAsyncWorker {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
PipelineBaton *baton;
|
PipelineBaton *baton;
|
||||||
NanCallback *queueListener;
|
Callback *queueListener;
|
||||||
VipsObject *hook;
|
VipsObject *hook;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1026,18 +1046,19 @@ class PipelineWorker : public NanAsyncWorker {
|
|||||||
2. Use input image EXIF Orientation header - supports mirroring
|
2. Use input image EXIF Orientation header - supports mirroring
|
||||||
3. Otherwise default to zero, i.e. no rotation
|
3. Otherwise default to zero, i.e. no rotation
|
||||||
*/
|
*/
|
||||||
std::tuple<Angle, bool>
|
std::tuple<Angle, bool, bool>
|
||||||
CalculateRotationAndFlip(int const angle, VipsImage const *input) {
|
CalculateRotationAndFlip(int const angle, VipsImage const *input) {
|
||||||
Angle rotate = Angle::D0;
|
Angle rotate = Angle::D0;
|
||||||
bool flip = FALSE;
|
bool flip = FALSE;
|
||||||
|
bool flop = FALSE;
|
||||||
if (angle == -1) {
|
if (angle == -1) {
|
||||||
switch(ExifOrientation(input)) {
|
switch(ExifOrientation(input)) {
|
||||||
case 6: rotate = Angle::D90; break;
|
case 6: rotate = Angle::D90; break;
|
||||||
case 3: rotate = Angle::D180; break;
|
case 3: rotate = Angle::D180; break;
|
||||||
case 8: rotate = Angle::D270; break;
|
case 8: rotate = Angle::D270; break;
|
||||||
case 2: flip = TRUE; break; // flip 1
|
case 2: flop = TRUE; break; // flop 1
|
||||||
case 7: flip = TRUE; rotate = Angle::D90; break; // flip 6
|
case 7: flip = TRUE; rotate = Angle::D90; break; // flip 6
|
||||||
case 4: flip = TRUE; rotate = Angle::D180; break; // flip 3
|
case 4: flop = TRUE; rotate = Angle::D180; break; // flop 3
|
||||||
case 5: flip = TRUE; rotate = Angle::D270; break; // flip 8
|
case 5: flip = TRUE; rotate = Angle::D270; break; // flip 8
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1049,7 +1070,7 @@ class PipelineWorker : public NanAsyncWorker {
|
|||||||
rotate = Angle::D270;
|
rotate = Angle::D270;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return std::make_tuple(rotate, flip);
|
return std::make_tuple(rotate, flip, flop);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1075,6 +1096,16 @@ class PipelineWorker : public NanAsyncWorker {
|
|||||||
case 4: // West
|
case 4: // West
|
||||||
top = (inHeight - outHeight + 1) / 2;
|
top = (inHeight - outHeight + 1) / 2;
|
||||||
break;
|
break;
|
||||||
|
case 5: // Northeast
|
||||||
|
left = inWidth - outWidth;
|
||||||
|
break;
|
||||||
|
case 6: // Southeast
|
||||||
|
left = inWidth - outWidth;
|
||||||
|
top = inHeight - outHeight;
|
||||||
|
case 7: // Southwest
|
||||||
|
top = inHeight - outHeight;
|
||||||
|
case 8: // Northwest
|
||||||
|
break;
|
||||||
default: // Centre
|
default: // Centre
|
||||||
left = (inWidth - outWidth + 1) / 2;
|
left = (inWidth - outWidth + 1) / 2;
|
||||||
top = (inHeight - outHeight + 1) / 2;
|
top = (inHeight - outHeight + 1) / 2;
|
||||||
@@ -1126,102 +1157,103 @@ class PipelineWorker : public NanAsyncWorker {
|
|||||||
pipeline(options, output, callback)
|
pipeline(options, output, callback)
|
||||||
*/
|
*/
|
||||||
NAN_METHOD(pipeline) {
|
NAN_METHOD(pipeline) {
|
||||||
NanScope();
|
HandleScope();
|
||||||
|
|
||||||
// V8 objects are converted to non-V8 types held in the baton struct
|
// V8 objects are converted to non-V8 types held in the baton struct
|
||||||
PipelineBaton *baton = new PipelineBaton;
|
PipelineBaton *baton = new PipelineBaton;
|
||||||
Local<Object> options = args[0]->ToObject();
|
Local<Object> options = info[0].As<Object>();
|
||||||
|
|
||||||
// Input filename
|
// Input filename
|
||||||
baton->fileIn = *String::Utf8Value(options->Get(NanNew<String>("fileIn"))->ToString());
|
baton->fileIn = *Utf8String(Get(options, New("fileIn").ToLocalChecked()).ToLocalChecked());
|
||||||
baton->accessMethod = options->Get(NanNew<String>("sequentialRead"))->BooleanValue() ? VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
|
baton->accessMethod =
|
||||||
|
To<bool>(Get(options, New("sequentialRead").ToLocalChecked()).ToLocalChecked()).FromJust() ?
|
||||||
|
VIPS_ACCESS_SEQUENTIAL : VIPS_ACCESS_RANDOM;
|
||||||
// Input Buffer object
|
// Input Buffer object
|
||||||
if (options->Get(NanNew<String>("bufferIn"))->IsObject()) {
|
if (node::Buffer::HasInstance(Get(options, New("bufferIn").ToLocalChecked()).ToLocalChecked())) {
|
||||||
Local<Object> buffer = options->Get(NanNew<String>("bufferIn"))->ToObject();
|
Local<Object> buffer = Get(options, New("bufferIn").ToLocalChecked()).ToLocalChecked().As<Object>();
|
||||||
// Take a copy of the input Buffer to avoid problems with V8 heap compaction
|
// Take a copy of the input Buffer to avoid problems with V8 heap compaction
|
||||||
baton->bufferInLength = node::Buffer::Length(buffer);
|
baton->bufferInLength = node::Buffer::Length(buffer);
|
||||||
baton->bufferIn = new char[baton->bufferInLength];
|
baton->bufferIn = new char[baton->bufferInLength];
|
||||||
memcpy(baton->bufferIn, node::Buffer::Data(buffer), baton->bufferInLength);
|
memcpy(baton->bufferIn, node::Buffer::Data(buffer), baton->bufferInLength);
|
||||||
}
|
}
|
||||||
// ICC profile to use when input CMYK image has no embedded profile
|
// ICC profile to use when input CMYK image has no embedded profile
|
||||||
baton->iccProfilePath = *String::Utf8Value(options->Get(NanNew<String>("iccProfilePath"))->ToString());
|
baton->iccProfilePath = *Utf8String(Get(options, New("iccProfilePath").ToLocalChecked()).ToLocalChecked());
|
||||||
// Limit input images to a given number of pixels, where pixels = width * height
|
// Limit input images to a given number of pixels, where pixels = width * height
|
||||||
baton->limitInputPixels = options->Get(NanNew<String>("limitInputPixels"))->Int32Value();
|
baton->limitInputPixels = To<int32_t>(Get(options, New("limitInputPixels").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
// Extract image options
|
// Extract image options
|
||||||
baton->topOffsetPre = options->Get(NanNew<String>("topOffsetPre"))->Int32Value();
|
baton->topOffsetPre = To<int32_t>(Get(options, New("topOffsetPre").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->leftOffsetPre = options->Get(NanNew<String>("leftOffsetPre"))->Int32Value();
|
baton->leftOffsetPre = To<int32_t>(Get(options, New("leftOffsetPre").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->widthPre = options->Get(NanNew<String>("widthPre"))->Int32Value();
|
baton->widthPre = To<int32_t>(Get(options, New("widthPre").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->heightPre = options->Get(NanNew<String>("heightPre"))->Int32Value();
|
baton->heightPre = To<int32_t>(Get(options, New("heightPre").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->topOffsetPost = options->Get(NanNew<String>("topOffsetPost"))->Int32Value();
|
baton->topOffsetPost = To<int32_t>(Get(options, New("topOffsetPost").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->leftOffsetPost = options->Get(NanNew<String>("leftOffsetPost"))->Int32Value();
|
baton->leftOffsetPost = To<int32_t>(Get(options, New("leftOffsetPost").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->widthPost = options->Get(NanNew<String>("widthPost"))->Int32Value();
|
baton->widthPost = To<int32_t>(Get(options, New("widthPost").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->heightPost = options->Get(NanNew<String>("heightPost"))->Int32Value();
|
baton->heightPost = To<int32_t>(Get(options, New("heightPost").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
// Output image dimensions
|
// Output image dimensions
|
||||||
baton->width = options->Get(NanNew<String>("width"))->Int32Value();
|
baton->width = To<int32_t>(Get(options, New("width").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->height = options->Get(NanNew<String>("height"))->Int32Value();
|
baton->height = To<int32_t>(Get(options, New("height").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
// Canvas option
|
// Canvas option
|
||||||
Local<String> canvas = options->Get(NanNew<String>("canvas"))->ToString();
|
Local<String> canvas = To<String>(Get(options, New("canvas").ToLocalChecked()).ToLocalChecked()).ToLocalChecked();
|
||||||
if (canvas->Equals(NanNew<String>("crop"))) {
|
if (Equals(canvas, New("crop").ToLocalChecked()).FromJust()) {
|
||||||
baton->canvas = Canvas::CROP;
|
baton->canvas = Canvas::CROP;
|
||||||
} else if (canvas->Equals(NanNew<String>("embed"))) {
|
} else if (Equals(canvas, New("embed").ToLocalChecked()).FromJust()) {
|
||||||
baton->canvas = Canvas::EMBED;
|
baton->canvas = Canvas::EMBED;
|
||||||
} else if (canvas->Equals(NanNew<String>("max"))) {
|
} else if (Equals(canvas, New("max").ToLocalChecked()).FromJust()) {
|
||||||
baton->canvas = Canvas::MAX;
|
baton->canvas = Canvas::MAX;
|
||||||
} else if (canvas->Equals(NanNew<String>("min"))) {
|
} else if (Equals(canvas, New("min").ToLocalChecked()).FromJust()) {
|
||||||
baton->canvas = Canvas::MIN;
|
baton->canvas = Canvas::MIN;
|
||||||
} else if (canvas->Equals(NanNew<String>("ignore_aspect"))) {
|
} else if (Equals(canvas, New("ignore_aspect").ToLocalChecked()).FromJust()) {
|
||||||
baton->canvas = Canvas::IGNORE_ASPECT;
|
baton->canvas = Canvas::IGNORE_ASPECT;
|
||||||
}
|
}
|
||||||
// Background colour
|
// Background colour
|
||||||
Local<Array> background = Local<Array>::Cast(options->Get(NanNew<String>("background")));
|
Local<Object> background = Get(options, New("background").ToLocalChecked()).ToLocalChecked().As<Object>();
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
baton->background[i] = background->Get(i)->NumberValue();
|
baton->background[i] = To<int32_t>(Get(background, i).ToLocalChecked()).FromJust();
|
||||||
}
|
}
|
||||||
// Overlay options
|
// Overlay options
|
||||||
baton->overlayPath = *String::Utf8Value(options->Get(NanNew<String>("overlayPath"))->ToString());
|
baton->overlayPath = *Utf8String(Get(options, New("overlayPath").ToLocalChecked()).ToLocalChecked());
|
||||||
// Resize options
|
// Resize options
|
||||||
baton->withoutEnlargement = options->Get(NanNew<String>("withoutEnlargement"))->BooleanValue();
|
baton->withoutEnlargement = To<bool>(Get(options, New("withoutEnlargement").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->gravity = options->Get(NanNew<String>("gravity"))->Int32Value();
|
baton->gravity = To<int32_t>(Get(options, New("gravity").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->interpolator = *String::Utf8Value(options->Get(NanNew<String>("interpolator"))->ToString());
|
baton->interpolator = *Utf8String(Get(options, New("interpolator").ToLocalChecked()).ToLocalChecked());
|
||||||
// Operators
|
// Operators
|
||||||
baton->flatten = options->Get(NanNew<String>("flatten"))->BooleanValue();
|
baton->flatten = To<bool>(Get(options, New("flatten").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->blurSigma = options->Get(NanNew<String>("blurSigma"))->NumberValue();
|
baton->blurSigma = To<double>(Get(options, New("blurSigma").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->sharpenRadius = options->Get(NanNew<String>("sharpenRadius"))->Int32Value();
|
baton->sharpenRadius = To<int32_t>(Get(options, New("sharpenRadius").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->sharpenFlat = options->Get(NanNew<String>("sharpenFlat"))->NumberValue();
|
baton->sharpenFlat = To<double>(Get(options, New("sharpenFlat").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->sharpenJagged = options->Get(NanNew<String>("sharpenJagged"))->NumberValue();
|
baton->sharpenJagged = To<double>(Get(options, New("sharpenJagged").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->gamma = options->Get(NanNew<String>("gamma"))->NumberValue();
|
baton->gamma = To<int32_t>(Get(options, New("gamma").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->greyscale = options->Get(NanNew<String>("greyscale"))->BooleanValue();
|
baton->greyscale = To<bool>(Get(options, New("greyscale").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->normalize = options->Get(NanNew<String>("normalize"))->BooleanValue();
|
baton->normalize = To<bool>(Get(options, New("normalize").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->angle = options->Get(NanNew<String>("angle"))->Int32Value();
|
baton->angle = To<int32_t>(Get(options, New("angle").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->rotateBeforePreExtract = options->Get(NanNew<String>("rotateBeforePreExtract"))->BooleanValue();
|
baton->rotateBeforePreExtract = To<bool>(Get(options, New("rotateBeforePreExtract").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->flip = options->Get(NanNew<String>("flip"))->BooleanValue();
|
baton->flip = To<bool>(Get(options, New("flip").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->flop = options->Get(NanNew<String>("flop"))->BooleanValue();
|
baton->flop = To<bool>(Get(options, New("flop").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
// Output options
|
// Output options
|
||||||
baton->progressive = options->Get(NanNew<String>("progressive"))->BooleanValue();
|
baton->progressive = To<bool>(Get(options, New("progressive").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->quality = options->Get(NanNew<String>("quality"))->Int32Value();
|
baton->quality = To<int32_t>(Get(options, New("quality").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->compressionLevel = options->Get(NanNew<String>("compressionLevel"))->Int32Value();
|
baton->compressionLevel = To<int32_t>(Get(options, New("compressionLevel").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->withoutAdaptiveFiltering = options->Get(NanNew<String>("withoutAdaptiveFiltering"))->BooleanValue();
|
baton->withoutAdaptiveFiltering = To<bool>(Get(options, New("withoutAdaptiveFiltering").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->withoutChromaSubsampling = options->Get(NanNew<String>("withoutChromaSubsampling"))->BooleanValue();
|
baton->withoutChromaSubsampling = To<bool>(Get(options, New("withoutChromaSubsampling").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->trellisQuantisation = options->Get(NanNew<String>("trellisQuantisation"))->BooleanValue();
|
baton->trellisQuantisation = To<bool>(Get(options, New("trellisQuantisation").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->overshootDeringing = options->Get(NanNew<String>("overshootDeringing"))->BooleanValue();
|
baton->overshootDeringing = To<bool>(Get(options, New("overshootDeringing").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->optimiseScans = options->Get(NanNew<String>("optimiseScans"))->BooleanValue();
|
baton->optimiseScans = To<bool>(Get(options, New("optimiseScans").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->withMetadata = options->Get(NanNew<String>("withMetadata"))->BooleanValue();
|
baton->withMetadata = To<bool>(Get(options, New("withMetadata").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->withMetadataOrientation = options->Get(NanNew<String>("withMetadataOrientation"))->Int32Value();
|
baton->withMetadataOrientation = To<int32_t>(Get(options, New("withMetadataOrientation").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
// Output filename or __format for Buffer
|
// Output filename or __format for Buffer
|
||||||
baton->output = *String::Utf8Value(options->Get(NanNew<String>("output"))->ToString());
|
baton->output = *Utf8String(Get(options, New("output").ToLocalChecked()).ToLocalChecked());
|
||||||
baton->tileSize = options->Get(NanNew<String>("tileSize"))->Int32Value();
|
baton->tileSize = To<int32_t>(Get(options, New("tileSize").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
baton->tileOverlap = options->Get(NanNew<String>("tileOverlap"))->Int32Value();
|
baton->tileOverlap = To<int32_t>(Get(options, New("tileOverlap").ToLocalChecked()).ToLocalChecked()).FromJust();
|
||||||
// Function to notify of queue length changes
|
// Function to notify of queue length changes
|
||||||
NanCallback *queueListener = new NanCallback(Handle<Function>::Cast(options->Get(NanNew<String>("queueListener"))));
|
Callback *queueListener = new Callback(Get(options, New("queueListener").ToLocalChecked()).ToLocalChecked().As<Function>());
|
||||||
|
|
||||||
// Join queue for worker thread
|
// Join queue for worker thread
|
||||||
NanCallback *callback = new NanCallback(args[1].As<Function>());
|
Callback *callback = new Callback(info[1].As<Function>());
|
||||||
NanAsyncQueueWorker(new PipelineWorker(callback, baton, queueListener));
|
AsyncQueueWorker(new PipelineWorker(callback, baton, queueListener));
|
||||||
|
|
||||||
// Increment queued task counter
|
// Increment queued task counter
|
||||||
g_atomic_int_inc(&counterQueue);
|
g_atomic_int_inc(&counterQueue);
|
||||||
Handle<Value> queueLength[1] = { NanNew<Uint32>(counterQueue) };
|
Local<Value> queueLength[1] = { New<Uint32>(counterQueue) };
|
||||||
queueListener->Call(1, queueLength);
|
queueListener->Call(1, queueLength);
|
||||||
|
|
||||||
NanReturnUndefined();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
27
src/sharp.cc
@@ -8,8 +8,7 @@
|
|||||||
#include "pipeline.h"
|
#include "pipeline.h"
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
extern "C" void init(v8::Handle<v8::Object> target) {
|
NAN_MODULE_INIT(init) {
|
||||||
NanScope();
|
|
||||||
vips_init("sharp");
|
vips_init("sharp");
|
||||||
|
|
||||||
// Set libvips operation cache limits
|
// Set libvips operation cache limits
|
||||||
@@ -17,14 +16,22 @@ extern "C" void init(v8::Handle<v8::Object> target) {
|
|||||||
vips_cache_set_max(500); // 500 operations
|
vips_cache_set_max(500); // 500 operations
|
||||||
|
|
||||||
// Methods available to JavaScript
|
// Methods available to JavaScript
|
||||||
NODE_SET_METHOD(target, "metadata", metadata);
|
Nan::Set(target, Nan::New("metadata").ToLocalChecked(),
|
||||||
NODE_SET_METHOD(target, "pipeline", pipeline);
|
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(metadata)).ToLocalChecked());
|
||||||
NODE_SET_METHOD(target, "cache", cache);
|
Nan::Set(target, Nan::New("pipeline").ToLocalChecked(),
|
||||||
NODE_SET_METHOD(target, "concurrency", concurrency);
|
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(pipeline)).ToLocalChecked());
|
||||||
NODE_SET_METHOD(target, "counters", counters);
|
Nan::Set(target, Nan::New("cache").ToLocalChecked(),
|
||||||
NODE_SET_METHOD(target, "libvipsVersion", libvipsVersion);
|
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(cache)).ToLocalChecked());
|
||||||
NODE_SET_METHOD(target, "format", format);
|
Nan::Set(target, Nan::New("concurrency").ToLocalChecked(),
|
||||||
NODE_SET_METHOD(target, "_maxColourDistance", _maxColourDistance);
|
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(concurrency)).ToLocalChecked());
|
||||||
|
Nan::Set(target, Nan::New("counters").ToLocalChecked(),
|
||||||
|
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(counters)).ToLocalChecked());
|
||||||
|
Nan::Set(target, Nan::New("libvipsVersion").ToLocalChecked(),
|
||||||
|
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(libvipsVersion)).ToLocalChecked());
|
||||||
|
Nan::Set(target, Nan::New("format").ToLocalChecked(),
|
||||||
|
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(format)).ToLocalChecked());
|
||||||
|
Nan::Set(target, Nan::New("_maxColourDistance").ToLocalChecked(),
|
||||||
|
Nan::GetFunction(Nan::New<v8::FunctionTemplate>(_maxColourDistance)).ToLocalChecked());
|
||||||
}
|
}
|
||||||
|
|
||||||
NODE_MODULE(sharp, init)
|
NODE_MODULE(sharp, init)
|
||||||
|
|||||||
181
src/utilities.cc
@@ -13,48 +13,50 @@ using v8::Number;
|
|||||||
using v8::String;
|
using v8::String;
|
||||||
using v8::Boolean;
|
using v8::Boolean;
|
||||||
|
|
||||||
|
using Nan::HandleScope;
|
||||||
|
using Nan::New;
|
||||||
|
using Nan::Set;
|
||||||
|
using Nan::ThrowError;
|
||||||
|
using Nan::To;
|
||||||
|
using Nan::Utf8String;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Get and set cache memory and item limits
|
Get and set cache memory and item limits
|
||||||
*/
|
*/
|
||||||
NAN_METHOD(cache) {
|
NAN_METHOD(cache) {
|
||||||
NanScope();
|
HandleScope();
|
||||||
|
|
||||||
// Set cache memory limit
|
// Set cache memory limit
|
||||||
if (args[0]->IsInt32()) {
|
if (info[0]->IsInt32()) {
|
||||||
int newMax = args[0]->Int32Value() * 1048576;
|
vips_cache_set_max_mem(To<int32_t>(info[0]).FromJust() * 1048576);
|
||||||
int oldMax = vips_cache_get_max_mem();
|
|
||||||
vips_cache_set_max_mem(newMax);
|
|
||||||
|
|
||||||
// Notify the V8 garbage collector of delta in max cache size
|
|
||||||
NanAdjustExternalMemory(newMax - oldMax);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set cache items limit
|
// Set cache items limit
|
||||||
if (args[1]->IsInt32()) {
|
if (info[1]->IsInt32()) {
|
||||||
vips_cache_set_max(args[1]->Int32Value());
|
vips_cache_set_max(To<int32_t>(info[1]).FromJust());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get cache statistics
|
// Get cache statistics
|
||||||
Local<Object> cache = NanNew<Object>();
|
Local<Object> cache = New<Object>();
|
||||||
cache->Set(NanNew<String>("current"), NanNew<Number>(vips_tracked_get_mem() / 1048576));
|
Set(cache, New("current").ToLocalChecked(), New<Number>(vips_tracked_get_mem() / 1048576));
|
||||||
cache->Set(NanNew<String>("high"), NanNew<Number>(vips_tracked_get_mem_highwater() / 1048576));
|
Set(cache, New("high").ToLocalChecked(), New<Number>(vips_tracked_get_mem_highwater() / 1048576));
|
||||||
cache->Set(NanNew<String>("memory"), NanNew<Number>(vips_cache_get_max_mem() / 1048576));
|
Set(cache, New("memory").ToLocalChecked(), New<Number>(vips_cache_get_max_mem() / 1048576));
|
||||||
cache->Set(NanNew<String>("items"), NanNew<Number>(vips_cache_get_max()));
|
Set(cache, New("items").ToLocalChecked(), New<Number>(vips_cache_get_max()));
|
||||||
NanReturnValue(cache);
|
info.GetReturnValue().Set(cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Get and set size of thread pool
|
Get and set size of thread pool
|
||||||
*/
|
*/
|
||||||
NAN_METHOD(concurrency) {
|
NAN_METHOD(concurrency) {
|
||||||
NanScope();
|
HandleScope();
|
||||||
|
|
||||||
// Set concurrency
|
// Set concurrency
|
||||||
if (args[0]->IsInt32()) {
|
if (info[0]->IsInt32()) {
|
||||||
vips_concurrency_set(args[0]->Int32Value());
|
vips_concurrency_set(To<int32_t>(info[0]).FromJust());
|
||||||
}
|
}
|
||||||
// Get concurrency
|
// Get concurrency
|
||||||
NanReturnValue(NanNew<Number>(vips_concurrency_get()));
|
info.GetReturnValue().Set(New<Number>(vips_concurrency_get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -64,84 +66,89 @@ NAN_METHOD(counters) {
|
|||||||
using sharp::counterProcess;
|
using sharp::counterProcess;
|
||||||
using sharp::counterQueue;
|
using sharp::counterQueue;
|
||||||
|
|
||||||
NanScope();
|
HandleScope();
|
||||||
Local<Object> counters = NanNew<Object>();
|
Local<Object> counters = New<Object>();
|
||||||
counters->Set(NanNew<String>("queue"), NanNew<Number>(counterQueue));
|
Set(counters, New("queue").ToLocalChecked(), New<Number>(counterQueue));
|
||||||
counters->Set(NanNew<String>("process"), NanNew<Number>(counterProcess));
|
Set(counters, New("process").ToLocalChecked(), New<Number>(counterProcess));
|
||||||
NanReturnValue(counters);
|
info.GetReturnValue().Set(counters);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Get libvips version
|
Get libvips version
|
||||||
*/
|
*/
|
||||||
NAN_METHOD(libvipsVersion) {
|
NAN_METHOD(libvipsVersion) {
|
||||||
NanScope();
|
HandleScope();
|
||||||
char version[9];
|
char version[9];
|
||||||
g_snprintf(version, sizeof(version), "%d.%d.%d", vips_version(0), vips_version(1), vips_version(2));
|
g_snprintf(version, sizeof(version), "%d.%d.%d", vips_version(0), vips_version(1), vips_version(2));
|
||||||
NanReturnValue(NanNew<String>(version));
|
info.GetReturnValue().Set(New(version).ToLocalChecked());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Get available input/output file/buffer/stream formats
|
Get available input/output file/buffer/stream formats
|
||||||
*/
|
*/
|
||||||
NAN_METHOD(format) {
|
NAN_METHOD(format) {
|
||||||
NanScope();
|
HandleScope();
|
||||||
|
|
||||||
// Attribute names
|
// Attribute names
|
||||||
Local<String> attrId = NanNew<String>("id");
|
Local<String> attrId = New("id").ToLocalChecked();
|
||||||
Local<String> attrInput = NanNew<String>("input");
|
Local<String> attrInput = New("input").ToLocalChecked();
|
||||||
Local<String> attrOutput = NanNew<String>("output");
|
Local<String> attrOutput = New("output").ToLocalChecked();
|
||||||
Local<String> attrFile = NanNew<String>("file");
|
Local<String> attrFile = New("file").ToLocalChecked();
|
||||||
Local<String> attrBuffer = NanNew<String>("buffer");
|
Local<String> attrBuffer = New("buffer").ToLocalChecked();
|
||||||
Local<String> attrStream = NanNew<String>("stream");
|
Local<String> attrStream = New("stream").ToLocalChecked();
|
||||||
|
|
||||||
// Which load/save operations are available for each compressed format?
|
// Which load/save operations are available for each compressed format?
|
||||||
Local<Object> format = NanNew<Object>();
|
Local<Object> format = New<Object>();
|
||||||
for (std::string f : {"jpeg", "png", "webp", "tiff", "magick", "openslide", "dz"}) {
|
for (std::string f : {"jpeg", "png", "webp", "tiff", "magick", "openslide", "dz"}) {
|
||||||
// Input
|
// Input
|
||||||
Local<Object> input = NanNew<Object>();
|
Local<Boolean> hasInputFile =
|
||||||
input->Set(attrFile, NanNew<Boolean>(
|
New<Boolean>(vips_type_find("VipsOperation", (f + "load").c_str()));
|
||||||
vips_type_find("VipsOperation", (f + "load").c_str())));
|
Local<Boolean> hasInputBuffer =
|
||||||
input->Set(attrBuffer, NanNew<Boolean>(
|
New<Boolean>(vips_type_find("VipsOperation", (f + "load_buffer").c_str()));
|
||||||
vips_type_find("VipsOperation", (f + "load_buffer").c_str())));
|
Local<Object> input = New<Object>();
|
||||||
input->Set(attrStream, input->Get(attrBuffer));
|
Set(input, attrFile, hasInputFile);
|
||||||
|
Set(input, attrBuffer, hasInputBuffer);
|
||||||
|
Set(input, attrStream, hasInputBuffer);
|
||||||
// Output
|
// Output
|
||||||
Local<Object> output = NanNew<Object>();
|
Local<Boolean> hasOutputFile =
|
||||||
output->Set(attrFile, NanNew<Boolean>(
|
New<Boolean>(vips_type_find("VipsOperation", (f + "save").c_str()));
|
||||||
vips_type_find("VipsOperation", (f + "save").c_str())));
|
Local<Boolean> hasOutputBuffer =
|
||||||
output->Set(attrBuffer, NanNew<Boolean>(
|
New<Boolean>(vips_type_find("VipsOperation", (f + "save_buffer").c_str()));
|
||||||
vips_type_find("VipsOperation", (f + "save_buffer").c_str())));
|
Local<Object> output = New<Object>();
|
||||||
output->Set(attrStream, output->Get(attrBuffer));
|
Set(output, attrFile, hasOutputFile);
|
||||||
|
Set(output, attrBuffer, hasOutputBuffer);
|
||||||
|
Set(output, attrStream, hasOutputBuffer);
|
||||||
// Other attributes
|
// Other attributes
|
||||||
Local<Object> container = NanNew<Object>();
|
Local<Object> container = New<Object>();
|
||||||
Local<String> formatId = NanNew<String>(f);
|
Local<String> formatId = New(f).ToLocalChecked();
|
||||||
container->Set(attrId, formatId);
|
Set(container, attrId, formatId);
|
||||||
container->Set(attrInput, input);
|
Set(container, attrInput, input);
|
||||||
container->Set(attrOutput, output);
|
Set(container, attrOutput, output);
|
||||||
// Add to set of formats
|
// Add to set of formats
|
||||||
format->Set(formatId, container);
|
Set(format, formatId, container);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raw, uncompressed data
|
// Raw, uncompressed data
|
||||||
Local<Object> raw = NanNew<Object>();
|
Local<Object> raw = New<Object>();
|
||||||
raw->Set(attrId, NanNew<String>("raw"));
|
Local<String> rawId = New("raw").ToLocalChecked();
|
||||||
format->Set(NanNew<String>("raw"), raw);
|
Set(raw, attrId, rawId);
|
||||||
|
Set(format, rawId, raw);
|
||||||
// No support for raw input yet, so always false
|
// No support for raw input yet, so always false
|
||||||
Local<Boolean> unsupported = NanNew<Boolean>(false);
|
Local<Boolean> unsupported = New<Boolean>(false);
|
||||||
Local<Object> rawInput = NanNew<Object>();
|
Local<Object> rawInput = New<Object>();
|
||||||
rawInput->Set(attrFile, unsupported);
|
Set(rawInput, attrFile, unsupported);
|
||||||
rawInput->Set(attrBuffer, unsupported);
|
Set(rawInput, attrBuffer, unsupported);
|
||||||
rawInput->Set(attrStream, unsupported);
|
Set(rawInput, attrStream, unsupported);
|
||||||
raw->Set(attrInput, rawInput);
|
Set(raw, attrInput, rawInput);
|
||||||
// Raw output via Buffer/Stream is available in libvips >= 7.42.0
|
// Raw output via Buffer/Stream is available in libvips >= 7.42.0
|
||||||
Local<Boolean> supportsRawOutput = NanNew<Boolean>(vips_version(0) >= 8 || (vips_version(0) == 7 && vips_version(1) >= 42));
|
Local<Boolean> hasOutputBufferRaw = New<Boolean>(vips_version(0) >= 8 || (vips_version(0) == 7 && vips_version(1) >= 42));
|
||||||
Local<Object> rawOutput = NanNew<Object>();
|
Local<Object> rawOutput = New<Object>();
|
||||||
rawOutput->Set(attrFile, unsupported);
|
Set(rawOutput, attrFile, unsupported);
|
||||||
rawOutput->Set(attrBuffer, supportsRawOutput);
|
Set(rawOutput, attrBuffer, hasOutputBufferRaw);
|
||||||
rawOutput->Set(attrStream, supportsRawOutput);
|
Set(rawOutput, attrStream, hasOutputBufferRaw);
|
||||||
raw->Set(attrOutput, rawOutput);
|
Set(raw, attrOutput, rawOutput);
|
||||||
|
|
||||||
NanReturnValue(format);
|
info.GetReturnValue().Set(format);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -156,50 +163,50 @@ NAN_METHOD(_maxColourDistance) {
|
|||||||
using sharp::InitImage;
|
using sharp::InitImage;
|
||||||
using sharp::HasAlpha;
|
using sharp::HasAlpha;
|
||||||
|
|
||||||
NanScope();
|
HandleScope();
|
||||||
|
|
||||||
// Create "hook" VipsObject to hang image references from
|
// Create "hook" VipsObject to hang image references from
|
||||||
VipsObject *hook = reinterpret_cast<VipsObject*>(vips_image_new());
|
VipsObject *hook = reinterpret_cast<VipsObject*>(vips_image_new());
|
||||||
|
|
||||||
// Open input files
|
// Open input files
|
||||||
VipsImage *image1 = NULL;
|
VipsImage *image1 = NULL;
|
||||||
ImageType imageType1 = DetermineImageType(*String::Utf8Value(args[0]));
|
ImageType imageType1 = DetermineImageType(*Utf8String(info[0]));
|
||||||
if (imageType1 != ImageType::UNKNOWN) {
|
if (imageType1 != ImageType::UNKNOWN) {
|
||||||
image1 = InitImage(*String::Utf8Value(args[0]), VIPS_ACCESS_SEQUENTIAL);
|
image1 = InitImage(*Utf8String(info[0]), VIPS_ACCESS_SEQUENTIAL);
|
||||||
if (image1 == NULL) {
|
if (image1 == NULL) {
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
return NanThrowError("Input file 1 has corrupt header");
|
return ThrowError("Input file 1 has corrupt header");
|
||||||
} else {
|
} else {
|
||||||
vips_object_local(hook, image1);
|
vips_object_local(hook, image1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
return NanThrowError("Input file 1 is of an unsupported image format");
|
return ThrowError("Input file 1 is of an unsupported image format");
|
||||||
}
|
}
|
||||||
VipsImage *image2 = NULL;
|
VipsImage *image2 = NULL;
|
||||||
ImageType imageType2 = DetermineImageType(*String::Utf8Value(args[1]));
|
ImageType imageType2 = DetermineImageType(*Utf8String(info[1]));
|
||||||
if (imageType2 != ImageType::UNKNOWN) {
|
if (imageType2 != ImageType::UNKNOWN) {
|
||||||
image2 = InitImage(*String::Utf8Value(args[1]), VIPS_ACCESS_SEQUENTIAL);
|
image2 = InitImage(*Utf8String(info[1]), VIPS_ACCESS_SEQUENTIAL);
|
||||||
if (image2 == NULL) {
|
if (image2 == NULL) {
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
return NanThrowError("Input file 2 has corrupt header");
|
return ThrowError("Input file 2 has corrupt header");
|
||||||
} else {
|
} else {
|
||||||
vips_object_local(hook, image2);
|
vips_object_local(hook, image2);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
return NanThrowError("Input file 2 is of an unsupported image format");
|
return ThrowError("Input file 2 is of an unsupported image format");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure same number of channels
|
// Ensure same number of channels
|
||||||
if (image1->Bands != image2->Bands) {
|
if (image1->Bands != image2->Bands) {
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
return NanThrowError("mismatchedBands");
|
return ThrowError("mismatchedBands");
|
||||||
}
|
}
|
||||||
// Ensure same dimensions
|
// Ensure same dimensions
|
||||||
if (image1->Xsize != image2->Xsize || image1->Ysize != image2->Ysize) {
|
if (image1->Xsize != image2->Xsize || image1->Ysize != image2->Ysize) {
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
return NanThrowError("mismatchedDimensions");
|
return ThrowError("mismatchedDimensions");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Premultiply and remove alpha
|
// Premultiply and remove alpha
|
||||||
@@ -207,13 +214,13 @@ NAN_METHOD(_maxColourDistance) {
|
|||||||
VipsImage *imagePremultiplied1;
|
VipsImage *imagePremultiplied1;
|
||||||
if (Premultiply(hook, image1, &imagePremultiplied1)) {
|
if (Premultiply(hook, image1, &imagePremultiplied1)) {
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
return NanThrowError(vips_error_buffer());
|
return ThrowError(vips_error_buffer());
|
||||||
}
|
}
|
||||||
vips_object_local(hook, imagePremultiplied1);
|
vips_object_local(hook, imagePremultiplied1);
|
||||||
VipsImage *imagePremultipliedNoAlpha1;
|
VipsImage *imagePremultipliedNoAlpha1;
|
||||||
if (vips_extract_band(image1, &imagePremultipliedNoAlpha1, 1, "n", image1->Bands - 1, NULL)) {
|
if (vips_extract_band(image1, &imagePremultipliedNoAlpha1, 1, "n", image1->Bands - 1, NULL)) {
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
return NanThrowError(vips_error_buffer());
|
return ThrowError(vips_error_buffer());
|
||||||
}
|
}
|
||||||
vips_object_local(hook, imagePremultipliedNoAlpha1);
|
vips_object_local(hook, imagePremultipliedNoAlpha1);
|
||||||
image1 = imagePremultipliedNoAlpha1;
|
image1 = imagePremultipliedNoAlpha1;
|
||||||
@@ -222,13 +229,13 @@ NAN_METHOD(_maxColourDistance) {
|
|||||||
VipsImage *imagePremultiplied2;
|
VipsImage *imagePremultiplied2;
|
||||||
if (Premultiply(hook, image2, &imagePremultiplied2)) {
|
if (Premultiply(hook, image2, &imagePremultiplied2)) {
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
return NanThrowError(vips_error_buffer());
|
return ThrowError(vips_error_buffer());
|
||||||
}
|
}
|
||||||
vips_object_local(hook, imagePremultiplied2);
|
vips_object_local(hook, imagePremultiplied2);
|
||||||
VipsImage *imagePremultipliedNoAlpha2;
|
VipsImage *imagePremultipliedNoAlpha2;
|
||||||
if (vips_extract_band(image2, &imagePremultipliedNoAlpha2, 1, "n", image2->Bands - 1, NULL)) {
|
if (vips_extract_band(image2, &imagePremultipliedNoAlpha2, 1, "n", image2->Bands - 1, NULL)) {
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
return NanThrowError(vips_error_buffer());
|
return ThrowError(vips_error_buffer());
|
||||||
}
|
}
|
||||||
vips_object_local(hook, imagePremultipliedNoAlpha2);
|
vips_object_local(hook, imagePremultipliedNoAlpha2);
|
||||||
image2 = imagePremultipliedNoAlpha2;
|
image2 = imagePremultipliedNoAlpha2;
|
||||||
@@ -237,15 +244,15 @@ NAN_METHOD(_maxColourDistance) {
|
|||||||
VipsImage *difference;
|
VipsImage *difference;
|
||||||
if (vips_dE00(image1, image2, &difference, NULL)) {
|
if (vips_dE00(image1, image2, &difference, NULL)) {
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
return NanThrowError(vips_error_buffer());
|
return ThrowError(vips_error_buffer());
|
||||||
}
|
}
|
||||||
vips_object_local(hook, difference);
|
vips_object_local(hook, difference);
|
||||||
// Extract maximum distance
|
// Extract maximum distance
|
||||||
double maxColourDistance;
|
double maxColourDistance;
|
||||||
if (vips_max(difference, &maxColourDistance, NULL)) {
|
if (vips_max(difference, &maxColourDistance, NULL)) {
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
return NanThrowError(vips_error_buffer());
|
return ThrowError(vips_error_buffer());
|
||||||
}
|
}
|
||||||
g_object_unref(hook);
|
g_object_unref(hook);
|
||||||
NanReturnValue(maxColourDistance);
|
info.GetReturnValue().Set(New<Number>(maxColourDistance));
|
||||||
}
|
}
|
||||||
|
|||||||
11
test/bench/package.json
Executable file → Normal file
@@ -8,13 +8,14 @@
|
|||||||
"test": "node perf && node random && node parallel"
|
"test": "node perf && node random && node parallel"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"async": "^1.4.2",
|
||||||
|
"benchmark": "^1.0.0",
|
||||||
|
"gm": "^1.20.0",
|
||||||
"imagemagick": "^0.1.3",
|
"imagemagick": "^0.1.3",
|
||||||
"imagemagick-native": "^1.8.0",
|
"imagemagick-native": "^1.8.0",
|
||||||
"gm": "^1.18.1",
|
"jimp": "^0.2.8",
|
||||||
"lwip": "^0.0.7",
|
"lwip": "^0.0.8",
|
||||||
"async": "^1.4.2",
|
"semver": "^5.0.3"
|
||||||
"semver": "^5.0.1",
|
|
||||||
"benchmark": "^1.0.0"
|
|
||||||
},
|
},
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
@@ -7,11 +7,23 @@ var assert = require('assert');
|
|||||||
var Benchmark = require('benchmark');
|
var Benchmark = require('benchmark');
|
||||||
var semver = require('semver');
|
var semver = require('semver');
|
||||||
|
|
||||||
var imagemagick = require('imagemagick');
|
// Contenders
|
||||||
var imagemagickNative = require('imagemagick-native');
|
|
||||||
var gm = require('gm');
|
var gm = require('gm');
|
||||||
var lwip = require('lwip');
|
var imagemagick = require('imagemagick');
|
||||||
|
var jimp = require('jimp');
|
||||||
var sharp = require('../../index');
|
var sharp = require('../../index');
|
||||||
|
var imagemagickNative;
|
||||||
|
try {
|
||||||
|
imagemagickNative = require('imagemagick-native');
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Excluding imagemagick-native');
|
||||||
|
}
|
||||||
|
var lwip;
|
||||||
|
try {
|
||||||
|
lwip = require('lwip');
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Excluding lwip');
|
||||||
|
}
|
||||||
|
|
||||||
var fixtures = require('../fixtures');
|
var fixtures = require('../fixtures');
|
||||||
|
|
||||||
@@ -27,7 +39,52 @@ sharp.cache(0);
|
|||||||
async.series({
|
async.series({
|
||||||
jpeg: function(callback) {
|
jpeg: function(callback) {
|
||||||
var inputJpgBuffer = fs.readFileSync(fixtures.inputJpg);
|
var inputJpgBuffer = fs.readFileSync(fixtures.inputJpg);
|
||||||
(new Benchmark.Suite('jpeg')).add('lwip-file-file', {
|
var jpegSuite = new Benchmark.Suite('jpeg');
|
||||||
|
// jimp
|
||||||
|
jpegSuite.add('jimp-buffer-buffer', {
|
||||||
|
defer: true,
|
||||||
|
fn: function(deferred) {
|
||||||
|
new jimp(inputJpgBuffer, function(err) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
} else {
|
||||||
|
this
|
||||||
|
.resize(width, height)
|
||||||
|
.quality(80)
|
||||||
|
.getBuffer(jimp.MIME_JPEG, function (err) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
} else {
|
||||||
|
deferred.resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).add('jimp-file-file', {
|
||||||
|
defer: true,
|
||||||
|
fn: function(deferred) {
|
||||||
|
new jimp(fixtures.inputJpg, function(err) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
} else {
|
||||||
|
this
|
||||||
|
.resize(width, height)
|
||||||
|
.quality(80)
|
||||||
|
.write(fixtures.outputJpg, function (err) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
} else {
|
||||||
|
deferred.resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// lwip
|
||||||
|
if (typeof lwip !== 'undefined') {
|
||||||
|
jpegSuite.add('lwip-file-file', {
|
||||||
defer: true,
|
defer: true,
|
||||||
fn: function(deferred) {
|
fn: function(deferred) {
|
||||||
lwip.open(fixtures.inputJpg, function (err, image) {
|
lwip.open(fixtures.inputJpg, function (err, image) {
|
||||||
@@ -68,7 +125,10 @@ async.series({
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}).add('imagemagick-file-file', {
|
});
|
||||||
|
}
|
||||||
|
// imagemagick
|
||||||
|
jpegSuite.add('imagemagick-file-file', {
|
||||||
defer: true,
|
defer: true,
|
||||||
fn: function(deferred) {
|
fn: function(deferred) {
|
||||||
imagemagick.resize({
|
imagemagick.resize({
|
||||||
@@ -87,7 +147,10 @@ async.series({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}).add('imagemagick-native-buffer-buffer', {
|
});
|
||||||
|
// imagemagick-native
|
||||||
|
if (typeof imagemagickNative !== 'undefined') {
|
||||||
|
jpegSuite.add('imagemagick-native-buffer-buffer', {
|
||||||
defer: true,
|
defer: true,
|
||||||
fn: function(deferred) {
|
fn: function(deferred) {
|
||||||
imagemagickNative.convert({
|
imagemagickNative.convert({
|
||||||
@@ -106,7 +169,10 @@ async.series({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}).add('gm-buffer-file', {
|
});
|
||||||
|
}
|
||||||
|
// gm
|
||||||
|
jpegSuite.add('gm-buffer-file', {
|
||||||
defer: true,
|
defer: true,
|
||||||
fn: function(deferred) {
|
fn: function(deferred) {
|
||||||
gm(inputJpgBuffer)
|
gm(inputJpgBuffer)
|
||||||
@@ -168,7 +234,9 @@ async.series({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}).add('sharp-buffer-file', {
|
});
|
||||||
|
// sharp
|
||||||
|
jpegSuite.add('sharp-buffer-file', {
|
||||||
defer: true,
|
defer: true,
|
||||||
fn: function(deferred) {
|
fn: function(deferred) {
|
||||||
sharp(inputJpgBuffer).resize(width, height).toFile(fixtures.outputJpg, function(err) {
|
sharp(inputJpgBuffer).resize(width, height).toFile(fixtures.outputJpg, function(err) {
|
||||||
@@ -446,6 +514,48 @@ async.series({
|
|||||||
png: function(callback) {
|
png: function(callback) {
|
||||||
var inputPngBuffer = fs.readFileSync(fixtures.inputPng);
|
var inputPngBuffer = fs.readFileSync(fixtures.inputPng);
|
||||||
var pngSuite = new Benchmark.Suite('png');
|
var pngSuite = new Benchmark.Suite('png');
|
||||||
|
// jimp
|
||||||
|
pngSuite.add('jimp-buffer-buffer', {
|
||||||
|
defer: true,
|
||||||
|
fn: function(deferred) {
|
||||||
|
new jimp(inputPngBuffer, function(err) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
} else {
|
||||||
|
this
|
||||||
|
.resize(width, height)
|
||||||
|
.getBuffer(jimp.MIME_PNG, function (err) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
} else {
|
||||||
|
deferred.resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).add('jimp-file-file', {
|
||||||
|
defer: true,
|
||||||
|
fn: function(deferred) {
|
||||||
|
new jimp(fixtures.inputPng, function(err) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
} else {
|
||||||
|
this
|
||||||
|
.resize(width, height)
|
||||||
|
.write(fixtures.outputPng, function (err) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
} else {
|
||||||
|
deferred.resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// lwip
|
||||||
|
if (typeof lwip !== 'undefined') {
|
||||||
pngSuite.add('lwip-buffer-buffer', {
|
pngSuite.add('lwip-buffer-buffer', {
|
||||||
defer: true,
|
defer: true,
|
||||||
fn: function(deferred) {
|
fn: function(deferred) {
|
||||||
@@ -467,7 +577,10 @@ async.series({
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}).add('imagemagick-file-file', {
|
});
|
||||||
|
}
|
||||||
|
// imagemagick
|
||||||
|
pngSuite.add('imagemagick-file-file', {
|
||||||
defer: true,
|
defer: true,
|
||||||
fn: function(deferred) {
|
fn: function(deferred) {
|
||||||
imagemagick.resize({
|
imagemagick.resize({
|
||||||
@@ -484,7 +597,10 @@ async.series({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}).add('imagemagick-native-buffer-buffer', {
|
});
|
||||||
|
// imagemagick-native
|
||||||
|
if (typeof imagemagickNative !== 'undefined') {
|
||||||
|
pngSuite.add('imagemagick-native-buffer-buffer', {
|
||||||
defer: true,
|
defer: true,
|
||||||
fn: function(deferred) {
|
fn: function(deferred) {
|
||||||
imagemagickNative.convert({
|
imagemagickNative.convert({
|
||||||
@@ -496,7 +612,10 @@ async.series({
|
|||||||
});
|
});
|
||||||
deferred.resolve();
|
deferred.resolve();
|
||||||
}
|
}
|
||||||
}).add('gm-file-file', {
|
});
|
||||||
|
}
|
||||||
|
// gm
|
||||||
|
pngSuite.add('gm-file-file', {
|
||||||
defer: true,
|
defer: true,
|
||||||
fn: function(deferred) {
|
fn: function(deferred) {
|
||||||
gm(fixtures.inputPng)
|
gm(fixtures.inputPng)
|
||||||
@@ -525,7 +644,9 @@ async.series({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}).add('sharp-buffer-file', {
|
});
|
||||||
|
// sharp
|
||||||
|
pngSuite.add('sharp-buffer-file', {
|
||||||
defer: true,
|
defer: true,
|
||||||
fn: function(deferred) {
|
fn: function(deferred) {
|
||||||
sharp(inputPngBuffer).resize(width, height).toFile(fixtures.outputPng, function(err) {
|
sharp(inputPngBuffer).resize(width, height).toFile(fixtures.outputPng, function(err) {
|
||||||
|
|||||||
BIN
test/fixtures/Landscape_1.jpg
vendored
Executable file
|
After Width: | Height: | Size: 136 KiB |
BIN
test/fixtures/Landscape_2.jpg
vendored
Executable file
|
After Width: | Height: | Size: 134 KiB |
BIN
test/fixtures/Landscape_3.jpg
vendored
Executable file
|
After Width: | Height: | Size: 138 KiB |
BIN
test/fixtures/Landscape_4.jpg
vendored
Executable file
|
After Width: | Height: | Size: 137 KiB |
0
test/fixtures/Landscape_5.jpg
vendored
Normal file → Executable file
|
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 134 KiB |
BIN
test/fixtures/Landscape_6.jpg
vendored
Executable file
|
After Width: | Height: | Size: 134 KiB |
BIN
test/fixtures/Landscape_7.jpg
vendored
Executable file
|
After Width: | Height: | Size: 137 KiB |
0
test/fixtures/Landscape_8.jpg
vendored
Normal file → Executable file
|
Before Width: | Height: | Size: 138 KiB After Width: | Height: | Size: 138 KiB |
BIN
test/fixtures/Portrait_1.jpg
vendored
Executable file
|
After Width: | Height: | Size: 126 KiB |
BIN
test/fixtures/Portrait_2.jpg
vendored
Executable file
|
After Width: | Height: | Size: 133 KiB |
BIN
test/fixtures/Portrait_3.jpg
vendored
Executable file
|
After Width: | Height: | Size: 133 KiB |
BIN
test/fixtures/Portrait_4.jpg
vendored
Executable file
|
After Width: | Height: | Size: 128 KiB |
BIN
test/fixtures/Portrait_5.jpg
vendored
Executable file
|
After Width: | Height: | Size: 131 KiB |
BIN
test/fixtures/Portrait_6.jpg
vendored
Executable file
|
After Width: | Height: | Size: 133 KiB |
BIN
test/fixtures/Portrait_7.jpg
vendored
Executable file
|
After Width: | Height: | Size: 132 KiB |
BIN
test/fixtures/Portrait_8.jpg
vendored
Executable file
|
After Width: | Height: | Size: 129 KiB |
BIN
test/fixtures/expected/Landscape_1-out.jpg
vendored
Normal file
|
After Width: | Height: | Size: 109 KiB |
BIN
test/fixtures/expected/Landscape_2-out.jpg
vendored
Normal file
|
After Width: | Height: | Size: 103 KiB |
BIN
test/fixtures/expected/Landscape_3-out.jpg
vendored
Normal file
|
After Width: | Height: | Size: 103 KiB |
BIN
test/fixtures/expected/Landscape_4-out.jpg
vendored
Normal file
|
After Width: | Height: | Size: 103 KiB |
BIN
test/fixtures/expected/Landscape_5-out.jpg
vendored
Normal file
|
After Width: | Height: | Size: 103 KiB |
BIN
test/fixtures/expected/Landscape_6-out.jpg
vendored
Normal file
|
After Width: | Height: | Size: 103 KiB |
BIN
test/fixtures/expected/Landscape_7-out.jpg
vendored
Normal file
|
After Width: | Height: | Size: 103 KiB |
BIN
test/fixtures/expected/Landscape_8-out.jpg
vendored
Normal file
|
After Width: | Height: | Size: 103 KiB |
BIN
test/fixtures/expected/Portrait_1-out.jpg
vendored
Normal file
|
After Width: | Height: | Size: 169 KiB |
BIN
test/fixtures/expected/Portrait_2-out.jpg
vendored
Normal file
|
After Width: | Height: | Size: 166 KiB |
BIN
test/fixtures/expected/Portrait_3-out.jpg
vendored
Normal file
|
After Width: | Height: | Size: 165 KiB |
BIN
test/fixtures/expected/Portrait_4-out.jpg
vendored
Normal file
|
After Width: | Height: | Size: 166 KiB |
BIN
test/fixtures/expected/Portrait_5-out.jpg
vendored
Normal file
|
After Width: | Height: | Size: 172 KiB |
BIN
test/fixtures/expected/Portrait_6-out.jpg
vendored
Normal file
|
After Width: | Height: | Size: 167 KiB |
BIN
test/fixtures/expected/Portrait_7-out.jpg
vendored
Normal file
|
After Width: | Height: | Size: 164 KiB |
BIN
test/fixtures/expected/Portrait_8-out.jpg
vendored
Normal file
|
After Width: | Height: | Size: 165 KiB |
BIN
test/fixtures/expected/blur-0.3.jpg
vendored
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
test/fixtures/expected/blur-1.jpg
vendored
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
test/fixtures/expected/blur-10.jpg
vendored
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
test/fixtures/expected/blur-mild.jpg
vendored
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
test/fixtures/expected/sharpen-10.jpg
vendored
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
test/fixtures/expected/sharpen-3-0.5-2.5.jpg
vendored
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
test/fixtures/expected/sharpen-5-2-4.jpg
vendored
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
test/fixtures/expected/sharpen-mild.jpg
vendored
Normal file
|
After Width: | Height: | Size: 15 KiB |
18
test/fixtures/index.js
vendored
@@ -40,6 +40,24 @@ var fingerprint = function(image, callback) {
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
||||||
|
inputJpgWithLandscapeExif1: getPath('Landscape_1.jpg'), // https://github.com/recurser/exif-orientation-examples
|
||||||
|
inputJpgWithLandscapeExif2: getPath('Landscape_2.jpg'), // https://github.com/recurser/exif-orientation-examples
|
||||||
|
inputJpgWithLandscapeExif3: getPath('Landscape_3.jpg'), // https://github.com/recurser/exif-orientation-examples
|
||||||
|
inputJpgWithLandscapeExif4: getPath('Landscape_4.jpg'), // https://github.com/recurser/exif-orientation-examples
|
||||||
|
inputJpgWithLandscapeExif5: getPath('Landscape_5.jpg'), // https://github.com/recurser/exif-orientation-examples
|
||||||
|
inputJpgWithLandscapeExif6: getPath('Landscape_6.jpg'), // https://github.com/recurser/exif-orientation-examples
|
||||||
|
inputJpgWithLandscapeExif7: getPath('Landscape_7.jpg'), // https://github.com/recurser/exif-orientation-examples
|
||||||
|
inputJpgWithLandscapeExif8: getPath('Landscape_8.jpg'), // https://github.com/recurser/exif-orientation-examples
|
||||||
|
|
||||||
|
inputJpgWithPortraitExif1: getPath('Portrait_1.jpg'), // https://github.com/recurser/exif-orientation-examples
|
||||||
|
inputJpgWithPortraitExif2: getPath('Portrait_2.jpg'), // https://github.com/recurser/exif-orientation-examples
|
||||||
|
inputJpgWithPortraitExif3: getPath('Portrait_3.jpg'), // https://github.com/recurser/exif-orientation-examples
|
||||||
|
inputJpgWithPortraitExif4: getPath('Portrait_4.jpg'), // https://github.com/recurser/exif-orientation-examples
|
||||||
|
inputJpgWithPortraitExif5: getPath('Portrait_5.jpg'), // https://github.com/recurser/exif-orientation-examples
|
||||||
|
inputJpgWithPortraitExif6: getPath('Portrait_6.jpg'), // https://github.com/recurser/exif-orientation-examples
|
||||||
|
inputJpgWithPortraitExif7: getPath('Portrait_7.jpg'), // https://github.com/recurser/exif-orientation-examples
|
||||||
|
inputJpgWithPortraitExif8: getPath('Portrait_8.jpg'), // https://github.com/recurser/exif-orientation-examples
|
||||||
|
|
||||||
inputJpg: getPath('2569067123_aca715a2ee_o.jpg'), // http://www.flickr.com/photos/grizdave/2569067123/
|
inputJpg: getPath('2569067123_aca715a2ee_o.jpg'), // http://www.flickr.com/photos/grizdave/2569067123/
|
||||||
inputJpgWithExif: getPath('Landscape_8.jpg'), // https://github.com/recurser/exif-orientation-examples/blob/master/Landscape_8.jpg
|
inputJpgWithExif: getPath('Landscape_8.jpg'), // https://github.com/recurser/exif-orientation-examples/blob/master/Landscape_8.jpg
|
||||||
inputJpgWithExifMirroring: getPath('Landscape_5.jpg'), // https://github.com/recurser/exif-orientation-examples/blob/master/Landscape_5.jpg
|
inputJpgWithExifMirroring: getPath('Landscape_5.jpg'), // https://github.com/recurser/exif-orientation-examples/blob/master/Landscape_5.jpg
|
||||||
|
|||||||
@@ -1,8 +1,18 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
if ! type valgrind >/dev/null; then
|
if ! type valgrind >/dev/null; then
|
||||||
echo "Please install valgrind before running memory leak tests"
|
echo "Please install valgrind before running memory leak tests"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
curl -O https://raw.githubusercontent.com/jcupitt/libvips/master/libvips.supp
|
curl -o ./test/leak/libvips.supp https://raw.githubusercontent.com/jcupitt/libvips/master/libvips.supp
|
||||||
cd ../../
|
|
||||||
G_SLICE=always-malloc G_DEBUG=gc-friendly valgrind --suppressions=test/leak/libvips.supp --suppressions=test/leak/sharp.supp --leak-check=full --show-leak-kinds=definite,indirect,possible --num-callers=20 --trace-children=yes npm test
|
G_SLICE=always-malloc G_DEBUG=gc-friendly valgrind \
|
||||||
|
--suppressions=test/leak/libvips.supp \
|
||||||
|
--suppressions=test/leak/sharp.supp \
|
||||||
|
--gen-suppressions=yes \
|
||||||
|
--leak-check=full \
|
||||||
|
--show-leak-kinds=definite,indirect,possible \
|
||||||
|
--num-callers=20 \
|
||||||
|
--trace-children=yes \
|
||||||
|
npm test
|
||||||
|
|||||||
151
test/leak/sharp.supp
Executable file → Normal file
@@ -30,7 +30,61 @@
|
|||||||
fun:jpeg_finish_compress
|
fun:jpeg_finish_compress
|
||||||
}
|
}
|
||||||
|
|
||||||
# libvips interpolator warnings
|
# libpng
|
||||||
|
{
|
||||||
|
cond_libpng_png_read_row
|
||||||
|
Memcheck:Cond
|
||||||
|
...
|
||||||
|
fun:png_read_row
|
||||||
|
}
|
||||||
|
{
|
||||||
|
value_libpng_png_read_row
|
||||||
|
Memcheck:Value8
|
||||||
|
...
|
||||||
|
fun:png_read_row
|
||||||
|
}
|
||||||
|
{
|
||||||
|
cond_libpng_png_write_rows
|
||||||
|
Memcheck:Cond
|
||||||
|
...
|
||||||
|
fun:png_write_row
|
||||||
|
fun:png_write_rows
|
||||||
|
}
|
||||||
|
{
|
||||||
|
value_libpng_png_write_rows
|
||||||
|
Memcheck:Value8
|
||||||
|
...
|
||||||
|
fun:png_write_row
|
||||||
|
fun:png_write_rows
|
||||||
|
}
|
||||||
|
|
||||||
|
# libwebp
|
||||||
|
{
|
||||||
|
cond_libwebp_WebPEncodeRGBA
|
||||||
|
Memcheck:Cond
|
||||||
|
...
|
||||||
|
fun:WebPEncodeRGBA
|
||||||
|
}
|
||||||
|
{
|
||||||
|
value_libwebp_WebPEncodeRGBA
|
||||||
|
Memcheck:Value8
|
||||||
|
...
|
||||||
|
fun:WebPEncodeRGBA
|
||||||
|
}
|
||||||
|
{
|
||||||
|
cond_libwebp_WebPEncodeRGB
|
||||||
|
Memcheck:Cond
|
||||||
|
...
|
||||||
|
fun:WebPEncodeRGB
|
||||||
|
}
|
||||||
|
{
|
||||||
|
value_libwebp_WebPEncodeRGB
|
||||||
|
Memcheck:Value8
|
||||||
|
...
|
||||||
|
fun:WebPEncodeRGB
|
||||||
|
}
|
||||||
|
|
||||||
|
# libvips
|
||||||
{
|
{
|
||||||
cond_libvips_interpolate_lbb
|
cond_libvips_interpolate_lbb
|
||||||
Memcheck:Cond
|
Memcheck:Cond
|
||||||
@@ -38,6 +92,18 @@
|
|||||||
fun:_ZL32vips_interpolate_lbb_interpolateP16_VipsInterpolatePvP11_VipsRegiondd
|
fun:_ZL32vips_interpolate_lbb_interpolateP16_VipsInterpolatePvP11_VipsRegiondd
|
||||||
fun:vips_affine_gen
|
fun:vips_affine_gen
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
cond_libvips_conv_gen
|
||||||
|
Memcheck:Cond
|
||||||
|
fun:conv_gen
|
||||||
|
fun:vips_region_generate
|
||||||
|
}
|
||||||
|
{
|
||||||
|
cond_libvips_col_sRGB2scRGB_8
|
||||||
|
Memcheck:Value8
|
||||||
|
fun:vips_col_sRGB2scRGB_8
|
||||||
|
fun:vips_sRGB2scRGB_gen
|
||||||
|
}
|
||||||
|
|
||||||
# libuv warnings
|
# libuv warnings
|
||||||
{
|
{
|
||||||
@@ -46,6 +112,19 @@
|
|||||||
...
|
...
|
||||||
fun:uv__work_done
|
fun:uv__work_done
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
param_libuv_fs_work
|
||||||
|
Memcheck:Param
|
||||||
|
write(buf)
|
||||||
|
...
|
||||||
|
fun:uv__fs_work
|
||||||
|
}
|
||||||
|
{
|
||||||
|
cond_libuv_work_done
|
||||||
|
Memcheck:Cond
|
||||||
|
...
|
||||||
|
fun:uv__work_done
|
||||||
|
}
|
||||||
|
|
||||||
# nodejs warnings
|
# nodejs warnings
|
||||||
{
|
{
|
||||||
@@ -55,6 +134,13 @@
|
|||||||
...
|
...
|
||||||
obj:/usr/bin/nodejs
|
obj:/usr/bin/nodejs
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
param_iojs_write_buffer
|
||||||
|
Memcheck:Param
|
||||||
|
write(buf)
|
||||||
|
...
|
||||||
|
obj:/usr/bin/iojs
|
||||||
|
}
|
||||||
{
|
{
|
||||||
leak_nodejs_ImmutableAsciiSource_CreateFromLiteral
|
leak_nodejs_ImmutableAsciiSource_CreateFromLiteral
|
||||||
Memcheck:Leak
|
Memcheck:Leak
|
||||||
@@ -99,6 +185,69 @@
|
|||||||
...
|
...
|
||||||
fun:ares_init_options
|
fun:ares_init_options
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
leak_nodejs_CreateEnvironment_Handle
|
||||||
|
Memcheck:Leak
|
||||||
|
match-leak-kinds: possible
|
||||||
|
...
|
||||||
|
fun:_ZN4node17CreateEnvironmentEPN2v87IsolateEP9uv_loop_sNS0_6HandleINS0_7ContextEEEiPKPKciSB_
|
||||||
|
}
|
||||||
|
{
|
||||||
|
leak_nodejs_CreateEnvironment_Local
|
||||||
|
Memcheck:Leak
|
||||||
|
match-leak-kinds: possible
|
||||||
|
...
|
||||||
|
fun:_ZN4node17CreateEnvironmentEPN2v87IsolateEP9uv_loop_sNS0_5LocalINS0_7ContextEEEiPKPKciSB_
|
||||||
|
}
|
||||||
|
{
|
||||||
|
leak_nan_FunctionCallbackInfo
|
||||||
|
Memcheck:Leak
|
||||||
|
match-leak-kinds: definite
|
||||||
|
...
|
||||||
|
fun:_ZN3Nan3impL23FunctionCallbackWrapperERKN2v820FunctionCallbackInfoINS1_5ValueEEE
|
||||||
|
}
|
||||||
|
{
|
||||||
|
leak_v8_FunctionCallbackInfo
|
||||||
|
Memcheck:Leak
|
||||||
|
match-leak-kinds: possible
|
||||||
|
...
|
||||||
|
fun:_ZN2v88internal25FunctionCallbackArguments4CallEPFvRKNS_20FunctionCallbackInfoINS_5ValueEEEE
|
||||||
|
}
|
||||||
|
{
|
||||||
|
leak_v8_CallInterfaceDescriptorData
|
||||||
|
Memcheck:Leak
|
||||||
|
match-leak-kinds: possible
|
||||||
|
...
|
||||||
|
fun:_ZN2v88internal27CallInterfaceDescriptorData10InitializeEiPNS0_8RegisterEPNS0_14RepresentationEPNS0_27PlatformInterfaceDescriptorE
|
||||||
|
}
|
||||||
|
{
|
||||||
|
leak_v8_Isolate_Init
|
||||||
|
Memcheck:Leak
|
||||||
|
match-leak-kinds: possible
|
||||||
|
...
|
||||||
|
fun:_ZN2v88internal7Isolate4InitEPNS0_12DeserializerE
|
||||||
|
}
|
||||||
|
{
|
||||||
|
leak_v8_StoreDescriptor_Initialize
|
||||||
|
Memcheck:Leak
|
||||||
|
match-leak-kinds: possible
|
||||||
|
...
|
||||||
|
fun:_ZN2v88internal15StoreDescriptor10InitializeEPNS0_27CallInterfaceDescriptorDataE
|
||||||
|
}
|
||||||
|
{
|
||||||
|
leak_v8_CodeStub_GetCode
|
||||||
|
Memcheck:Leak
|
||||||
|
match-leak-kinds: possible
|
||||||
|
...
|
||||||
|
fun:_ZN2v88internal8CodeStub7GetCodeEv
|
||||||
|
}
|
||||||
|
{
|
||||||
|
leak_v8_CreateICUCollator
|
||||||
|
Memcheck:Leak
|
||||||
|
match-leak-kinds: possible
|
||||||
|
...
|
||||||
|
fun:_ZN2v88internal12_GLOBAL__N_117CreateICUCollatorEPNS0_7IsolateERKN6icu_556LocaleENS0_6HandleINS0_8JSObjectEEE
|
||||||
|
}
|
||||||
|
|
||||||
# vips__init warnings
|
# vips__init warnings
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,12 +13,11 @@ describe('Blur', function() {
|
|||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.resize(320, 240)
|
.resize(320, 240)
|
||||||
.blur(1)
|
.blur(1)
|
||||||
.toFile(fixtures.path('output.blur-1.jpg'), function(err, info) {
|
.toBuffer(function(err, data, info) {
|
||||||
if (err) throw err;
|
|
||||||
assert.strictEqual('jpeg', info.format);
|
assert.strictEqual('jpeg', info.format);
|
||||||
assert.strictEqual(320, info.width);
|
assert.strictEqual(320, info.width);
|
||||||
assert.strictEqual(240, info.height);
|
assert.strictEqual(240, info.height);
|
||||||
done();
|
fixtures.assertSimilar(fixtures.expected('blur-1.jpg'), data, done);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -26,12 +25,11 @@ describe('Blur', function() {
|
|||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.resize(320, 240)
|
.resize(320, 240)
|
||||||
.blur(10)
|
.blur(10)
|
||||||
.toFile(fixtures.path('output.blur-10.jpg'), function(err, info) {
|
.toBuffer(function(err, data, info) {
|
||||||
if (err) throw err;
|
|
||||||
assert.strictEqual('jpeg', info.format);
|
assert.strictEqual('jpeg', info.format);
|
||||||
assert.strictEqual(320, info.width);
|
assert.strictEqual(320, info.width);
|
||||||
assert.strictEqual(240, info.height);
|
assert.strictEqual(240, info.height);
|
||||||
done();
|
fixtures.assertSimilar(fixtures.expected('blur-10.jpg'), data, done);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -39,12 +37,11 @@ describe('Blur', function() {
|
|||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.resize(320, 240)
|
.resize(320, 240)
|
||||||
.blur(0.3)
|
.blur(0.3)
|
||||||
.toFile(fixtures.path('output.blur-0.3.jpg'), function(err, info) {
|
.toBuffer(function(err, data, info) {
|
||||||
if (err) throw err;
|
|
||||||
assert.strictEqual('jpeg', info.format);
|
assert.strictEqual('jpeg', info.format);
|
||||||
assert.strictEqual(320, info.width);
|
assert.strictEqual(320, info.width);
|
||||||
assert.strictEqual(240, info.height);
|
assert.strictEqual(240, info.height);
|
||||||
done();
|
fixtures.assertSimilar(fixtures.expected('blur-0.3.jpg'), data, done);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -52,24 +49,18 @@ describe('Blur', function() {
|
|||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.resize(320, 240)
|
.resize(320, 240)
|
||||||
.blur()
|
.blur()
|
||||||
.toFile(fixtures.path('output.blur-mild.jpg'), function(err, info) {
|
.toBuffer(function(err, data, info) {
|
||||||
if (err) throw err;
|
|
||||||
assert.strictEqual('jpeg', info.format);
|
assert.strictEqual('jpeg', info.format);
|
||||||
assert.strictEqual(320, info.width);
|
assert.strictEqual(320, info.width);
|
||||||
assert.strictEqual(240, info.height);
|
assert.strictEqual(240, info.height);
|
||||||
done();
|
fixtures.assertSimilar(fixtures.expected('blur-mild.jpg'), data, done);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('invalid radius', function(done) {
|
it('invalid radius', function() {
|
||||||
var isValid = true;
|
assert.throws(function() {
|
||||||
try {
|
|
||||||
sharp(fixtures.inputJpg).blur(0.1);
|
sharp(fixtures.inputJpg).blur(0.1);
|
||||||
} catch (err) {
|
});
|
||||||
isValid = false;
|
|
||||||
}
|
|
||||||
assert.strictEqual(false, isValid);
|
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('blurred image is smaller than non-blurred', function(done) {
|
it('blurred image is smaller than non-blurred', function(done) {
|
||||||
@@ -77,7 +68,6 @@ describe('Blur', function() {
|
|||||||
.resize(320, 240)
|
.resize(320, 240)
|
||||||
.blur(false)
|
.blur(false)
|
||||||
.toBuffer(function(err, notBlurred, info) {
|
.toBuffer(function(err, notBlurred, info) {
|
||||||
if (err) throw err;
|
|
||||||
assert.strictEqual(true, notBlurred.length > 0);
|
assert.strictEqual(true, notBlurred.length > 0);
|
||||||
assert.strictEqual('jpeg', info.format);
|
assert.strictEqual('jpeg', info.format);
|
||||||
assert.strictEqual(320, info.width);
|
assert.strictEqual(320, info.width);
|
||||||
@@ -86,7 +76,6 @@ describe('Blur', function() {
|
|||||||
.resize(320, 240)
|
.resize(320, 240)
|
||||||
.blur(true)
|
.blur(true)
|
||||||
.toBuffer(function(err, blurred, info) {
|
.toBuffer(function(err, blurred, info) {
|
||||||
if (err) throw err;
|
|
||||||
assert.strictEqual(true, blurred.length > 0);
|
assert.strictEqual(true, blurred.length > 0);
|
||||||
assert.strictEqual(true, blurred.length < notBlurred.length);
|
assert.strictEqual(true, blurred.length < notBlurred.length);
|
||||||
assert.strictEqual('jpeg', info.format);
|
assert.strictEqual('jpeg', info.format);
|
||||||
|
|||||||
@@ -9,22 +9,125 @@ sharp.cache(0);
|
|||||||
|
|
||||||
describe('Crop gravities', function() {
|
describe('Crop gravities', function() {
|
||||||
|
|
||||||
it('North', function(done) {
|
var testSettings = [
|
||||||
|
{
|
||||||
|
name: 'North',
|
||||||
|
width: 320,
|
||||||
|
height: 80,
|
||||||
|
gravity: sharp.gravity.north,
|
||||||
|
fixture: 'gravity-north.jpg'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'East',
|
||||||
|
width: 80,
|
||||||
|
height: 320,
|
||||||
|
gravity: sharp.gravity.east,
|
||||||
|
fixture: 'gravity-east.jpg'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'South',
|
||||||
|
width: 320,
|
||||||
|
height: 80,
|
||||||
|
gravity: sharp.gravity.south,
|
||||||
|
fixture: 'gravity-south.jpg'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'West',
|
||||||
|
width: 80,
|
||||||
|
height: 320,
|
||||||
|
gravity: sharp.gravity.west,
|
||||||
|
fixture: 'gravity-west.jpg'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Center',
|
||||||
|
width: 320,
|
||||||
|
height: 80,
|
||||||
|
gravity: sharp.gravity.center,
|
||||||
|
fixture: 'gravity-center.jpg'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Centre',
|
||||||
|
width: 80,
|
||||||
|
height: 320,
|
||||||
|
gravity: sharp.gravity.centre,
|
||||||
|
fixture: 'gravity-centre.jpg'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Northeast',
|
||||||
|
width: 320,
|
||||||
|
height: 80,
|
||||||
|
gravity: sharp.gravity.northeast,
|
||||||
|
fixture: 'gravity-north.jpg'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Northeast',
|
||||||
|
width: 80,
|
||||||
|
height: 320,
|
||||||
|
gravity: sharp.gravity.northeast,
|
||||||
|
fixture: 'gravity-east.jpg'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Southeast',
|
||||||
|
width: 320,
|
||||||
|
height: 80,
|
||||||
|
gravity: sharp.gravity.southeast,
|
||||||
|
fixture: 'gravity-south.jpg'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Southeast',
|
||||||
|
width: 80,
|
||||||
|
height: 320,
|
||||||
|
gravity: sharp.gravity.southeast,
|
||||||
|
fixture: 'gravity-east.jpg'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Southwest',
|
||||||
|
width: 320,
|
||||||
|
height: 80,
|
||||||
|
gravity: sharp.gravity.southwest,
|
||||||
|
fixture: 'gravity-south.jpg'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Southwest',
|
||||||
|
width: 80,
|
||||||
|
height: 320,
|
||||||
|
gravity: sharp.gravity.southwest,
|
||||||
|
fixture: 'gravity-west.jpg'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Northwest',
|
||||||
|
width: 320,
|
||||||
|
height: 80,
|
||||||
|
gravity: sharp.gravity.northwest,
|
||||||
|
fixture: 'gravity-north.jpg'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Northwest',
|
||||||
|
width: 80,
|
||||||
|
height: 320,
|
||||||
|
gravity: sharp.gravity.northwest,
|
||||||
|
fixture: 'gravity-west.jpg'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
testSettings.forEach(function(settings) {
|
||||||
|
it(settings.name, function(done) {
|
||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.resize(320, 80)
|
.resize(settings.width, settings.height)
|
||||||
.crop(sharp.gravity.north)
|
.crop(settings.gravity)
|
||||||
.toBuffer(function(err, data, info) {
|
.toBuffer(function(err, data, info) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
assert.strictEqual(320, info.width);
|
assert.strictEqual(settings.width, info.width);
|
||||||
assert.strictEqual(80, info.height);
|
assert.strictEqual(settings.height, info.height);
|
||||||
fixtures.assertSimilar(fixtures.expected('gravity-north.jpg'), data, done);
|
fixtures.assertSimilar(fixtures.expected(settings.fixture), data, done);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('East', function(done) {
|
it('allows specifying the gravity as a string', function(done) {
|
||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.resize(80, 320)
|
.resize(80, 320)
|
||||||
.crop(sharp.gravity.east)
|
.crop('east')
|
||||||
.toBuffer(function(err, data, info) {
|
.toBuffer(function(err, data, info) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
assert.strictEqual(80, info.width);
|
assert.strictEqual(80, info.width);
|
||||||
@@ -33,58 +136,15 @@ describe('Crop gravities', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('South', function(done) {
|
it('Invalid number', function() {
|
||||||
sharp(fixtures.inputJpg)
|
|
||||||
.resize(320, 80)
|
|
||||||
.crop(sharp.gravity.south)
|
|
||||||
.toBuffer(function(err, data, info) {
|
|
||||||
if (err) throw err;
|
|
||||||
assert.strictEqual(320, info.width);
|
|
||||||
assert.strictEqual(80, info.height);
|
|
||||||
fixtures.assertSimilar(fixtures.expected('gravity-south.jpg'), data, done);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('West', function(done) {
|
|
||||||
sharp(fixtures.inputJpg)
|
|
||||||
.resize(80, 320)
|
|
||||||
.crop(sharp.gravity.west)
|
|
||||||
.toBuffer(function(err, data, info) {
|
|
||||||
if (err) throw err;
|
|
||||||
assert.strictEqual(80, info.width);
|
|
||||||
assert.strictEqual(320, info.height);
|
|
||||||
fixtures.assertSimilar(fixtures.expected('gravity-west.jpg'), data, done);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Center', function(done) {
|
|
||||||
sharp(fixtures.inputJpg)
|
|
||||||
.resize(320, 80)
|
|
||||||
.crop(sharp.gravity.center)
|
|
||||||
.toBuffer(function(err, data, info) {
|
|
||||||
if (err) throw err;
|
|
||||||
assert.strictEqual(320, info.width);
|
|
||||||
assert.strictEqual(80, info.height);
|
|
||||||
fixtures.assertSimilar(fixtures.expected('gravity-center.jpg'), data, done);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Centre', function(done) {
|
|
||||||
sharp(fixtures.inputJpg)
|
|
||||||
.resize(80, 320)
|
|
||||||
.crop(sharp.gravity.centre)
|
|
||||||
.toBuffer(function(err, data, info) {
|
|
||||||
if (err) throw err;
|
|
||||||
assert.strictEqual(80, info.width);
|
|
||||||
assert.strictEqual(320, info.height);
|
|
||||||
fixtures.assertSimilar(fixtures.expected('gravity-centre.jpg'), data, done);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Invalid', function() {
|
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
sharp(fixtures.inputJpg).crop(5);
|
sharp(fixtures.inputJpg).crop(9);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Invalid string', function() {
|
||||||
|
assert.throws(function() {
|
||||||
|
sharp(fixtures.inputJpg).crop('yadda');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ describe('Gamma correction', function() {
|
|||||||
assert.strictEqual('jpeg', info.format);
|
assert.strictEqual('jpeg', info.format);
|
||||||
assert.strictEqual(129, info.width);
|
assert.strictEqual(129, info.width);
|
||||||
assert.strictEqual(111, info.height);
|
assert.strictEqual(111, info.height);
|
||||||
fixtures.assertSimilar(fixtures.expected('gamma-0.0.jpg'), data, done);
|
fixtures.assertSimilar(fixtures.expected('gamma-0.0.jpg'), data, {threshold: 12}, done);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
15
test/unit/require.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
describe('Require-time checks', function() {
|
||||||
|
|
||||||
|
/*
|
||||||
|
Including sharp alongside another C++ module that does not require
|
||||||
|
-stdlib=libc++ (for its C++11 features) has caused clang/llvm to
|
||||||
|
segfault due to the use of static function variables.
|
||||||
|
*/
|
||||||
|
it('Require alongside C++ module that does not use libc++', function() {
|
||||||
|
var bufferutil = require('bufferutil');
|
||||||
|
var sharp = require('../../index');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
@@ -9,6 +9,23 @@ sharp.cache(0);
|
|||||||
|
|
||||||
describe('Rotation', function() {
|
describe('Rotation', function() {
|
||||||
|
|
||||||
|
['Landscape', 'Portrait'].forEach(function(orientation) {
|
||||||
|
[1,2,3,4,5,6,7,8].forEach(function(exifTag) {
|
||||||
|
it('Input image has Orientation EXIF tag value of (' + exifTag + '), auto-rotate', function(done) {
|
||||||
|
sharp(fixtures['inputJpgWith'+orientation+'Exif'+exifTag])
|
||||||
|
.rotate()
|
||||||
|
.resize(320)
|
||||||
|
.toBuffer(function(err, data, info) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.strictEqual('jpeg', info.format);
|
||||||
|
assert.strictEqual(320, info.width);
|
||||||
|
assert.strictEqual(orientation === 'Landscape' ? 240 : 427, info.height);
|
||||||
|
fixtures.assertSimilar(fixtures.expected(orientation + '_' + exifTag + '-out.jpg'), data, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('Rotate by 90 degrees, respecting output input size', function(done) {
|
it('Rotate by 90 degrees, respecting output input size', function(done) {
|
||||||
sharp(fixtures.inputJpg).rotate(90).resize(320, 240).toBuffer(function(err, data, info) {
|
sharp(fixtures.inputJpg).rotate(90).resize(320, 240).toBuffer(function(err, data, info) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
|
|||||||
@@ -13,12 +13,11 @@ describe('Sharpen', function() {
|
|||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.resize(320, 240)
|
.resize(320, 240)
|
||||||
.sharpen(10)
|
.sharpen(10)
|
||||||
.toFile(fixtures.path('output.sharpen-10.jpg'), function(err, info) {
|
.toBuffer(function(err, data, info) {
|
||||||
if (err) throw err;
|
|
||||||
assert.strictEqual('jpeg', info.format);
|
assert.strictEqual('jpeg', info.format);
|
||||||
assert.strictEqual(320, info.width);
|
assert.strictEqual(320, info.width);
|
||||||
assert.strictEqual(240, info.height);
|
assert.strictEqual(240, info.height);
|
||||||
done();
|
fixtures.assertSimilar(fixtures.expected('sharpen-10.jpg'), data, done);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -26,12 +25,11 @@ describe('Sharpen', function() {
|
|||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.resize(320, 240)
|
.resize(320, 240)
|
||||||
.sharpen(3, 0.5, 2.5)
|
.sharpen(3, 0.5, 2.5)
|
||||||
.toFile(fixtures.path('output.sharpen-3-0.5-2.5.jpg'), function(err, info) {
|
.toBuffer(function(err, data, info) {
|
||||||
if (err) throw err;
|
|
||||||
assert.strictEqual('jpeg', info.format);
|
assert.strictEqual('jpeg', info.format);
|
||||||
assert.strictEqual(320, info.width);
|
assert.strictEqual(320, info.width);
|
||||||
assert.strictEqual(240, info.height);
|
assert.strictEqual(240, info.height);
|
||||||
done();
|
fixtures.assertSimilar(fixtures.expected('sharpen-3-0.5-2.5.jpg'), data, done);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -39,12 +37,11 @@ describe('Sharpen', function() {
|
|||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.resize(320, 240)
|
.resize(320, 240)
|
||||||
.sharpen(5, 2, 4)
|
.sharpen(5, 2, 4)
|
||||||
.toFile(fixtures.path('output.sharpen-5-2-4.jpg'), function(err, info) {
|
.toBuffer(function(err, data, info) {
|
||||||
if (err) throw err;
|
|
||||||
assert.strictEqual('jpeg', info.format);
|
assert.strictEqual('jpeg', info.format);
|
||||||
assert.strictEqual(320, info.width);
|
assert.strictEqual(320, info.width);
|
||||||
assert.strictEqual(240, info.height);
|
assert.strictEqual(240, info.height);
|
||||||
done();
|
fixtures.assertSimilar(fixtures.expected('sharpen-5-2-4.jpg'), data, done);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -52,46 +49,30 @@ describe('Sharpen', function() {
|
|||||||
sharp(fixtures.inputJpg)
|
sharp(fixtures.inputJpg)
|
||||||
.resize(320, 240)
|
.resize(320, 240)
|
||||||
.sharpen()
|
.sharpen()
|
||||||
.toFile(fixtures.path('output.sharpen-mild.jpg'), function(err, info) {
|
.toBuffer(function(err, data, info) {
|
||||||
if (err) throw err;
|
|
||||||
assert.strictEqual('jpeg', info.format);
|
assert.strictEqual('jpeg', info.format);
|
||||||
assert.strictEqual(320, info.width);
|
assert.strictEqual(320, info.width);
|
||||||
assert.strictEqual(240, info.height);
|
assert.strictEqual(240, info.height);
|
||||||
done();
|
fixtures.assertSimilar(fixtures.expected('sharpen-mild.jpg'), data, done);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('invalid radius', function(done) {
|
it('invalid radius', function() {
|
||||||
var isValid = true;
|
assert.throws(function() {
|
||||||
try {
|
|
||||||
sharp(fixtures.inputJpg).sharpen(1.5);
|
sharp(fixtures.inputJpg).sharpen(1.5);
|
||||||
} catch (err) {
|
});
|
||||||
isValid = false;
|
|
||||||
}
|
|
||||||
assert.strictEqual(false, isValid);
|
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('invalid flat', function(done) {
|
it('invalid flat', function() {
|
||||||
var isValid = true;
|
assert.throws(function() {
|
||||||
try {
|
|
||||||
sharp(fixtures.inputJpg).sharpen(1, -1);
|
sharp(fixtures.inputJpg).sharpen(1, -1);
|
||||||
} catch (err) {
|
});
|
||||||
isValid = false;
|
|
||||||
}
|
|
||||||
assert.strictEqual(false, isValid);
|
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('invalid jagged', function(done) {
|
it('invalid jagged', function() {
|
||||||
var isValid = true;
|
assert.throws(function() {
|
||||||
try {
|
|
||||||
sharp(fixtures.inputJpg).sharpen(1, 1, -1);
|
sharp(fixtures.inputJpg).sharpen(1, 1, -1);
|
||||||
} catch (err) {
|
});
|
||||||
isValid = false;
|
|
||||||
}
|
|
||||||
assert.strictEqual(false, isValid);
|
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sharpened image is larger than non-sharpened', function(done) {
|
it('sharpened image is larger than non-sharpened', function(done) {
|
||||||
@@ -99,7 +80,6 @@ describe('Sharpen', function() {
|
|||||||
.resize(320, 240)
|
.resize(320, 240)
|
||||||
.sharpen(false)
|
.sharpen(false)
|
||||||
.toBuffer(function(err, notSharpened, info) {
|
.toBuffer(function(err, notSharpened, info) {
|
||||||
if (err) throw err;
|
|
||||||
assert.strictEqual(true, notSharpened.length > 0);
|
assert.strictEqual(true, notSharpened.length > 0);
|
||||||
assert.strictEqual('jpeg', info.format);
|
assert.strictEqual('jpeg', info.format);
|
||||||
assert.strictEqual(320, info.width);
|
assert.strictEqual(320, info.width);
|
||||||
@@ -108,7 +88,6 @@ describe('Sharpen', function() {
|
|||||||
.resize(320, 240)
|
.resize(320, 240)
|
||||||
.sharpen(true)
|
.sharpen(true)
|
||||||
.toBuffer(function(err, sharpened, info) {
|
.toBuffer(function(err, sharpened, info) {
|
||||||
if (err) throw err;
|
|
||||||
assert.strictEqual(true, sharpened.length > 0);
|
assert.strictEqual(true, sharpened.length > 0);
|
||||||
assert.strictEqual(true, sharpened.length > notSharpened.length);
|
assert.strictEqual(true, sharpened.length > notSharpened.length);
|
||||||
assert.strictEqual('jpeg', info.format);
|
assert.strictEqual('jpeg', info.format);
|
||||||
|
|||||||