mirror of
https://github.com/lovell/sharp.git
synced 2026-02-04 05:36:18 +01:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3511723914 | ||
|
|
6a1c7b7588 | ||
|
|
18fd6ef119 | ||
|
|
0004f5d2ff | ||
|
|
5f29d1ba9c | ||
|
|
791fd35c35 | ||
|
|
e0d622d347 | ||
|
|
6b34e8a804 | ||
|
|
eb8773fe3e | ||
|
|
b40e3fa1f1 | ||
|
|
d25d761b55 | ||
|
|
d6051dd714 | ||
|
|
53ff061efa | ||
|
|
72b0efd393 | ||
|
|
df97ef23d9 | ||
|
|
f6373971bd | ||
|
|
ec617f2489 | ||
|
|
502ae78579 | ||
|
|
49297d6afb | ||
|
|
29354badd8 | ||
|
|
3c4de796c8 | ||
|
|
c7f4488e77 | ||
|
|
d8765f955d | ||
|
|
9f20037dad | ||
|
|
2ebb090df2 | ||
|
|
110fff3ab9 | ||
|
|
f42a1ceab7 | ||
|
|
9e39a7fa95 |
40
.travis.yml
40
.travis.yml
@@ -1,21 +1,27 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "4"
|
||||
- "6"
|
||||
- "7"
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
sudo: false
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.8
|
||||
osx_image: xcode8
|
||||
before_install:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then export CXX=g++-4.8; fi
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
dist: trusty
|
||||
sudo: false
|
||||
node_js: "4"
|
||||
- os: linux
|
||||
dist: trusty
|
||||
sudo: false
|
||||
node_js: "6"
|
||||
- os: linux
|
||||
dist: trusty
|
||||
sudo: false
|
||||
node_js: "8"
|
||||
- os: osx
|
||||
osx_image: xcode8
|
||||
node_js: "4"
|
||||
- os: osx
|
||||
osx_image: xcode8
|
||||
node_js: "6"
|
||||
- os: osx
|
||||
osx_image: xcode8
|
||||
node_js: "8"
|
||||
after_success:
|
||||
- npm install coveralls
|
||||
- cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js
|
||||
|
||||
@@ -30,8 +30,11 @@ import sharp from 'sharp';
|
||||
sharp(inputBuffer)
|
||||
.resize(320, 240)
|
||||
.toFile('output.webp', (err, info) => ... );
|
||||
// A Promises/A+ promise is returned when callback is not provided.
|
||||
```
|
||||
|
||||
|
||||
|
||||
```javascript
|
||||
sharp('input.jpg')
|
||||
.rotate()
|
||||
|
||||
@@ -144,7 +144,7 @@
|
||||
}],
|
||||
['OS == "linux"', {
|
||||
'variables': {
|
||||
'download_vips': '<!(LDD_VERSION="<!(ldd --version 2>&1 || true)" node -e "require(\'./binding\').download_vips()")'
|
||||
'download_vips': '<!(node -e "require(\'./binding\').download_vips()")'
|
||||
},
|
||||
'defines': [
|
||||
'_GLIBCXX_USE_CXX11_ABI=0'
|
||||
|
||||
40
binding.js
40
binding.js
@@ -5,11 +5,12 @@ const os = require('os');
|
||||
const path = require('path');
|
||||
|
||||
const caw = require('caw');
|
||||
const got = require('got');
|
||||
const simpleGet = require('simple-get');
|
||||
const semver = require('semver');
|
||||
const tar = require('tar');
|
||||
const detectLibc = require('detect-libc');
|
||||
|
||||
const distBaseUrl = 'https://dl.bintray.com/lovell/sharp/';
|
||||
const distBaseUrl = process.env.SHARP_DIST_BASE_URL || 'https://dl.bintray.com/lovell/sharp/';
|
||||
|
||||
// Use NPM-provided environment variable where available, falling back to require-based method for Electron
|
||||
const minimumLibvipsVersion = process.env.npm_package_config_libvips || require('./package.json').config.libvips;
|
||||
@@ -68,19 +69,15 @@ module.exports.download_vips = function () {
|
||||
if (!isFile(vipsHeaderPath)) {
|
||||
// Ensure Intel 64-bit or ARM
|
||||
if (arch === 'ia32') {
|
||||
error('Intel Architecture 32-bit systems require manual installation - please see http://sharp.dimens.io/en/stable/install/');
|
||||
error('Intel Architecture 32-bit systems require manual installation of libvips - please see http://sharp.dimens.io/page/install');
|
||||
}
|
||||
// Ensure glibc >= 2.15
|
||||
const lddVersion = process.env.LDD_VERSION;
|
||||
if (lddVersion) {
|
||||
if (/(glibc|gnu libc|gentoo)/i.test(lddVersion)) {
|
||||
const glibcVersion = lddVersion ? lddVersion.split(/\n/)[0].split(' ').slice(-1)[0].trim() : '';
|
||||
if (glibcVersion && semver.lt(glibcVersion + '.0', '2.13.0')) {
|
||||
error('glibc version ' + glibcVersion + ' requires manual installation - please see http://sharp.dimens.io/en/stable/install/');
|
||||
}
|
||||
} else {
|
||||
error(lddVersion.split(/\n/)[0] + ' requires manual installation - please see http://sharp.dimens.io/en/stable/install/');
|
||||
}
|
||||
// Ensure glibc Linux
|
||||
if (detectLibc.isNonGlibcLinux) {
|
||||
error(`Use with ${detectLibc.family} libc requires manual installation of libvips - please see http://sharp.dimens.io/page/install`);
|
||||
}
|
||||
// Ensure glibc >= 2.13
|
||||
if (detectLibc.family === detectLibc.GLIBC && detectLibc.version && semver.lt(`${detectLibc.version}.0`, '2.13.0')) {
|
||||
error(`Use with glibc version ${detectLibc.version} requires manual installation of libvips - please see http://sharp.dimens.io/page/install`);
|
||||
}
|
||||
// Arch/platform-specific .tar.gz
|
||||
const tarFilename = ['libvips', minimumLibvipsVersion, platformId()].join('-') + '.tar.gz';
|
||||
@@ -98,19 +95,22 @@ module.exports.download_vips = function () {
|
||||
} catch (err) {}
|
||||
});
|
||||
});
|
||||
const gotOpt = {
|
||||
const url = distBaseUrl + tarFilename;
|
||||
const simpleGetOpt = {
|
||||
url: url,
|
||||
agent: caw(null, {
|
||||
protocol: 'https'
|
||||
})
|
||||
};
|
||||
const url = distBaseUrl + tarFilename;
|
||||
got.stream(url, gotOpt).on('response', function (response) {
|
||||
simpleGet(simpleGetOpt, function (err, response) {
|
||||
if (err) {
|
||||
error('Download of ' + url + ' failed: ' + err.message);
|
||||
}
|
||||
if (response.statusCode !== 200) {
|
||||
error(url + ' status code ' + response.statusCode);
|
||||
}
|
||||
}).on('error', function (err) {
|
||||
error('Download of ' + url + ' failed: ' + err.message);
|
||||
}).pipe(tmpFile);
|
||||
response.pipe(tmpFile);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
machine:
|
||||
node:
|
||||
version: v4.6.1
|
||||
version: v4.8.4
|
||||
services:
|
||||
- docker
|
||||
test:
|
||||
|
||||
@@ -140,6 +140,8 @@ Use these TIFF options for output image.
|
||||
- `options.force` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** force TIFF output, otherwise attempt to use input format (optional, default `true`)
|
||||
- `options.compression` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** compression options: lzw, deflate, jpeg (optional, default `'jpeg'`)
|
||||
- `options.predictor` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** compression predictor options: none, horizontal, float (optional, default `'none'`)
|
||||
- `options.xres` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** horizontal resolution in pixels/mm (optional, default `1.0`)
|
||||
- `options.yres` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** vertical resolution in pixels/mm (optional, default `1.0`)
|
||||
- `options.squash` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** squash 8-bit images down to 1 bit (optional, default `false`)
|
||||
|
||||
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
|
||||
## cache
|
||||
|
||||
Gets, or when options are provided sets, the limits of _libvips'_ operation cache.
|
||||
Gets or, when options are provided, sets the limits of _libvips'_ operation cache.
|
||||
Existing entries in the cache will be trimmed after any change in limits.
|
||||
This method always returns cache statistics,
|
||||
useful for determining how much working memory is required for a particular task.
|
||||
|
||||
**Parameters**
|
||||
|
||||
- `options` **([Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) \| [Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean))** Object with the following attributes, or Boolean where true uses default cache settings and false removes all caching.
|
||||
- `options` **([Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) \| [Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean))** Object with the following attributes, or Boolean where true uses default cache settings and false removes all caching (optional, default `true`)
|
||||
- `options.memory` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** is the maximum memory in MB to use for this cache (optional, default `50`)
|
||||
- `options.files` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** is the maximum number of files to hold open (optional, default `20`)
|
||||
- `options.items` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** is the maximum number of operations to cache (optional, default `100`)
|
||||
@@ -37,7 +37,7 @@ Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refer
|
||||
|
||||
## concurrency
|
||||
|
||||
Gets, or when a concurrency is provided sets,
|
||||
Gets or, when a concurrency is provided, sets
|
||||
the number of threads _libvips'_ should create to process each image.
|
||||
The default value is the number of CPU cores.
|
||||
A value of `0` will reset to this default.
|
||||
|
||||
@@ -4,6 +4,45 @@
|
||||
|
||||
Requires libvips v8.5.5.
|
||||
|
||||
#### v0.18.4 - 18<sup>th</sup> September 2017
|
||||
|
||||
* Ensure input Buffer really is marked as Persistent, prevents mark-sweep GC.
|
||||
[#950](https://github.com/lovell/sharp/issues/950)
|
||||
[@lfdoherty](https://github.com/lfdoherty)
|
||||
|
||||
#### v0.18.3 - 13<sup>th</sup> September 2017
|
||||
|
||||
* Skip shrink-on-load when trimming.
|
||||
[#888](https://github.com/lovell/sharp/pull/888)
|
||||
[@kleisauke](https://github.com/kleisauke)
|
||||
|
||||
* Migrate from got to simple-get for basic auth support.
|
||||
[#945](https://github.com/lovell/sharp/pull/945)
|
||||
[@pbomb](https://github.com/pbomb)
|
||||
|
||||
#### v0.18.2 - 1<sup>st</sup> July 2017
|
||||
|
||||
* Expose libvips' xres and yres properties for TIFF output.
|
||||
[#828](https://github.com/lovell/sharp/pull/828)
|
||||
[@YvesBos](https://github.com/YvesBos)
|
||||
|
||||
* Ensure flip and flop operations work with auto-rotate.
|
||||
[#837](https://github.com/lovell/sharp/issues/837)
|
||||
[@rexxars](https://github.com/rexxars)
|
||||
|
||||
* Allow binary download URL override via SHARP_DIST_BASE_URL env variable.
|
||||
[#841](https://github.com/lovell/sharp/issues/841)
|
||||
|
||||
* Add support for Solus Linux.
|
||||
[#857](https://github.com/lovell/sharp/pull/857)
|
||||
[@ekremkaraca](https://github.com/ekremkaraca)
|
||||
|
||||
#### v0.18.1 - 30<sup>th</sup> May 2017
|
||||
|
||||
* Remove regression from #781 that could cause incorrect shrink calculation.
|
||||
[#831](https://github.com/lovell/sharp/issues/831)
|
||||
[@suprMax](https://github.com/suprMax)
|
||||
|
||||
#### v0.18.0 - 30<sup>th</sup> May 2017
|
||||
|
||||
* Remove the previously-deprecated output format "option" functions:
|
||||
|
||||
@@ -100,6 +100,8 @@ the help and code contributions of the following people:
|
||||
* [Alice Monday](https://github.com/alice0meta)
|
||||
* [Kristo Jorgenson](https://github.com/kristojorg)
|
||||
* [Yves Bos](https://github.com/YvesBos)
|
||||
* [Nicolas Coden](https://github.com/ncoden)
|
||||
* [Matt Parrish](https://github.com/pbomb)
|
||||
|
||||
Thank you!
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ yarn add sharp
|
||||
|
||||
### Prerequisites
|
||||
|
||||
* Node v4+
|
||||
* Node v4.5.0+
|
||||
* C++11 compatible compiler such as gcc 4.8+, clang 3.0+ or MSVC 2013+
|
||||
* [node-gyp](https://github.com/TooTallNate/node-gyp#installation) and its dependencies (includes Python)
|
||||
|
||||
@@ -32,6 +32,7 @@ Most recent Linux-based operating systems with glibc running on x64 and ARMv6+ C
|
||||
* Archlinux
|
||||
* Raspbian Jessie
|
||||
* Amazon Linux 2016.03, 2016.09
|
||||
* Solus
|
||||
|
||||
To use a globally-installed version of libvips instead of the provided binaries,
|
||||
make sure it is at least the version listed under `config.libvips` in the `package.json` file
|
||||
@@ -46,10 +47,19 @@ This allows the use of newer versions of libvips with older versions of sharp.
|
||||
For 32-bit Intel CPUs and older Linux-based operating systems such as Centos 6,
|
||||
it is recommended to install a system-wide installation of libvips from source:
|
||||
|
||||
https://github.com/jcupitt/libvips#building-libvips-from-a-source-tarball
|
||||
https://jcupitt.github.io/libvips/install.html#building-libvips-from-a-source-tarball
|
||||
|
||||
For Linux-based operating systems such as Alpine that use musl libc,
|
||||
the smaller stack size means libvips' cache should be disabled
|
||||
#### Alpine Linux
|
||||
|
||||
libvips is available in the
|
||||
[testing repository](https://pkgs.alpinelinux.org/packages?name=vips-dev):
|
||||
|
||||
```sh
|
||||
apk add vips-dev fftw-dev --update-cache --repository https://dl-3.alpinelinux.org/alpine/edge/testing/
|
||||
```
|
||||
|
||||
The smaller stack size of musl libc means
|
||||
libvips may need to be used without a cache
|
||||
via `sharp.cache(false)` to avoid a stack overflow.
|
||||
|
||||
### Mac OS
|
||||
@@ -81,6 +91,9 @@ This can be achieved via [FreshPorts](https://www.freshports.org/graphics/vips/)
|
||||
cd /usr/ports/graphics/vips/ && make install clean
|
||||
```
|
||||
|
||||
FreeBSD's gcc v4 and v5 need `CXXFLAGS=-D_GLIBCXX_USE_C99` set for C++11 support due to
|
||||
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=193528
|
||||
|
||||
### Heroku
|
||||
|
||||
libvips and its dependencies are fetched and stored within `node_modules\sharp\vendor` during `npm install`.
|
||||
@@ -183,16 +196,27 @@ configuration file to prevent the use of coders known to be vulnerable.
|
||||
Set the `MAGICK_CONFIGURE_PATH` environment variable
|
||||
to the directory containing the `policy.xml` file.
|
||||
|
||||
### Licences
|
||||
### Pre-compiled libvips binaries
|
||||
|
||||
If a global installation of libvips that meets the
|
||||
minimum version requirement cannot be found,
|
||||
this module will download a pre-compiled bundle of libvips
|
||||
this module will attempt to download a pre-compiled bundle of libvips
|
||||
and its dependencies on Linux and Windows machines.
|
||||
|
||||
Should you need to manually download and inspect these files,
|
||||
you can do so via https://dl.bintray.com/lovell/sharp/
|
||||
|
||||
Should you wish to install these from your own location,
|
||||
set the `SHARP_DIST_BASE_URL` environment variable, e.g.
|
||||
|
||||
```sh
|
||||
SHARP_DIST_BASE_URL="https://hostname/path/" npm install sharp
|
||||
```
|
||||
|
||||
to use `https://hostname/path/libvips-x.y.z-platform.tar.gz`.
|
||||
|
||||
### Licences
|
||||
|
||||
This module is licensed under the terms of the
|
||||
[Apache 2.0 Licence](https://github.com/lovell/sharp/blob/master/LICENSE).
|
||||
|
||||
|
||||
@@ -180,6 +180,8 @@ const Sharp = function (input, options) {
|
||||
tiffCompression: 'jpeg',
|
||||
tiffPredictor: 'none',
|
||||
tiffSquash: false,
|
||||
tiffXres: 1.0,
|
||||
tiffYres: 1.0,
|
||||
tileSize: 256,
|
||||
tileOverlap: 0,
|
||||
// Function to notify of libvips warnings
|
||||
|
||||
@@ -214,6 +214,8 @@ function webp (options) {
|
||||
* @param {Boolean} [options.force=true] - force TIFF output, otherwise attempt to use input format
|
||||
* @param {Boolean} [options.compression='jpeg'] - compression options: lzw, deflate, jpeg
|
||||
* @param {Boolean} [options.predictor='none'] - compression predictor options: none, horizontal, float
|
||||
* @param {Number} [options.xres=1.0] - horizontal resolution in pixels/mm
|
||||
* @param {Number} [options.yres=1.0] - vertical resolution in pixels/mm
|
||||
* @param {Boolean} [options.squash=false] - squash 8-bit images down to 1 bit
|
||||
* @returns {Sharp}
|
||||
* @throws {Error} Invalid options
|
||||
@@ -233,6 +235,21 @@ function tiff (options) {
|
||||
throw new Error('Invalid Value for squash ' + options.squash + ' Only Boolean Values allowed for options.squash.');
|
||||
}
|
||||
}
|
||||
// resolution
|
||||
if (is.object(options) && is.defined(options.xres)) {
|
||||
if (is.number(options.xres)) {
|
||||
this.options.tiffXres = options.xres;
|
||||
} else {
|
||||
throw new Error('Invalid Value for xres ' + options.xres + ' Only numeric values allowed for options.xres');
|
||||
}
|
||||
}
|
||||
if (is.object(options) && is.defined(options.yres)) {
|
||||
if (is.number(options.yres)) {
|
||||
this.options.tiffYres = options.yres;
|
||||
} else {
|
||||
throw new Error('Invalid Value for yres ' + options.yres + ' Only numeric values allowed for options.yres');
|
||||
}
|
||||
}
|
||||
// compression
|
||||
if (is.defined(options) && is.defined(options.compression)) {
|
||||
if (is.string(options.compression) && is.inArray(options.compression, ['lzw', 'deflate', 'jpeg', 'none'])) {
|
||||
|
||||
@@ -4,7 +4,7 @@ const is = require('./is');
|
||||
const sharp = require('../build/Release/sharp.node');
|
||||
|
||||
/**
|
||||
* Gets, or when options are provided sets, the limits of _libvips'_ operation cache.
|
||||
* Gets or, when options are provided, sets the limits of _libvips'_ operation cache.
|
||||
* Existing entries in the cache will be trimmed after any change in limits.
|
||||
* This method always returns cache statistics,
|
||||
* useful for determining how much working memory is required for a particular task.
|
||||
@@ -16,7 +16,7 @@ const sharp = require('../build/Release/sharp.node');
|
||||
* sharp.cache( { files: 0 } );
|
||||
* sharp.cache(false);
|
||||
*
|
||||
* @param {Object|Boolean} options - Object with the following attributes, or Boolean where true uses default cache settings and false removes all caching.
|
||||
* @param {Object|Boolean} [options=true] - Object with the following attributes, or Boolean where true uses default cache settings and false removes all caching
|
||||
* @param {Number} [options.memory=50] - is the maximum memory in MB to use for this cache
|
||||
* @param {Number} [options.files=20] - is the maximum number of files to hold open
|
||||
* @param {Number} [options.items=100] - is the maximum number of operations to cache
|
||||
@@ -39,7 +39,7 @@ function cache (options) {
|
||||
cache(true);
|
||||
|
||||
/**
|
||||
* Gets, or when a concurrency is provided sets,
|
||||
* Gets or, when a concurrency is provided, sets
|
||||
* the number of threads _libvips'_ should create to process each image.
|
||||
* The default value is the number of CPU cores.
|
||||
* A value of `0` will reset to this default.
|
||||
|
||||
21
package.json
21
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "sharp",
|
||||
"description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP and TIFF images",
|
||||
"version": "0.18.0",
|
||||
"version": "0.18.4",
|
||||
"author": "Lovell Fuller <npm@lovell.info>",
|
||||
"homepage": "https://github.com/lovell/sharp",
|
||||
"contributors": [
|
||||
@@ -37,7 +37,8 @@
|
||||
"Kristo Jorgenson <kristo.jorgenson@gmail.com>",
|
||||
"YvesBos <yves_bos@outlook.com>",
|
||||
"Guy Maliar <guy@tailorbrands.com>",
|
||||
"Nicolas Coden <nicolas@ncoden.fr>"
|
||||
"Nicolas Coden <nicolas@ncoden.fr>",
|
||||
"Matt Parrish <matt.r.parrish@gmail.com>"
|
||||
],
|
||||
"scripts": {
|
||||
"clean": "rm -rf node_modules/ build/ vendor/ coverage/ test/fixtures/output.*",
|
||||
@@ -68,20 +69,21 @@
|
||||
],
|
||||
"dependencies": {
|
||||
"caw": "^2.0.0",
|
||||
"color": "^1.0.3",
|
||||
"got": "^7.0.0",
|
||||
"color": "^2.0.0",
|
||||
"detect-libc": "^0.2.0",
|
||||
"nan": "^2.6.2",
|
||||
"semver": "^5.3.0",
|
||||
"tar": "^3.1.3"
|
||||
"simple-get": "^2.7.0",
|
||||
"tar": "^3.1.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"async": "^2.4.1",
|
||||
"async": "^2.5.0",
|
||||
"cc": "^1.0.1",
|
||||
"documentation": "^4.0.0-rc.1",
|
||||
"exif-reader": "^1.0.2",
|
||||
"icc": "^1.0.0",
|
||||
"mocha": "^3.4.2",
|
||||
"nyc": "^10.3.2",
|
||||
"nyc": "^11.0.3",
|
||||
"rimraf": "^2.6.1",
|
||||
"semistandard": "^11.0.0",
|
||||
"unzip": "^0.1.11"
|
||||
@@ -91,7 +93,7 @@
|
||||
"libvips": "8.5.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
"node": ">=4.5.0"
|
||||
},
|
||||
"semistandard": {
|
||||
"env": [
|
||||
@@ -103,7 +105,8 @@
|
||||
"filter": [
|
||||
"build/c++11",
|
||||
"build/include",
|
||||
"runtime/indentation_namespace"
|
||||
"runtime/indentation_namespace",
|
||||
"runtime/references"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace sharp {
|
||||
|
||||
// Create an InputDescriptor instance from a v8::Object describing an input image
|
||||
InputDescriptor* CreateInputDescriptor(
|
||||
v8::Handle<v8::Object> input, std::vector<v8::Local<v8::Object>> buffersToPersist
|
||||
v8::Handle<v8::Object> input, std::vector<v8::Local<v8::Object>> &buffersToPersist
|
||||
) {
|
||||
Nan::HandleScope();
|
||||
InputDescriptor *descriptor = new InputDescriptor;
|
||||
@@ -438,9 +438,11 @@ namespace sharp {
|
||||
// Southeast
|
||||
left = inWidth - outWidth;
|
||||
top = inHeight - outHeight;
|
||||
break;
|
||||
case 7:
|
||||
// Southwest
|
||||
top = inHeight - outHeight;
|
||||
break;
|
||||
case 8:
|
||||
// Northwest
|
||||
break;
|
||||
|
||||
@@ -89,7 +89,7 @@ namespace sharp {
|
||||
|
||||
// Create an InputDescriptor instance from a v8::Object describing an input image
|
||||
InputDescriptor* CreateInputDescriptor(
|
||||
v8::Handle<v8::Object> input, std::vector<v8::Local<v8::Object>> buffersToPersist);
|
||||
v8::Handle<v8::Object> input, std::vector<v8::Local<v8::Object>> &buffersToPersist);
|
||||
|
||||
enum class ImageType {
|
||||
JPEG,
|
||||
|
||||
@@ -83,8 +83,11 @@ class PipelineWorker : public Nan::AsyncWorker {
|
||||
VipsAngle rotation;
|
||||
if (baton->useExifOrientation) {
|
||||
// Rotate and flip image according to Exif orientation
|
||||
// (ignore the requested rotation and flip)
|
||||
std::tie(rotation, baton->flip, baton->flop) = CalculateExifRotationAndFlip(sharp::ExifOrientation(image));
|
||||
bool flip;
|
||||
bool flop;
|
||||
std::tie(rotation, flip, flop) = CalculateExifRotationAndFlip(sharp::ExifOrientation(image));
|
||||
baton->flip = baton->flip || flip;
|
||||
baton->flop = baton->flop || flop;
|
||||
} else {
|
||||
rotation = CalculateAngleRotation(baton->angle);
|
||||
}
|
||||
@@ -217,12 +220,12 @@ class PipelineWorker : public Nan::AsyncWorker {
|
||||
}
|
||||
|
||||
// If integral x and y shrink are equal, try to use shrink-on-load for JPEG and WebP,
|
||||
// but not when applying gamma correction or pre-resize extract
|
||||
// but not when applying gamma correction, pre-resize extract or trim
|
||||
int shrink_on_load = 1;
|
||||
if (
|
||||
xshrink == yshrink && xshrink >= 2 &&
|
||||
(inputImageType == ImageType::JPEG || inputImageType == ImageType::WEBP) &&
|
||||
baton->gamma == 0 && baton->topOffsetPre == -1
|
||||
baton->gamma == 0 && baton->topOffsetPre == -1 && baton->trimTolerance == 0
|
||||
) {
|
||||
if (xshrink >= 8) {
|
||||
xfactor = xfactor / 8;
|
||||
@@ -288,11 +291,11 @@ class PipelineWorker : public Nan::AsyncWorker {
|
||||
}
|
||||
}
|
||||
// Help ensure a final kernel-based reduction to prevent shrink aliasing
|
||||
if ((xshrink > 1 || yshrink > 1) && (xresidual == 1.0 || yresidual == 1.0)) {
|
||||
if (xshrink > 1 && yshrink > 1 && (xresidual == 1.0 || yresidual == 1.0)) {
|
||||
xshrink = xshrink / 2;
|
||||
yshrink = yshrink / 2;
|
||||
xresidual = xresidual / 2.0;
|
||||
yresidual = yresidual / 2.0;
|
||||
xresidual = static_cast<double>(xshrink) / xfactor;
|
||||
yresidual = static_cast<double>(yshrink) / yfactor;
|
||||
}
|
||||
|
||||
// Ensure we're using a device-independent colour space
|
||||
@@ -808,7 +811,9 @@ class PipelineWorker : public Nan::AsyncWorker {
|
||||
->set("Q", baton->tiffQuality)
|
||||
->set("squash", baton->tiffSquash)
|
||||
->set("compression", baton->tiffCompression)
|
||||
->set("predictor", baton->tiffPredictor)));
|
||||
->set("predictor", baton->tiffPredictor)
|
||||
->set("xres", baton->tiffXres)
|
||||
->set("yres", baton->tiffYres)));
|
||||
baton->bufferOut = static_cast<char*>(area->data);
|
||||
baton->bufferOutLength = area->length;
|
||||
area->free_fn = nullptr;
|
||||
@@ -904,7 +909,9 @@ class PipelineWorker : public Nan::AsyncWorker {
|
||||
->set("Q", baton->tiffQuality)
|
||||
->set("squash", baton->tiffSquash)
|
||||
->set("compression", baton->tiffCompression)
|
||||
->set("predictor", baton->tiffPredictor));
|
||||
->set("predictor", baton->tiffPredictor)
|
||||
->set("xres", baton->tiffXres)
|
||||
->set("yres", baton->tiffYres));
|
||||
baton->formatOut = "tiff";
|
||||
baton->channels = std::min(baton->channels, 3);
|
||||
} else if (baton->formatOut == "dz" || isDz || isDzZip) {
|
||||
@@ -1277,6 +1284,8 @@ NAN_METHOD(pipeline) {
|
||||
baton->webpNearLossless = AttrTo<bool>(options, "webpNearLossless");
|
||||
baton->tiffQuality = AttrTo<uint32_t>(options, "tiffQuality");
|
||||
baton->tiffSquash = AttrTo<bool>(options, "tiffSquash");
|
||||
baton->tiffXres = AttrTo<double>(options, "tiffXres");
|
||||
baton->tiffYres = AttrTo<double>(options, "tiffYres");
|
||||
// tiff compression options
|
||||
baton->tiffCompression = static_cast<VipsForeignTiffCompression>(
|
||||
vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_TIFF_COMPRESSION,
|
||||
|
||||
@@ -109,6 +109,8 @@ struct PipelineBaton {
|
||||
VipsForeignTiffCompression tiffCompression;
|
||||
VipsForeignTiffPredictor tiffPredictor;
|
||||
bool tiffSquash;
|
||||
double tiffXres;
|
||||
double tiffYres;
|
||||
std::string err;
|
||||
bool withMetadata;
|
||||
int withMetadataOrientation;
|
||||
@@ -182,6 +184,8 @@ struct PipelineBaton {
|
||||
tiffCompression(VIPS_FOREIGN_TIFF_COMPRESSION_JPEG),
|
||||
tiffPredictor(VIPS_FOREIGN_TIFF_PREDICTOR_NONE),
|
||||
tiffSquash(false),
|
||||
tiffXres(1.0),
|
||||
tiffYres(1.0),
|
||||
withMetadata(false),
|
||||
withMetadataOrientation(-1),
|
||||
convKernelWidth(0),
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
"test": "node perf && node random && node parallel"
|
||||
},
|
||||
"devDependencies": {
|
||||
"async": "^2.1.4",
|
||||
"benchmark": "^2.1.2",
|
||||
"async": "^2.5.0",
|
||||
"benchmark": "^2.1.4",
|
||||
"gm": "^1.23.0",
|
||||
"imagemagick": "^0.1.3",
|
||||
"imagemagick-native": "^1.9.3",
|
||||
"images": "^3.0.0",
|
||||
"jimp": "^0.2.27",
|
||||
"mapnik": "^3.6.0",
|
||||
"jimp": "^0.2.28",
|
||||
"mapnik": "^3.6.2",
|
||||
"pajk-lwip": "^0.2.0",
|
||||
"semver": "^5.3.0"
|
||||
},
|
||||
|
||||
@@ -12,7 +12,12 @@ const gm = require('gm');
|
||||
const imagemagick = require('imagemagick');
|
||||
const mapnik = require('mapnik');
|
||||
const jimp = require('jimp');
|
||||
const images = require('images');
|
||||
let images;
|
||||
try {
|
||||
images = require('images');
|
||||
} catch (err) {
|
||||
console.log('Excluding node-images');
|
||||
}
|
||||
let imagemagickNative;
|
||||
try {
|
||||
imagemagickNative = require('imagemagick-native');
|
||||
@@ -268,11 +273,13 @@ async.series({
|
||||
}
|
||||
});
|
||||
// images
|
||||
jpegSuite.add('images-file-file', function () {
|
||||
images(fixtures.inputJpg)
|
||||
.resize(width, height)
|
||||
.save(fixtures.outputJpg, { quality: 80 });
|
||||
});
|
||||
if (typeof images !== 'undefined') {
|
||||
jpegSuite.add('images-file-file', function () {
|
||||
images(fixtures.inputJpg)
|
||||
.resize(width, height)
|
||||
.save(fixtures.outputJpg, { quality: 80 });
|
||||
});
|
||||
}
|
||||
// sharp
|
||||
jpegSuite.add('sharp-buffer-file', {
|
||||
defer: true,
|
||||
@@ -827,11 +834,13 @@ async.series({
|
||||
}
|
||||
});
|
||||
// images
|
||||
pngSuite.add('images-file-file', function () {
|
||||
images(fixtures.inputPng)
|
||||
.resize(width, height)
|
||||
.save(fixtures.outputPng);
|
||||
});
|
||||
if (typeof images !== 'undefined') {
|
||||
pngSuite.add('images-file-file', function () {
|
||||
images(fixtures.inputPng)
|
||||
.resize(width, height)
|
||||
.save(fixtures.outputPng);
|
||||
});
|
||||
}
|
||||
// sharp
|
||||
pngSuite.add('sharp-buffer-file', {
|
||||
defer: true,
|
||||
|
||||
BIN
test/fixtures/alpha-layer-2-ink.jpg
vendored
Normal file
BIN
test/fixtures/alpha-layer-2-ink.jpg
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
BIN
test/fixtures/expected/alpha-layer-2-trim-resize.jpg
vendored
Normal file
BIN
test/fixtures/expected/alpha-layer-2-trim-resize.jpg
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.2 KiB |
BIN
test/fixtures/expected/resize-diff-shrink-even.jpg
vendored
Normal file
BIN
test/fixtures/expected/resize-diff-shrink-even.jpg
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.0 KiB |
BIN
test/fixtures/expected/resize-diff-shrink-odd.jpg
vendored
Normal file
BIN
test/fixtures/expected/resize-diff-shrink-odd.jpg
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.3 KiB |
BIN
test/fixtures/expected/rotate-and-flip.jpg
vendored
Normal file
BIN
test/fixtures/expected/rotate-and-flip.jpg
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
BIN
test/fixtures/expected/rotate-and-flop.jpg
vendored
Normal file
BIN
test/fixtures/expected/rotate-and-flop.jpg
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
1
test/fixtures/index.js
vendored
1
test/fixtures/index.js
vendored
@@ -65,6 +65,7 @@ module.exports = {
|
||||
inputJpgWithLowContrast: getPath('low-contrast.jpg'), // http://www.flickr.com/photos/grizdave/2569067123/
|
||||
inputJpgLarge: getPath('giant-image.jpg'),
|
||||
inputJpg320x240: getPath('320x240.jpg'), // http://www.andrewault.net/2010/01/26/create-a-test-pattern-video-with-perl/
|
||||
inputJpgOverlayLayer2: getPath('alpha-layer-2-ink.jpg'),
|
||||
|
||||
inputPng: getPath('50020484-00001.png'), // http://c.searspartsdirect.com/lis_png/PLDM/50020484-00001.png
|
||||
inputPngWithTransparency: getPath('blackbug.png'), // public domain
|
||||
|
||||
@@ -933,6 +933,53 @@ describe('Input/output', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('TIFF setting xres and yres on file', function (done) {
|
||||
const res = 1000.0; // inputTiff has a dpi of 300 (res*2.54)
|
||||
sharp(fixtures.inputTiff)
|
||||
.tiff({
|
||||
xres: (res),
|
||||
yres: (res)
|
||||
})
|
||||
.toFile(fixtures.outputTiff, (err, info) => {
|
||||
if (err) throw err;
|
||||
assert.strictEqual('tiff', info.format);
|
||||
sharp(fixtures.outputTiff).metadata(function (err, metadata) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(metadata.density, res * 2.54); // convert to dpi
|
||||
fs.unlink(fixtures.outputTiff, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('TIFF setting xres and yres on buffer', function (done) {
|
||||
const res = 1000.0; // inputTiff has a dpi of 300 (res*2.54)
|
||||
sharp(fixtures.inputTiff)
|
||||
.tiff({
|
||||
xres: (res),
|
||||
yres: (res)
|
||||
})
|
||||
.toBuffer(function (err, data, info) {
|
||||
if (err) throw err;
|
||||
sharp(data).metadata(function (err, metadata) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(metadata.density, res * 2.54); // convert to dpi
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('TIFF invalid xres value should throw an error', function () {
|
||||
assert.throws(function () {
|
||||
sharp().tiff({ xres: '1000.0' });
|
||||
});
|
||||
});
|
||||
|
||||
it('TIFF invalid yres value should throw an error', function () {
|
||||
assert.throws(function () {
|
||||
sharp().tiff({ yres: '1000.0' });
|
||||
});
|
||||
});
|
||||
|
||||
it('TIFF lzw compression with horizontal predictor shrinks test file', function (done) {
|
||||
const startSize = fs.statSync(fixtures.inputTiffUncompressed).size;
|
||||
sharp(fixtures.inputTiffUncompressed)
|
||||
|
||||
@@ -412,4 +412,40 @@ describe('Resize dimensions', function () {
|
||||
sharp().resize(32, 24, { centreSampling: 1 });
|
||||
});
|
||||
});
|
||||
|
||||
it('Dimensions that result in differing even shrinks on each axis', function (done) {
|
||||
sharp(fixtures.inputJpg)
|
||||
.resize(645, 399)
|
||||
.toBuffer(function (err, data, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(645, info.width);
|
||||
assert.strictEqual(399, info.height);
|
||||
sharp(data)
|
||||
.resize(150, 100)
|
||||
.toBuffer(function (err, data, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(150, info.width);
|
||||
assert.strictEqual(100, info.height);
|
||||
fixtures.assertSimilar(fixtures.expected('resize-diff-shrink-even.jpg'), data, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Dimensions that result in differing odd shrinks on each axis', function (done) {
|
||||
return sharp(fixtures.inputJpg)
|
||||
.resize(600, 399)
|
||||
.toBuffer(function (err, data, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(600, info.width);
|
||||
assert.strictEqual(399, info.height);
|
||||
sharp(data)
|
||||
.resize(200)
|
||||
.toBuffer(function (err, data, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(200, info.width);
|
||||
assert.strictEqual(133, info.height);
|
||||
fixtures.assertSimilar(fixtures.expected('resize-diff-shrink-odd.jpg'), data, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -253,4 +253,32 @@ describe('Rotation', function () {
|
||||
fixtures.assertSimilar(fixtures.inputJpg, data, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('Auto-rotate and flip', function (done) {
|
||||
sharp(fixtures.inputJpgWithExif)
|
||||
.rotate()
|
||||
.flip()
|
||||
.resize(320)
|
||||
.toBuffer(function (err, data, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual('jpeg', info.format);
|
||||
assert.strictEqual(320, info.width);
|
||||
assert.strictEqual(240, info.height);
|
||||
fixtures.assertSimilar(fixtures.expected('rotate-and-flip.jpg'), data, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('Auto-rotate and flop', function (done) {
|
||||
sharp(fixtures.inputJpgWithExif)
|
||||
.rotate()
|
||||
.flop()
|
||||
.resize(320)
|
||||
.toBuffer(function (err, data, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual('jpeg', info.format);
|
||||
assert.strictEqual(320, info.width);
|
||||
assert.strictEqual(240, info.height);
|
||||
fixtures.assertSimilar(fixtures.expected('rotate-and-flop.jpg'), data, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -20,6 +20,20 @@ describe('Trim borders', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('Skip shrink-on-load', function (done) {
|
||||
const expected = fixtures.expected('alpha-layer-2-trim-resize.jpg');
|
||||
sharp(fixtures.inputJpgOverlayLayer2)
|
||||
.trim()
|
||||
.resize(300)
|
||||
.toBuffer(function (err, data, info) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual('jpeg', info.format);
|
||||
assert.strictEqual(300, info.width);
|
||||
assert.strictEqual(300, info.height);
|
||||
fixtures.assertSimilar(expected, data, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('16-bit PNG with alpha channel', function (done) {
|
||||
sharp(fixtures.inputPngWithTransparency16bit)
|
||||
.resize(32, 32)
|
||||
|
||||
Reference in New Issue
Block a user