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
.DS_Store
.nyc_output
.vscode/
package-lock.json

View File

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

View File

@ -1,11 +1,5 @@
matrix:
include:
- name: "Linux (glibc) - Node 6"
os: linux
dist: trusty
sudo: false
language: node_js
node_js: "6"
- name: "Linux (glibc) - Node 8"
os: linux
dist: trusty
@ -27,12 +21,6 @@ matrix:
after_success:
- npm install coveralls
- 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"
os: linux
dist: trusty
@ -53,16 +41,6 @@ matrix:
- 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 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"
os: linux
dist: trusty
@ -73,11 +51,6 @@ matrix:
- sudo docker exec sharp apk add build-base git python2 --update-cache
install: sudo docker exec sharp sh -c "npm install --unsafe-perm"
script: sudo docker exec sharp sh -c "npm test"
- name: "OS X - Node 6"
os: osx
osx_image: xcode9.2
language: node_js
node_js: "6"
- name: "OS X - Node 8"
os: osx
osx_image: xcode9.2
@ -88,11 +61,6 @@ matrix:
osx_image: xcode9.2
language: node_js
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"
os: osx
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.
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.
## Examples

View File

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

View File

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

View File

@ -1,5 +1,16 @@
# 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*"
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.
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.
[![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
* Node.js v6+
* Node.js v8.5.0+
### Building from source
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.
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)
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.:
* Debian 7+
* Debian 8+
* Ubuntu 14.04+
* Centos 7+
* Alpine 3.8+ (Node 8+)
* Red Hat Enterprise 8
* CentOS 8
* Alpine 3.8+
* Fedora
* openSUSE 13.2+
* Archlinux
* Raspbian Jessie
* Amazon Linux
* Amazon Linux 2
* Solus
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.
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.
[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)
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
`C:\Users\[user]\AppData\Roaming\npm-cache\_libvips`.
@ -150,7 +152,7 @@ docker pull tailor/docker-libvips
### 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
[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
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:
```sh
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.

View File

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

View File

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

View File

@ -1,7 +1,5 @@
'use strict';
const deprecate = require('util').deprecate;
const is = require('./is');
/**
@ -154,21 +152,11 @@ function composite (images) {
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.
* @private
*/
module.exports = function (Sharp) {
Sharp.prototype.composite = composite;
Sharp.prototype.overlayWith = deprecate(overlayWith, 'overlayWith(input, options) is deprecated, use composite([{ input, ...options }]) instead');
Sharp.blend = blend;
};

View File

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

View File

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

View File

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

View File

@ -563,7 +563,7 @@ VImage::new_from_file( const char *name, VOption *options )
}
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 )
{
const char *operation_name;
@ -588,6 +588,13 @@ VImage::new_from_buffer( void *buf, size_t len, const char *option_string,
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::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 <utility>
#include <vector>
#include <sys/types.h>
#include <sys/stat.h>
#include <vips/vips8>
#include <node.h>
@ -30,6 +32,17 @@
#include "operations.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 {
public:
PipelineWorker(
@ -1005,8 +1018,8 @@ class PipelineWorker : public Nan::AsyncWorker {
argv[2] = info;
} else {
// Add file size to info
GStatBuf st;
if (g_stat(baton->fileOut.data(), &st) == 0) {
struct STAT64_STRUCT st;
if (STAT64_FUNCTION(baton->fileOut.data(), &st) == 0) {
Set(info, New("size").ToLocalChecked(), New<v8::Uint32>(static_cast<uint32_t>(st.st_size)));
}
argv[1] = info;

View File

@ -194,7 +194,7 @@ struct PipelineBaton {
blurSigma(0.0),
brightness(1.0),
saturation(1.0),
hue(0.0),
hue(0),
medianSize(0),
sharpenSigma(0.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("maxX").ToLocalChecked(), New<v8::Number>(it->maxX));
Set(channelStat, New("maxY").ToLocalChecked(), New<v8::Number>(it->maxY));
channels->Set(i, channelStat);
Set(channels, i, channelStat);
}
Set(info, New("channels").ToLocalChecked(), channels);

View File

@ -8,17 +8,17 @@
"test": "node perf && node random && node parallel"
},
"devDependencies": {
"async": "^2.6.1",
"async": "^3.1.0",
"benchmark": "^2.1.4",
"gm": "^1.23.1",
"imagemagick": "^0.1.3",
"imagemagick-native": "^1.9.3",
"jimp": "^0.5.3",
"mapnik": "^4.0.1",
"semver": "^5.5.1"
"jimp": "^0.6.4",
"mapnik": "^4.2.1",
"semver": "^6.1.2"
},
"license": "Apache-2.0",
"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
inputPngOverlayLayer0: getPath('alpha-layer-0-background.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'),
inputPngAlphaPremultiplicationLarge: getPath('alpha-premultiply-2048x1536-paper.png'),
inputPngBooleanNoAlpha: getPath('bandbool.png'),

View File

@ -75,8 +75,8 @@ describe('Image metadata', function () {
// XMP
assert.strictEqual('object', typeof metadata.xmp);
assert.strictEqual(true, metadata.xmp instanceof Buffer);
assert.strictEqual(12495, metadata.xmp.byteLength);
assert.strictEqual(metadata.xmp.indexOf(Buffer.from('http://ns.adobe.com/xap/1.0')), 0);
assert.strictEqual(12466, metadata.xmp.byteLength);
assert.strictEqual(metadata.xmp.indexOf(Buffer.from('<?xpacket begin="')), 0);
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(80, info.width);
assert.strictEqual(320, info.height);
assert.strictEqual(-143, info.cropOffsetLeft);
assert.strictEqual(-107, info.cropOffsetLeft);
assert.strictEqual(0, info.cropOffsetTop);
fixtures.assertSimilar(fixtures.expected('crop-strategy-attention.jpg'), data, done);
});

View File

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