Upgrade to libvips v8.8.0, remove deprecated overlayWith

This commit is contained in:
Lovell Fuller 2019-05-21 23:11:27 +01:00
parent cfa4f7d45c
commit 631a3597c7
43 changed files with 3064 additions and 3563 deletions

1
.gitignore vendored
View File

@ -12,4 +12,5 @@ vendor
.gitattributes .gitattributes
.DS_Store .DS_Store
.nyc_output .nyc_output
.vscode/
package-lock.json package-lock.json

View File

@ -13,3 +13,4 @@ vendor
.prebuildrc .prebuildrc
.nyc_output .nyc_output
.github/ .github/
.vscode/

View File

@ -1,11 +1,5 @@
matrix: matrix:
include: include:
- name: "Linux (glibc) - Node 6"
os: linux
dist: trusty
sudo: false
language: node_js
node_js: "6"
- name: "Linux (glibc) - Node 8" - name: "Linux (glibc) - Node 8"
os: linux os: linux
dist: trusty dist: trusty
@ -27,12 +21,6 @@ matrix:
after_success: after_success:
- npm install coveralls - npm install coveralls
- cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js - cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js
- name: "Linux (glibc) - Node 11"
os: linux
dist: trusty
sudo: false
language: node_js
node_js: "11"
- name: "Linux (musl) - Node 8" - name: "Linux (musl) - Node 8"
os: linux os: linux
dist: trusty dist: trusty
@ -53,16 +41,6 @@ matrix:
- sudo docker exec sharp apk add build-base git python2 --update-cache - sudo docker exec sharp apk add build-base git python2 --update-cache
install: sudo docker exec sharp sh -c "npm install --unsafe-perm" install: sudo docker exec sharp sh -c "npm install --unsafe-perm"
script: sudo docker exec sharp sh -c "npm test" script: sudo docker exec sharp sh -c "npm test"
- name: "Linux (musl) - Node 11"
os: linux
dist: trusty
sudo: true
language: minimal
before_install:
- sudo docker run -dit --name sharp --env CI --env PREBUILD_TOKEN --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp node:11-alpine
- sudo docker exec sharp apk add build-base git python2 --update-cache
install: sudo docker exec sharp sh -c "npm install --unsafe-perm"
script: sudo docker exec sharp sh -c "npm test"
- name: "Linux (musl) - Node 12" - name: "Linux (musl) - Node 12"
os: linux os: linux
dist: trusty dist: trusty
@ -73,11 +51,6 @@ matrix:
- sudo docker exec sharp apk add build-base git python2 --update-cache - sudo docker exec sharp apk add build-base git python2 --update-cache
install: sudo docker exec sharp sh -c "npm install --unsafe-perm" install: sudo docker exec sharp sh -c "npm install --unsafe-perm"
script: sudo docker exec sharp sh -c "npm test" script: sudo docker exec sharp sh -c "npm test"
- name: "OS X - Node 6"
os: osx
osx_image: xcode9.2
language: node_js
node_js: "6"
- name: "OS X - Node 8" - name: "OS X - Node 8"
os: osx os: osx
osx_image: xcode9.2 osx_image: xcode9.2
@ -88,11 +61,6 @@ matrix:
osx_image: xcode9.2 osx_image: xcode9.2
language: node_js language: node_js
node_js: "10" node_js: "10"
- name: "OS X - Node 11"
os: osx
osx_image: xcode9.2
language: node_js
node_js: "11"
- name: "OS X - Node 12" - name: "OS X - Node 12"
os: osx os: osx
osx_image: xcode9.2 osx_image: xcode9.2

View File

@ -20,7 +20,7 @@ As well as image resizing, operations such as
rotation, extraction, compositing and gamma correction are available. rotation, extraction, compositing and gamma correction are available.
Most modern 64-bit OS X, Windows and Linux systems running Most modern 64-bit OS X, Windows and Linux systems running
Node versions 6, 8, 10, 11 and 12 Node versions 8, 10 and 12
do not require any additional install or runtime dependencies. do not require any additional install or runtime dependencies.
## Examples ## Examples

View File

@ -4,10 +4,8 @@ build: off
platform: x64 platform: x64
environment: environment:
matrix: matrix:
- nodejs_version: "6"
- nodejs_version: "8" - nodejs_version: "8"
- nodejs_version: "10" - nodejs_version: "10"
- nodejs_version: "11"
- nodejs_version: "12" - nodejs_version: "12"
install: install:
- ps: Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version) x64 - ps: Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version) x64

View File

