Compare commits

...

28 Commits

Author SHA1 Message Date
Lovell Fuller
3511723914 Release v0.18.4 2017-09-18 18:26:12 +01:00
Lovell Fuller
6a1c7b7588 Ensure input Buffer really is marked as Persistent #950 2017-09-16 20:17:32 +01:00
Lovell Fuller
18fd6ef119 Release v0.18.3 2017-09-13 10:51:08 +01:00
Matt Parrish
0004f5d2ff Migrate from got to simple-get (#945)
The simple-get module provides support for basic auth and
is already used by the future prebuild dependency.
2017-09-12 07:38:17 +01:00
Mario Viens
5f29d1ba9c Clarifying cache documentation (#919) 2017-08-19 10:43:36 +01:00
Jasper Blues
791fd35c35 Update README.md (#913) 2017-08-16 12:09:02 +01:00
Kleis Auke Wolthuizen
e0d622d347 Skip shrink-on-load when trimming (#887) (#888) 2017-07-28 21:02:30 +01:00
Lovell Fuller
6b34e8a804 Docs: FreeBSD gcc v4/v5 needs _GLIBCXX_USE_C99 for C++11 #873 2017-07-25 14:54:44 +01:00
Lovell Fuller
eb8773fe3e Use detect-libc instead of ldd output parsing 2017-07-17 12:11:13 +01:00
Lovell Fuller
b40e3fa1f1 Docs: Alpine vips-dev package requires fftw-dev also 2017-07-15 14:47:25 +01:00
Lovell Fuller
d25d761b55 Update benchmark deps, allow node-images to fail 2017-07-14 13:18:13 +01:00
Lovell Fuller
d6051dd714 Release v0.18.2 2017-07-01 09:52:47 +01:00
Lovell Fuller
53ff061efa Document SHARP_DIST_BASE_URL #841 2017-07-01 09:44:02 +01:00
Lovell Fuller
72b0efd393 Remove possible switch case fall through
Luckily there were no side effects in this... case
2017-06-25 19:09:20 +01:00
Lovell Fuller
df97ef23d9 Document/changelog for Solus Linux support #857 2017-06-25 17:42:03 +01:00
Ekrem Karaca
f6373971bd Add support for Solus OS (#857) 2017-06-24 13:48:03 +01:00
Lovell Fuller
ec617f2489 Document minimum Node dependency of v4.5.0 #847 2017-06-20 22:05:05 +01:00
Lovell Fuller
502ae78579 Allow binary download URL override via SHARP_DIST_BASE_URL #841 2017-06-20 21:40:46 +01:00
Lovell Fuller
49297d6afb Ensure flip and flop operations work with auto-rotate #837 2017-06-19 23:42:26 +01:00
Lovell Fuller
29354badd8 Docs: add Alpine Linux install details 2017-06-19 08:13:49 +01:00
Lovell Fuller
3c4de796c8 Dependency bumps and next point release 2017-06-04 19:55:45 +01:00
Lovell Fuller
c7f4488e77 Docs and changelog entry for #828 2017-06-04 19:51:22 +01:00
Yves Bos
d8765f955d Allow xres and yres to be set for TIFF output (#828) 2017-06-03 10:52:09 +01:00
Lovell Fuller
9f20037dad Release v0.18.1 2017-05-30 21:02:35 +01:00
Lovell Fuller
2ebb090df2 Update Travis CI to Ubuntu 16.04
Rollback Appveyor CI from Node 8 to 7
2017-05-30 20:50:32 +01:00
Lovell Fuller
110fff3ab9 Replace Node 7 with Node 8 in CI environment 2017-05-30 20:32:15 +01:00
Lovell Fuller
f42a1ceab7 Recalculate residual after adjusting shrink #831 2017-05-30 20:22:15 +01:00
Lovell Fuller
9e39a7fa95 Correct shrink calc, regression introduced in e398b47 #831 2017-05-30 17:16:41 +01:00
31 changed files with 334 additions and 86 deletions

View File

@@ -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

View File

@@ -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()

View File

@@ -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'

View File

@@ -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);
});
}
}
};

View File

@@ -1,6 +1,6 @@
machine:
node:
version: v4.6.1
version: v4.8.4
services:
- docker
test:

View File

@@ -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`)

View File

@@ -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.

View File

@@ -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:

View File

@@ -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!

View File

@@ -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).

View File

@@ -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

View File

@@ -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'])) {

View File

@@ -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.

View File

@@ -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"
]
}
}

View File

@@ -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;

View File

@@ -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,

View File

@@ -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,

View File

@@ -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),

View File

@@ -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"
},

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -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

View File

@@ -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)

View File

@@ -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);
});
});
});
});

View File

@@ -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);
});
});
});

View File

@@ -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)