@ -97,7 +97,8 @@
'conditions': [ 'conditions': [
['OS == "win"', { ['OS == "win"', {
'defines': [ 'defines': [
'_ALLOW_KEYWORD_MACROS' '_ALLOW_KEYWORD_MACROS',
'_FILE_OFFSET_BITS=64'
], ],
'libraries': [ 'libraries': [
'../vendor/lib/libvips.lib', '../vendor/lib/libvips.lib',
@ -183,22 +184,15 @@
'configurations': { 'configurations': {
'Release': { 'Release': {
'cflags_cc': [ 'cflags_cc': [
'-Wno-cast-function-type', '-Wno-cast-function-type'
'-Wno-deprecated-declarations'
], ],
'xcode_settings': {
'OTHER_CPLUSPLUSFLAGS': [
'-Wno-deprecated-declarations'
]
},
'msvs_settings': { 'msvs_settings': {
'VCCLCompilerTool': { 'VCCLCompilerTool': {
'ExceptionHandling': 1 'ExceptionHandling': 1
} }
}, },
'msvs_disabled_warnings': [ 'msvs_disabled_warnings': [
4275, 4275
4996
] ]
} }
}, },

View File

@ -1,5 +1,16 @@
# Changelog # Changelog
### v0.23 - "*vision*"
Requires libvips v8.8.0.
#### v0.23.0 - TBD
* Remove `overlayWith` previously deprecated in v0.22.0.
* Drop support for Node.js versions 6 and 11.
[#1212](https://github.com/lovell/sharp/issues/1674)
### v0.22 - "*uptake*" ### v0.22 - "*uptake*"
Requires libvips v8.7.4. Requires libvips v8.7.4.

View File

@ -16,7 +16,7 @@ As well as image resizing, operations such as
rotation, extraction, compositing and gamma correction are available. rotation, extraction, compositing and gamma correction are available.
Most modern 64-bit OS X, Windows and Linux systems running Most modern 64-bit OS X, Windows and Linux systems running
Node versions 6, 8, 10, 11 and 12 Node versions 8, 10 and 12
do not require any additional install or runtime dependencies. do not require any additional install or runtime dependencies.
[![Test Coverage](https://coveralls.io/repos/lovell/sharp/badge.png?branch=master)](https://coveralls.io/r/lovell/sharp?branch=master) [![Test Coverage](https://coveralls.io/repos/lovell/sharp/badge.png?branch=master)](https://coveralls.io/r/lovell/sharp?branch=master)

View File

@ -10,12 +10,12 @@ yarn add sharp
## Prerequisites ## Prerequisites
* Node.js v6+ * Node.js v8.5.0+
### Building from source ### Building from source
Pre-compiled binaries for sharp are provided for use with Pre-compiled binaries for sharp are provided for use with
Node versions 6, 8, 10, 11 and 12 on Node versions 8, 10 and 12 on
64-bit Windows, OS X and Linux platforms. 64-bit Windows, OS X and Linux platforms.
Sharp will be built from source at install time when: Sharp will be built from source at install time when:
@ -36,19 +36,20 @@ Building from source requires:
[![Ubuntu 16.04 Build Status](https://travis-ci.org/lovell/sharp.png?branch=master)](https://travis-ci.org/lovell/sharp) [![Ubuntu 16.04 Build Status](https://travis-ci.org/lovell/sharp.png?branch=master)](https://travis-ci.org/lovell/sharp)
libvips and its dependencies are fetched and stored within `node_modules/sharp/vendor` during `npm install`. libvips and its dependencies are fetched and stored within `node_modules/sharp/vendor` during `npm install`.
This involves an automated HTTPS download of approximately 9MB. This involves an automated HTTPS download of approximately 10MB.
Most Linux-based (glibc, musl) operating systems running on x64 and ARMv6+ CPUs should "just work", e.g.: Most Linux-based (glibc, musl) operating systems running on x64 and ARMv6+ CPUs should "just work", e.g.:
* Debian 7+ * Debian 8+
* Ubuntu 14.04+ * Ubuntu 14.04+
* Centos 7+ * Red Hat Enterprise 8
* Alpine 3.8+ (Node 8+) * CentOS 8
* Alpine 3.8+
* Fedora * Fedora
* openSUSE 13.2+ * openSUSE 13.2+
* Archlinux * Archlinux
* Raspbian Jessie * Raspbian Jessie
* Amazon Linux * Amazon Linux 2
* Solus * Solus
To use a globally-installed version of libvips instead of the provided binaries, To use a globally-installed version of libvips instead of the provided binaries,
@ -61,7 +62,8 @@ and `LD_LIBRARY_PATH` at runtime.
This allows the use of newer versions of libvips with older versions of sharp. 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, For 32-bit Intel CPUs and older Linux-based operating systems such as
those based on Red Hat Enterprise Linux 7 (e.g. CentOS 7, Amazon Linux 1)
compiling libvips from source is recommended. compiling libvips from source is recommended.
[https://libvips.github.io/libvips/install.html#building-libvips-from-a-source-tarball](https://libvips.github.io/libvips/install.html#building-libvips-from-a-source-tarball) [https://libvips.github.io/libvips/install.html#building-libvips-from-a-source-tarball](https://libvips.github.io/libvips/install.html#building-libvips-from-a-source-tarball)
@ -97,7 +99,7 @@ that it can be located using `pkg-config --modversion vips-cpp`.
[![Windows x64 Build Status](https://ci.appveyor.com/api/projects/status/pgtul704nkhhg6sg)](https://ci.appveyor.com/project/lovell/sharp) [![Windows x64 Build Status](https://ci.appveyor.com/api/projects/status/pgtul704nkhhg6sg)](https://ci.appveyor.com/project/lovell/sharp)
libvips and its dependencies are fetched and stored within `node_modules\sharp\vendor` during `npm install`. libvips and its dependencies are fetched and stored within `node_modules\sharp\vendor` during `npm install`.
This involves an automated HTTPS download of approximately 14MB. This involves an automated HTTPS download of approximately 10MB.
If you are having issues during installation consider removing the directory If you are having issues during installation consider removing the directory
`C:\Users\[user]\AppData\Roaming\npm-cache\_libvips`. `C:\Users\[user]\AppData\Roaming\npm-cache\_libvips`.
@ -150,7 +152,7 @@ docker pull tailor/docker-libvips
### AWS Lambda ### AWS Lambda
Set the Lambda runtime to Node.js 8.10. Set the Lambda runtime to `nodejs10.x`.
The binaries in the `node_modules` directory of the The binaries in the `node_modules` directory of the
[deployment package](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-create-deployment-pkg.html) [deployment package](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-create-deployment-pkg.html)
@ -160,14 +162,14 @@ On non-Linux machines such as OS X and Windows run the following:
```sh ```sh
rm -rf node_modules/sharp rm -rf node_modules/sharp
npm install --arch=x64 --platform=linux --target=8.10.0 sharp npm install --arch=x64 --platform=linux --target=10.15.0 sharp
``` ```
Alternatively a Docker container closely matching the Lambda runtime can be used: Alternatively a Docker container closely matching the Lambda runtime can be used:
```sh ```sh
rm -rf node_modules/sharp rm -rf node_modules/sharp
docker run -v "$PWD":/var/task lambci/lambda:build-nodejs8.10 npm install sharp docker run -v "$PWD":/var/task lambci/lambda:build-nodejs10.x npm install sharp
``` ```
To get the best performance select the largest memory available. To get the best performance select the largest memory available.

View File

@ -3,7 +3,6 @@
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const copyFileSync = require('fs-copy-file-sync');
const libvips = require('../lib/libvips'); const libvips = require('../lib/libvips');
const npmLog = require('npmlog'); const npmLog = require('npmlog');
@ -24,7 +23,7 @@ if (process.platform === 'win32') {
return /\.dll$/.test(filename); return /\.dll$/.test(filename);
}) })
.forEach(function (filename) { .forEach(function (filename) {
copyFileSync( fs.copyFileSync(
path.join(vendorLibDir, filename), path.join(vendorLibDir, filename),
path.join(buildReleaseDir, filename) path.join(buildReleaseDir, filename)
); );

View File

@ -9,7 +9,6 @@ const npmLog = require('npmlog');
const semver = require('semver'); const semver = require('semver');
const simpleGet = require('simple-get'); const simpleGet = require('simple-get');
const tar = require('tar'); const tar = require('tar');
const copyFileSync = require('fs-copy-file-sync');
const agent = require('../lib/agent'); const agent = require('../lib/agent');
const libvips = require('../lib/libvips'); const libvips = require('../lib/libvips');
@ -64,7 +63,7 @@ try {
if (platformAndArch === 'freebsd-x64' || platformAndArch === 'openbsd-x64' || platformAndArch === 'sunos-x64') { if (platformAndArch === 'freebsd-x64' || platformAndArch === 'openbsd-x64' || platformAndArch === 'sunos-x64') {
throw new Error(`BSD/SunOS systems require manual installation of libvips >= ${minimumLibvipsVersion}`); throw new Error(`BSD/SunOS systems require manual installation of libvips >= ${minimumLibvipsVersion}`);
} }
if (detectLibc.family === detectLibc.GLIBC && detectLibc.version && semver.lt(`${detectLibc.version}.0`, '2.13.0')) { if (detectLibc.family === detectLibc.GLIBC && detectLibc.version && semver.lt(`${detectLibc.version}.0`, '2.19.0')) {
throw new Error(`Use with glibc version ${detectLibc.version} requires manual installation of libvips >= ${minimumLibvipsVersion}`); throw new Error(`Use with glibc version ${detectLibc.version} requires manual installation of libvips >= ${minimumLibvipsVersion}`);
} }
// Download to per-process temporary file // Download to per-process temporary file
@ -97,7 +96,7 @@ try {
fs.renameSync(tarPathTemp, tarPathCache); fs.renameSync(tarPathTemp, tarPathCache);
} catch (err) { } catch (err) {
// Fall back to copy and unlink // Fall back to copy and unlink
copyFileSync(tarPathTemp, tarPathCache); fs.copyFileSync(tarPathTemp, tarPathCache);
fs.unlinkSync(tarPathTemp); fs.unlinkSync(tarPathTemp);
} }
extractTarball(tarPathCache); extractTarball(tarPathCache);

View File

@ -1,7 +1,5 @@
'use strict'; 'use strict';
const deprecate = require('util').deprecate;
const is = require('./is'); const is = require('./is');
/** /**
@ -154,21 +152,11 @@ function composite (images) {
return this; return this;
} }
/**
* @deprecated
* @private
*/
function overlayWith (input, options) {
const blend = (is.object(options) && options.cutout) ? 'dest-in' : 'over';
return this.composite([Object.assign({ input, blend }, options)]);
}
/** /**
* Decorate the Sharp prototype with composite-related functions. * Decorate the Sharp prototype with composite-related functions.
* @private * @private
*/ */
module.exports = function (Sharp) { module.exports = function (Sharp) {
Sharp.prototype.composite = composite; Sharp.prototype.composite = composite;
Sharp.prototype.overlayWith = deprecate(overlayWith, 'overlayWith(input, options) is deprecated, use composite([{ input, ...options }]) instead');
Sharp.blend = blend; Sharp.blend = blend;
}; };

View File

@ -93,39 +93,38 @@
"vips" "vips"
], ],
"dependencies": { "dependencies": {
"color": "^3.1.1", "color": "^3.1.2",
"detect-libc": "^1.0.3", "detect-libc": "^1.0.3",
"fs-copy-file-sync": "^1.1.1", "nan": "^2.14.0",
"nan": "^2.13.2",
"npmlog": "^4.1.2", "npmlog": "^4.1.2",
"prebuild-install": "^5.3.0", "prebuild-install": "^5.3.0",
"semver": "^6.0.0", "semver": "^6.1.2",
"simple-get": "^3.0.3", "simple-get": "^3.0.3",
"tar": "^4.4.8", "tar": "^4.4.10",
"tunnel-agent": "^0.6.0" "tunnel-agent": "^0.6.0"
}, },
"devDependencies": { "devDependencies": {
"async": "^2.6.2", "async": "^3.1.0",
"cc": "^1.0.2", "cc": "^1.0.2",
"decompress-zip": "^0.3.2", "decompress-zip": "^0.3.2",
"documentation": "^10.0.0", "documentation": "^11.0.1",
"exif-reader": "^1.0.2", "exif-reader": "^1.0.2",
"icc": "^1.0.0", "icc": "^1.0.0",
"license-checker": "^25.0.1", "license-checker": "^25.0.1",
"mocha": "^6.1.4", "mocha": "^6.1.4",
"mock-fs": "^4.9.0", "mock-fs": "^4.10.1",
"nyc": "^14.0.0", "nyc": "^14.1.1",
"prebuild": "^8.2.1", "prebuild": "^9.0.0",
"prebuild-ci": "^3.0.0", "prebuild-ci": "^3.0.0",
"rimraf": "^2.6.3", "rimraf": "^2.6.3",
"semistandard": "^13.0.1" "semistandard": "^13.0.1"
}, },
"license": "Apache-2.0", "license": "Apache-2.0",
"config": { "config": {
"libvips": "8.7.4" "libvips": "8.8.0"
}, },
"engines": { "engines": {
"node": ">=6" "node": ">=8.5.0"
}, },
"semistandard": { "semistandard": {
"env": [ "env": [

View File

@ -25,8 +25,8 @@
// Verify platform and compiler compatibility // Verify platform and compiler compatibility
#if (VIPS_MAJOR_VERSION < 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 7)) #if (VIPS_MAJOR_VERSION < 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 8))
#error libvips version 8.7.0+ is required - see sharp.pixelplumbing.com/page/install #error libvips version 8.8.0+ is required - see sharp.pixelplumbing.com/page/install
#endif #endif
#if ((!defined(__clang__)) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6))) #if ((!defined(__clang__)) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)))

View File

@ -32,8 +32,6 @@
#endif /*HAVE_CONFIG_H*/ #endif /*HAVE_CONFIG_H*/
#include <vips/intl.h> #include <vips/intl.h>
#include <iostream>
#include <vips/vips8> #include <vips/vips8>
VIPS_NAMESPACE_START VIPS_NAMESPACE_START

View File

@ -563,7 +563,7 @@ VImage::new_from_file( const char *name, VOption *options )
} }
VImage VImage
VImage::new_from_buffer( void *buf, size_t len, const char *option_string, VImage::new_from_buffer( const void *buf, size_t len, const char *option_string,
VOption *options ) VOption *options )
{ {
const char *operation_name; const char *operation_name;
@ -588,6 +588,13 @@ VImage::new_from_buffer( void *buf, size_t len, const char *option_string,
return( out ); return( out );
} }
VImage
VImage::new_from_buffer( const std::string &buf, const char *option_string,
VOption *options )
{
return( new_from_buffer( buf.c_str(), buf.size(), option_string, options ) );
}
VImage VImage
VImage::new_matrix( int width, int height ) VImage::new_matrix( int width, int height )
{ {

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,8 @@
#include <tuple> #include <tuple>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <sys/types.h>
#include <sys/stat.h>
#include <vips/vips8> #include <vips/vips8>
#include <node.h> #include <node.h>
@ -30,6 +32,17 @@
#include "operations.h" #include "operations.h"
#include "pipeline.h" #include "pipeline.h"
#if defined(WIN32)
#define STAT64_STRUCT __stat64
#define STAT64_FUNCTION _stat64
#elif defined(__APPLE__)
#define STAT64_STRUCT stat
#define STAT64_FUNCTION stat
#else
#define STAT64_STRUCT stat64
#define STAT64_FUNCTION stat64
#endif
class PipelineWorker : public Nan::AsyncWorker { class PipelineWorker : public Nan::AsyncWorker {
public: public:
PipelineWorker( PipelineWorker(
@ -1005,8 +1018,8 @@ class PipelineWorker : public Nan::AsyncWorker {
argv[2] = info; argv[2] = info;
} else { } else {
// Add file size to info // Add file size to info
GStatBuf st; struct STAT64_STRUCT st;
if (g_stat(baton->fileOut.data(), &st) == 0) { if (STAT64_FUNCTION(baton->fileOut.data(), &st) == 0) {
Set(info, New("size").ToLocalChecked(), New<v8::Uint32>(static_cast<uint32_t>(st.st_size))); Set(info, New("size").ToLocalChecked(), New<v8::Uint32>(static_cast<uint32_t>(st.st_size)));
} }
argv[1] = info; argv[1] = info;

View File

@ -194,7 +194,7 @@ struct PipelineBaton {
blurSigma(0.0), blurSigma(0.0),
brightness(1.0), brightness(1.0),
saturation(1.0), saturation(1.0),
hue(0.0), hue(0),
medianSize(0), medianSize(0),
sharpenSigma(0.0), sharpenSigma(0.0),
sharpenFlat(1.0), sharpenFlat(1.0),

View File

@ -127,7 +127,7 @@ class StatsWorker : public Nan::AsyncWorker {
Set(channelStat, New("minY").ToLocalChecked(), New<v8::Number>(it->minY)); Set(channelStat, New("minY").ToLocalChecked(), New<v8::Number>(it->minY));
Set(channelStat, New("maxX").ToLocalChecked(), New<v8::Number>(it->maxX)); Set(channelStat, New("maxX").ToLocalChecked(), New<v8::Number>(it->maxX));
Set(channelStat, New("maxY").ToLocalChecked(), New<v8::Number>(it->maxY)); Set(channelStat, New("maxY").ToLocalChecked(), New<v8::Number>(it->maxY));
channels->Set(i, channelStat); Set(channels, i, channelStat);
} }
Set(info, New("channels").ToLocalChecked(), channels); Set(info, New("channels").ToLocalChecked(), channels);

View File

@ -8,17 +8,17 @@
"test": "node perf && node random && node parallel" "test": "node perf && node random && node parallel"
}, },
"devDependencies": { "devDependencies": {
"async": "^2.6.1", "async": "^3.1.0",
"benchmark": "^2.1.4", "benchmark": "^2.1.4",
"gm": "^1.23.1", "gm": "^1.23.1",
"imagemagick": "^0.1.3", "imagemagick": "^0.1.3",
"imagemagick-native": "^1.9.3", "imagemagick-native": "^1.9.3",
"jimp": "^0.5.3", "jimp": "^0.6.4",
"mapnik": "^4.0.1", "mapnik": "^4.2.1",
"semver": "^5.5.1" "semver": "^6.1.2"
}, },
"license": "Apache-2.0", "license": "Apache-2.0",
"engines": { "engines": {
"node": ">=6" "node": ">=8.5.0"
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 259 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 84 KiB

View File

@ -80,9 +80,6 @@ module.exports = {
inputPngWithTransparency16bit: getPath('tbgn2c16.png'), // http://www.schaik.com/pngsuite/tbgn2c16.png inputPngWithTransparency16bit: getPath('tbgn2c16.png'), // http://www.schaik.com/pngsuite/tbgn2c16.png
inputPngOverlayLayer0: getPath('alpha-layer-0-background.png'), inputPngOverlayLayer0: getPath('alpha-layer-0-background.png'),
inputPngOverlayLayer1: getPath('alpha-layer-1-fill.png'), inputPngOverlayLayer1: getPath('alpha-layer-1-fill.png'),
inputPngOverlayLayer2: getPath('alpha-layer-2-ink.png'),
inputPngOverlayLayer1LowAlpha: getPath('alpha-layer-1-fill-low-alpha.png'),
inputPngOverlayLayer2LowAlpha: getPath('alpha-layer-2-ink-low-alpha.png'),
inputPngAlphaPremultiplicationSmall: getPath('alpha-premultiply-1024x768-paper.png'), inputPngAlphaPremultiplicationSmall: getPath('alpha-premultiply-1024x768-paper.png'),
inputPngAlphaPremultiplicationLarge: getPath('alpha-premultiply-2048x1536-paper.png'), inputPngAlphaPremultiplicationLarge: getPath('alpha-premultiply-2048x1536-paper.png'),
inputPngBooleanNoAlpha: getPath('bandbool.png'), inputPngBooleanNoAlpha: getPath('bandbool.png'),

View File

@ -75,8 +75,8 @@ describe('Image metadata', function () {
// XMP // XMP
assert.strictEqual('object', typeof metadata.xmp); assert.strictEqual('object', typeof metadata.xmp);
assert.strictEqual(true, metadata.xmp instanceof Buffer); assert.strictEqual(true, metadata.xmp instanceof Buffer);
assert.strictEqual(12495, metadata.xmp.byteLength); assert.strictEqual(12466, metadata.xmp.byteLength);
assert.strictEqual(metadata.xmp.indexOf(Buffer.from('http://ns.adobe.com/xap/1.0')), 0); assert.strictEqual(metadata.xmp.indexOf(Buffer.from('<?xpacket begin="')), 0);
done(); done();
}); });
}); });

View File

@ -1,589 +0,0 @@
'use strict';
const fs = require('fs');
const assert = require('assert');
const fixtures = require('../fixtures');
const sharp = require('../../');
// Helpers
const getPaths = function (baseName, extension) {
if (typeof extension === 'undefined') {
extension = 'png';
}
return {
actual: fixtures.path('output.' + baseName + '.' + extension),
expected: fixtures.expected(baseName + '.' + extension)
};
};
// Test
describe('Overlays', function () {
it('Overlay transparent PNG file on solid background', function (done) {
const paths = getPaths('alpha-layer-01');
sharp(fixtures.inputPngOverlayLayer0)
.overlayWith(fixtures.inputPngOverlayLayer1)
.toFile(paths.actual, function (error) {
if (error) return done(error);
fixtures.assertMaxColourDistance(paths.actual, paths.expected);
done();
});
});
it('Overlay transparent PNG Buffer on solid background', function (done) {
const paths = getPaths('alpha-layer-01');
sharp(fixtures.inputPngOverlayLayer0)
.overlayWith(fs.readFileSync(fixtures.inputPngOverlayLayer1))
.toFile(paths.actual, function (error) {
if (error) return done(error);
fixtures.assertMaxColourDistance(paths.actual, paths.expected);
done();
});
});
it('Overlay low-alpha transparent PNG on solid background', function (done) {
const paths = getPaths('alpha-layer-01-low-alpha');
sharp(fixtures.inputPngOverlayLayer0)
.overlayWith(fixtures.inputPngOverlayLayer1LowAlpha)
.toFile(paths.actual, function (error) {
if (error) return done(error);
fixtures.assertMaxColourDistance(paths.actual, paths.expected);
done();
});
});
it('Composite three transparent PNGs into one', function (done) {
const paths = getPaths('alpha-layer-012');
sharp(fixtures.inputPngOverlayLayer0)
.overlayWith(fixtures.inputPngOverlayLayer1)
.toBuffer(function (error, data) {
if (error) return done(error);
sharp(data)
.overlayWith(fixtures.inputPngOverlayLayer2)
.toFile(paths.actual, function (error) {
if (error) return done(error);
fixtures.assertMaxColourDistance(paths.actual, paths.expected);
done();
});
});
});
it('Composite two transparent PNGs into one', function (done) {
const paths = getPaths('alpha-layer-12');
sharp(fixtures.inputPngOverlayLayer1)
.overlayWith(fixtures.inputPngOverlayLayer2)
.toFile(paths.actual, function (error) {
if (error) return done(error);
fixtures.assertMaxColourDistance(paths.actual, paths.expected);
done();
});
});
it('Composite two low-alpha transparent PNGs into one', function (done) {
const paths = getPaths('alpha-layer-12-low-alpha');
sharp(fixtures.inputPngOverlayLayer1LowAlpha)
.overlayWith(fixtures.inputPngOverlayLayer2LowAlpha)
.toFile(paths.actual, function (error) {
if (error) return done(error);
fixtures.assertMaxColourDistance(paths.actual, paths.expected, 2);
done();
});
});
it('Composite three low-alpha transparent PNGs into one', function (done) {
const paths = getPaths('alpha-layer-012-low-alpha');
sharp(fixtures.inputPngOverlayLayer0)
.overlayWith(fixtures.inputPngOverlayLayer1LowAlpha)
.toBuffer(function (error, data) {
if (error) return done(error);
sharp(data)
.overlayWith(fixtures.inputPngOverlayLayer2LowAlpha)
.toFile(paths.actual, function (error) {
if (error) return done(error);
fixtures.assertMaxColourDistance(paths.actual, paths.expected);
done();
});
});
});
it('Composite rgb+alpha PNG onto JPEG', function (done) {
const paths = getPaths('overlay-jpeg-with-rgb', 'jpg');
sharp(fixtures.inputJpg)
.resize(2048, 1536)
.overlayWith(fixtures.inputPngOverlayLayer1)
.toFile(paths.actual, function (error, info) {
if (error) return done(error);
fixtures.assertMaxColourDistance(paths.actual, paths.expected, 102);
done();
});
});
it('Composite greyscale+alpha PNG onto JPEG', function (done) {
const paths = getPaths('overlay-jpeg-with-greyscale', 'jpg');
sharp(fixtures.inputJpg)
.resize(400, 300)
.overlayWith(fixtures.inputPngWithGreyAlpha)
.toFile(paths.actual, function (error, info) {
if (error) return done(error);
fixtures.assertMaxColourDistance(paths.actual, paths.expected, 102);
done();
});
});
it('Composite WebP onto JPEG', function (done) {
const paths = getPaths('overlay-jpeg-with-webp', 'jpg');
sharp(fixtures.inputJpg)
.resize(300, 300)
.overlayWith(fixtures.inputWebPWithTransparency)
.toFile(paths.actual, function (error, info) {
if (error) return done(error);
fixtures.assertMaxColourDistance(paths.actual, paths.expected, 102);
done();
});
});
it('Composite JPEG onto PNG, ensure premultiply', function (done) {
sharp(fixtures.inputPngOverlayLayer1)
.overlayWith(fixtures.inputJpgWithLandscapeExif1)
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(true, info.premultiplied);
done();
});
});
it('Composite opaque JPEG onto JPEG, ensure premultiply', function (done) {
sharp(fixtures.inputJpg)
.overlayWith(fixtures.inputJpgWithLandscapeExif1)
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(true, info.premultiplied);
done();
});
});
it('Fail when overlay is larger', function (done) {
sharp(fixtures.inputJpg)
.resize(320)
.overlayWith(fixtures.inputPngOverlayLayer1)
.toBuffer(function (error) {
assert.strictEqual(true, error instanceof Error);
done();
});
});
it('Fail with empty String parameter', function () {
assert.throws(function () {
sharp().overlayWith('');
});
});
it('Fail with non-String parameter', function () {
assert.throws(function () {
sharp().overlayWith(1);
});
});
it('Fail with unsupported gravity', function () {
assert.throws(function () {
sharp()
.overlayWith(fixtures.inputPngOverlayLayer1, {
gravity: 9
});
});
});
it('Empty options', function () {
assert.doesNotThrow(function () {
sharp().overlayWith(fixtures.inputPngOverlayLayer1, {});
});
});
describe('Overlay with numeric gravity', function () {
Object.keys(sharp.gravity).forEach(function (gravity) {
it(gravity, function (done) {
const expected = fixtures.expected('overlay-gravity-' + gravity + '.jpg');
sharp(fixtures.inputJpg)
.resize(80)
.overlayWith(fixtures.inputPngWithTransparency16bit, {
gravity: gravity
})
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('jpeg', info.format);
assert.strictEqual(80, info.width);
assert.strictEqual(65, info.height);
assert.strictEqual(3, info.channels);
fixtures.assertSimilar(expected, data, done);
});
});
});
});
describe('Overlay with string-based gravity', function () {
Object.keys(sharp.gravity).forEach(function (gravity) {
it(gravity, function (done) {
const expected = fixtures.expected('overlay-gravity-' + gravity + '.jpg');
sharp(fixtures.inputJpg)
.resize(80)
.overlayWith(fixtures.inputPngWithTransparency16bit, {
gravity: sharp.gravity[gravity]
})
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('jpeg', info.format);
assert.strictEqual(80, info.width);
assert.strictEqual(65, info.height);
assert.strictEqual(3, info.channels);
fixtures.assertSimilar(expected, data, done);
});
});
});
});
describe('Overlay with tile enabled and gravity', function () {
Object.keys(sharp.gravity).forEach(function (gravity) {
it(gravity, function (done) {
const expected = fixtures.expected('overlay-tile-gravity-' + gravity + '.jpg');
sharp(fixtures.inputJpg)
.resize(80)
.overlayWith(fixtures.inputPngWithTransparency16bit, {
tile: true,
gravity: gravity
})
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('jpeg', info.format);
assert.strictEqual(80, info.width);
assert.strictEqual(65, info.height);
assert.strictEqual(3, info.channels);
fixtures.assertSimilar(expected, data, done);
});
});
});
});
describe('Overlay with top-left offsets', function () {
it('Overlay with 10px top & 10px left offsets', function (done) {
const expected = fixtures.expected('overlay-valid-offsets-10-10.jpg');
sharp(fixtures.inputJpg)
.resize(400)
.overlayWith(fixtures.inputPngWithTransparency16bit, {
top: 10,
left: 10
})
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('jpeg', info.format);
assert.strictEqual(3, info.channels);
fixtures.assertSimilar(expected, data, done);
});
});
it('Overlay with 100px top & 300px left offsets', function (done) {
const expected = fixtures.expected('overlay-valid-offsets-100-300.jpg');
sharp(fixtures.inputJpg)
.resize(400)
.overlayWith(fixtures.inputPngWithTransparency16bit, {
top: 100,
left: 300
})
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('jpeg', info.format);
assert.strictEqual(3, info.channels);
fixtures.assertSimilar(expected, data, done);
});
});
it('Overlay with only top offset', function () {
assert.throws(function () {
sharp(fixtures.inputJpg)
.resize(400)
.overlayWith(fixtures.inputPngWithTransparency16bit, {
top: 1000
});
});
});
it('Overlay with only left offset', function () {
assert.throws(function () {
sharp(fixtures.inputJpg)
.resize(400)
.overlayWith(fixtures.inputPngWithTransparency16bit, {
left: 1000
});
});
});
it('Overlay with negative offsets', function () {
assert.throws(function () {
sharp(fixtures.inputJpg)
.resize(400)
.overlayWith(fixtures.inputPngWithTransparency16bit, {
top: -1000,
left: -1000
});
});
});
it('Overlay with 0 offset', function (done) {
const expected = fixtures.expected('overlay-offset-0.jpg');
sharp(fixtures.inputJpg)
.resize(400)
.overlayWith(fixtures.inputPngWithTransparency16bit, {
top: 0,
left: 0
})
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('jpeg', info.format);
assert.strictEqual(3, info.channels);
fixtures.assertSimilar(expected, data, done);
});
});
it('Overlay with offset and gravity', function (done) {
const expected = fixtures.expected('overlay-offset-with-gravity.jpg');
sharp(fixtures.inputJpg)
.resize(400)
.overlayWith(fixtures.inputPngWithTransparency16bit, {
left: 10,
top: 10,
gravity: 4
})
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('jpeg', info.format);
assert.strictEqual(3, info.channels);
fixtures.assertSimilar(expected, data, done);
});
});
it('Overlay with offset and gravity and tile', function (done) {
const expected = fixtures.expected('overlay-offset-with-gravity-tile.jpg');
sharp(fixtures.inputJpg)
.resize(400)
.overlayWith(fixtures.inputPngWithTransparency16bit, {
left: 10,
top: 10,
gravity: 4,
tile: true
})
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('jpeg', info.format);
assert.strictEqual(3, info.channels);
fixtures.assertSimilar(expected, data, done);
});
});
it('Overlay with offset and tile', function (done) {
const expected = fixtures.expected('overlay-offset-with-tile.jpg');
sharp(fixtures.inputJpg)
.resize(400)
.overlayWith(fixtures.inputPngWithTransparency16bit, {
left: 10,
top: 10,
tile: true
})
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('jpeg', info.format);
assert.strictEqual(3, info.channels);
fixtures.assertSimilar(expected, data, done);
});
});
it('Overlay with invalid tile option', function () {
assert.throws(function () {
sharp().overlayWith('ignore', { tile: 1 });
});
});
it('Overlay with very large offset', function (done) {
const expected = fixtures.expected('overlay-very-large-offset.jpg');
sharp(fixtures.inputJpg)
.resize(400)
.overlayWith(fixtures.inputPngWithTransparency16bit, {
left: 10000,
top: 10000
})
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('jpeg', info.format);
assert.strictEqual(3, info.channels);
fixtures.assertSimilar(expected, data, done);
});
});
it('Overlay 100x100 with 50x50 so bottom edges meet', function (done) {
sharp(fixtures.inputJpg)
.resize(50, 50)
.toBuffer(function (err, overlay) {
if (err) throw err;
sharp(fixtures.inputJpgWithLandscapeExif1)
.resize(100, 100)
.overlayWith(overlay, {
top: 50,
left: 40
})
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('jpeg', info.format);
assert.strictEqual(100, info.width);
assert.strictEqual(100, info.height);
fixtures.assertSimilar(fixtures.expected('overlay-bottom-edges-meet.jpg'), data, done);
});
});
});
});
it('With tile enabled and image rotated 90 degrees', function (done) {
const expected = fixtures.expected('overlay-tile-rotated90.jpg');
sharp(fixtures.inputJpg)
.rotate(90)
.resize(80)
.overlayWith(fixtures.inputPngWithTransparency16bit, {
tile: true
})
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('jpeg', info.format);
assert.strictEqual(80, info.width);
assert.strictEqual(98, info.height);
assert.strictEqual(3, info.channels);
fixtures.assertSimilar(expected, data, done);
});
});
it('With tile enabled and image rotated 90 degrees and gravity northwest', function (done) {
const expected = fixtures.expected('overlay-tile-rotated90-gravity-northwest.jpg');
sharp(fixtures.inputJpg)
.rotate(90)
.resize(80)
.overlayWith(fixtures.inputPngWithTransparency16bit, {
tile: true,
gravity: 'northwest'
})
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('jpeg', info.format);
assert.strictEqual(80, info.width);
assert.strictEqual(98, info.height);
assert.strictEqual(3, info.channels);
fixtures.assertSimilar(expected, data, done);
});
});
describe('Overlay with cutout enabled and gravity', function () {
Object.keys(sharp.gravity).forEach(function (gravity) {
it(gravity, function (done) {
const expected = fixtures.expected('overlay-cutout-gravity-' + gravity + '.jpg');
sharp(fixtures.inputJpg)
.resize(80)
.overlayWith(fixtures.inputPngWithTransparency16bit, {
cutout: true,
gravity: gravity
})
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('jpeg', info.format);
assert.strictEqual(80, info.width);
assert.strictEqual(65, info.height);
assert.strictEqual(3, info.channels);
fixtures.assertSimilar(expected, data, done);
});
});
});
});
it('With cutout enabled and image rotated 90 degrees', function (done) {
const expected = fixtures.expected('overlay-cutout-rotated90.jpg');
sharp(fixtures.inputJpg)
.rotate(90)
.resize(80)
.overlayWith(fixtures.inputPngWithTransparency16bit, {
cutout: true
})
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('jpeg', info.format);
assert.strictEqual(80, info.width);
assert.strictEqual(98, info.height);
assert.strictEqual(3, info.channels);
fixtures.assertSimilar(expected, data, done);
});
});
it('With cutout enabled and image rotated 90 degrees and gravity northwest', function (done) {
const expected = fixtures.expected('overlay-cutout-rotated90-gravity-northwest.jpg');
sharp(fixtures.inputJpg)
.rotate(90)
.resize(80)
.overlayWith(fixtures.inputPngWithTransparency16bit, {
cutout: true,
gravity: 'northwest'
})
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('jpeg', info.format);
assert.strictEqual(80, info.width);
assert.strictEqual(98, info.height);
assert.strictEqual(3, info.channels);
fixtures.assertSimilar(expected, data, done);
});
});
it('Composite RGBA raw buffer onto JPEG', function (done) {
sharp(fixtures.inputPngOverlayLayer1)
.raw()
.toBuffer(function (err, data, info) {
if (err) throw err;
sharp(fixtures.inputJpg)
.resize(2048, 1536)
.overlayWith(data, { raw: info })
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual(true, info.premultiplied);
fixtures.assertSimilar(fixtures.expected('overlay-jpeg-with-rgb.jpg'), data, done);
});
});
});
it('Returns an error when called with an invalid file', function (done) {
sharp(fixtures.inputJpg)
.overlayWith('notfound.png')
.toBuffer(function (err) {
assert(err instanceof Error);
done();
});
});
it('Composite JPEG onto JPEG', function (done) {
sharp(fixtures.inputJpg)
.resize(480, 320)
.overlayWith(fixtures.inputJpgBooleanTest)
.toBuffer(function (err, data, info) {
if (err) throw err;
assert.strictEqual('jpeg', info.format);
assert.strictEqual(480, info.width);
assert.strictEqual(320, info.height);
assert.strictEqual(3, info.channels);
assert.strictEqual(true, info.premultiplied);
fixtures.assertSimilar(fixtures.expected('overlay-jpeg-with-jpeg.jpg'), data, done);
});
});
});

View File

@ -338,7 +338,7 @@ describe('Resize fit=cover', function () {
assert.strictEqual(3, info.channels); assert.strictEqual(3, info.channels);
assert.strictEqual(80, info.width); assert.strictEqual(80, info.width);
assert.strictEqual(320, info.height); assert.strictEqual(320, info.height);
assert.strictEqual(-143, info.cropOffsetLeft); assert.strictEqual(-107, info.cropOffsetLeft);
assert.strictEqual(0, info.cropOffsetTop); assert.strictEqual(0, info.cropOffsetTop);
fixtures.assertSimilar(fixtures.expected('crop-strategy-attention.jpg'), data, done); fixtures.assertSimilar(fixtures.expected('crop-strategy-attention.jpg'), data, done);
}); });

View File

@ -109,7 +109,7 @@ describe('TIFF', function () {
.toFile(fixtures.outputTiff, (err, info) => { .toFile(fixtures.outputTiff, (err, info) => {
if (err) throw err; if (err) throw err;
assert.strictEqual('tiff', info.format); assert.strictEqual('tiff', info.format);
assert(info.size === startSize); assert.strictEqual(startSize, info.size);
rimraf(fixtures.outputTiff, done); rimraf(fixtures.outputTiff, done);
}); });
}); });