From a216d2945b19079848409ff186774cc84ee9ec9a Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Thu, 2 Jan 2020 21:12:56 +0000 Subject: [PATCH] Upgrade to libvips v8.9.0-rc4, drop support for Node.js 8 --- .travis.yml | 70 ++++----- README.md | 2 +- appveyor.yml | 3 +- binding.gyp | 2 +- docs/api-channel.md | 4 + docs/api-composite.md | 4 + docs/api-operation.md | 8 + docs/api-output.md | 4 + docs/changelog.md | 17 ++- docs/index.md | 2 +- docs/install.md | 4 +- install/libvips.js | 9 +- lib/channel.js | 2 + lib/composite.js | 2 + lib/operation.js | 4 + lib/output.js | 2 + package.json | 8 +- src/common.cc | 2 +- src/common.h | 4 +- src/libvips/cplusplus/VConnection.cpp | 178 +++++++++++++++++++++++ src/libvips/cplusplus/VImage.cpp | 47 +++++- src/libvips/cplusplus/VInterpolate.cpp | 2 +- src/libvips/cplusplus/vips-operators.cpp | 156 +++++++++++++++++++- src/pipeline.cc | 32 ++-- test/unit/stats.js | 30 ++-- test/unit/toBuffer.js | 4 +- 26 files changed, 499 insertions(+), 103 deletions(-) create mode 100644 src/libvips/cplusplus/VConnection.cpp diff --git a/.travis.yml b/.travis.yml index e399971c..c1d8c664 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,88 +1,72 @@ matrix: include: - - name: "Linux (glibc) - Node 8" + - name: "Linux (glibc 2.17+) - Node.js 10" os: linux - dist: trusty - sudo: false - language: node_js - node_js: "8" - - name: "Linux (glibc) - Node 10" - os: linux - dist: trusty - sudo: false + dist: xenial language: node_js node_js: "10" - - name: "Linux (glibc) - Node 12" + - name: "Linux (glibc 2.17+) - Node.js 12" os: linux - dist: trusty - sudo: false + dist: xenial language: node_js node_js: "12" - - name: "Linux (glibc) - Node 13" + - name: "Linux (glibc 2.17+) - Node.js 13" os: linux - dist: trusty - sudo: false + dist: xenial language: node_js node_js: "13" after_success: - npm install coveralls - cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js - - name: "Linux (musl) - Node 8" + - name: "Linux (musl 1.1.20+) - Node.js 10" os: linux - dist: trusty - sudo: true + dist: bionic language: minimal before_install: - - sudo docker run -dit --name sharp --env CI --env PREBUILD_TOKEN --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp node:8-alpine + - sudo docker run -dit --name sharp --env CI --env PREBUILD_TOKEN --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp node:10.17.0-alpine3.9 # https://github.com/nodejs/docker-node/issues/1158 - 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 10" + - name: "Linux (musl 1.1.20+) - Node.js 12" 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:10-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 - sudo: true + dist: bionic language: minimal before_install: - sudo docker run -dit --name sharp --env CI --env PREBUILD_TOKEN --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp node:12.0-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 13" + - name: "Linux (musl 1.1.20+) - Node.js 13" os: linux - dist: trusty - sudo: true + dist: bionic language: minimal before_install: - sudo docker run -dit --name sharp --env CI --env PREBUILD_TOKEN --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp node:13.0-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: "OS X - Node 8" - os: osx - osx_image: xcode9.2 - language: node_js - node_js: "8" - - name: "OS X - Node 10" + - name: "Linux ARM64v8 (glibc 2.29+) - Node.js 10" + arch: arm64 + os: linux + dist: bionic + language: minimal + before_install: + - sudo docker run -dit --name sharp --env CI --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp arm64v8/debian:bullseye + - sudo docker exec sharp apt-get update + - sudo docker exec sharp apt-get install -y build-essential git python2 nodejs npm + install: sudo docker exec sharp sh -c "npm install --unsafe-perm" + script: sudo docker exec sharp sh -c "npm test" + - name: "OS X (10.12+) - Node.js 10" os: osx osx_image: xcode9.2 language: node_js node_js: "10" - - name: "OS X - Node 12" + - name: "OS X (10.12+) - Node.js 12" os: osx osx_image: xcode9.2 language: node_js node_js: "12" - - name: "OS X - Node 13" + - name: "OS X (10.12+) - Node.js 13" os: osx osx_image: xcode10 language: node_js diff --git a/README.md b/README.md index 409cd496..3f0ef595 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,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 8, 10, 12 and 13 +Node versions 10, 12 and 13 do not require any additional install or runtime dependencies. ## Examples diff --git a/appveyor.yml b/appveyor.yml index 12bc7e73..3d9f7ffe 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,10 +1,9 @@ -os: Visual Studio 2015 +os: Visual Studio 2017 version: "{build}" build: off platform: x64 environment: matrix: - - nodejs_version: "8" - nodejs_version: "10" - nodejs_version: "12" - nodejs_version: "13" diff --git a/binding.gyp b/binding.gyp index 3a189384..1e7c83ce 100644 --- a/binding.gyp +++ b/binding.gyp @@ -11,6 +11,7 @@ ], 'sources': [ 'src/libvips/cplusplus/VError.cpp', + 'src/libvips/cplusplus/VConnection.cpp', 'src/libvips/cplusplus/VInterpolate.cpp', 'src/libvips/cplusplus/VImage.cpp' ], @@ -127,7 +128,6 @@ '../vendor/lib/libgobject-2.0.so', # Dependencies of dependencies, included for openSUSE support '../vendor/lib/libcairo.so', - '../vendor/lib/libcroco-0.6.so', '../vendor/lib/libexif.so', '../vendor/lib/libexpat.so', '../vendor/lib/libffi.so', diff --git a/docs/api-channel.md b/docs/api-channel.md index 7e278111..4dccddf9 100644 --- a/docs/api-channel.md +++ b/docs/api-channel.md @@ -32,6 +32,10 @@ sharp('rgb.jpg') Returns **Sharp** +**Meta** + +- **since**: 0.21.2 + ## extractChannel Extract a single channel from a multi-channel image. diff --git a/docs/api-composite.md b/docs/api-composite.md index c571edd6..91ac1782 100644 --- a/docs/api-composite.md +++ b/docs/api-composite.md @@ -61,6 +61,10 @@ sharp('input.png') Returns **Sharp** +**Meta** + +- **since**: 0.22.0 + [1]: https://libvips.github.io/libvips/API/current/libvips-conversion.html#VipsBlendMode [2]: https://www.cairographics.org/operators/ diff --git a/docs/api-operation.md b/docs/api-operation.md index 7cd0600c..b4b62824 100644 --- a/docs/api-operation.md +++ b/docs/api-operation.md @@ -287,6 +287,10 @@ sharp(input) Returns **Sharp** +**Meta** + +- **since**: 0.21.1 + ## modulate Transforms the image using brightness, saturation and hue rotation. @@ -322,6 +326,10 @@ sharp(input) Returns **Sharp** +**Meta** + +- **since**: 0.22.1 + [1]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number [2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object diff --git a/docs/api-output.md b/docs/api-output.md index e40f4990..28b1de49 100644 --- a/docs/api-output.md +++ b/docs/api-output.md @@ -268,6 +268,10 @@ Most versions of libheif support only the patent-encumbered HEVC compression for Returns **Sharp** +**Meta** + +- **since**: 0.23.0 + ## raw Force output to be raw, uncompressed uint8 pixel data. diff --git a/docs/changelog.md b/docs/changelog.md index 99347473..bff8e849 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,14 +1,21 @@ # Changelog +### v0.24 - "*wit*" + +Requires libvips v8.9.0. + +#### v0.24.0 - TBD + +* Drop support for Node.js 8. + [#1910](https://github.com/lovell/sharp/issues/1910) + +* Ensure correct colour output for 16-bit, 2-channel PNG input with ICC profile. + [#2013](https://github.com/lovell/sharp/issues/2013) + ### v0.23 - "*vision*" Requires libvips v8.8.1. -#### v0.23.5 - TBD - -* Ensure correct colour output for 16-bit, 2-channel PNG input with ICC profile. - [#2013](https://github.com/lovell/sharp/issues/2013) - #### v0.23.4 - 5th December 2019 * Handle zero-length Buffer objects when using Node.js v13.2.0+. diff --git a/docs/index.md b/docs/index.md index 7574cf75..2f56b2de 100644 --- a/docs/index.md +++ b/docs/index.md @@ -17,7 +17,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 8, 10, 12 and 13 +Node versions 10, 12 and 13 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) diff --git a/docs/install.md b/docs/install.md index acbf2014..a1b5fa96 100644 --- a/docs/install.md +++ b/docs/install.md @@ -10,12 +10,12 @@ yarn add sharp ## Prerequisites -* Node.js v8.5.0+ +* Node.js v10.13.0+ ### Building from source Pre-compiled binaries for sharp are provided for use with -Node versions 8, 10, 12 and 13 on +Node versions 10, 12 and 13 on 64-bit Windows, OS X and Linux platforms. Sharp will be built from source at install time when: diff --git a/install/libvips.js b/install/libvips.js index a913878e..7b58041d 100644 --- a/install/libvips.js +++ b/install/libvips.js @@ -66,8 +66,11 @@ 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.17.0')) { - throw new Error(`Use with glibc version ${detectLibc.version} requires manual installation of libvips >= ${minimumLibvipsVersion}`); + if (detectLibc.family === detectLibc.GLIBC && detectLibc.version) { + const minimumGlibcVersion = arch === 'arm64' ? '2.29.0' : '2.17.0'; + if (semver.lt(`${detectLibc.version}.0`, minimumGlibcVersion)) { + throw new Error(`Use with glibc ${detectLibc.version} requires manual installation of libvips >= ${minimumLibvipsVersion}`); + } } // Download to per-process temporary file const tarFilename = ['libvips', minimumLibvipsVersion, platformAndArch].join('-') + '.tar.gz'; @@ -84,7 +87,7 @@ try { if (err) { fail(err); } else if (response.statusCode === 404) { - fail(new Error(`Prebuilt libvips binaries are not yet available for ${platformAndArch}`)); + fail(new Error(`Prebuilt libvips ${minimumLibvipsVersion} binaries are not yet available for ${platformAndArch}`)); } else if (response.statusCode !== 200) { fail(new Error(`Status ${response.statusCode} ${response.statusMessage}`)); } else { diff --git a/lib/channel.js b/lib/channel.js index 6acc5ef5..cf6560f9 100644 --- a/lib/channel.js +++ b/lib/channel.js @@ -32,6 +32,8 @@ function removeAlpha () { /** * Ensure alpha channel, if missing. The added alpha channel will be fully opaque. This is a no-op if the image already has an alpha channel. * + * @since 0.21.2 + * * @example * sharp('rgb.jpg') * .ensureAlpha() diff --git a/lib/composite.js b/lib/composite.js index cdcf57ee..c4345160 100644 --- a/lib/composite.js +++ b/lib/composite.js @@ -53,6 +53,8 @@ const blend = { * https://libvips.github.io/libvips/API/current/libvips-conversion.html#VipsBlendMode * and https://www.cairographics.org/operators/ * + * @since 0.22.0 + * * @example * sharp('input.png') * .rotate(180) diff --git a/lib/operation.js b/lib/operation.js index 90244fc1..9e0caa84 100644 --- a/lib/operation.js +++ b/lib/operation.js @@ -379,6 +379,8 @@ function linear (a, b) { /** * Recomb the image with the specified matrix. * + * @since 0.21.1 + * * @example * sharp(input) * .recomb([ @@ -416,6 +418,8 @@ function recomb (inputMatrix) { /** * Transforms the image using brightness, saturation and hue rotation. * + * @since 0.22.1 + * * @example * sharp(input) * .modulate({ diff --git a/lib/output.js b/lib/output.js index 09c3b520..a49b0591 100644 --- a/lib/output.js +++ b/lib/output.js @@ -444,6 +444,8 @@ function tiff (options) { * * Most versions of libheif support only the patent-encumbered HEVC compression format. * + * @since 0.23.0 + * * @param {Object} [options] - output options * @param {Number} [options.quality=80] - quality, integer 1-100 * @param {Boolean} [options.compression='hevc'] - compression format: hevc, avc, jpeg, av1 diff --git a/package.json b/package.json index 5a0d08a4..211baf70 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "nan": "^2.14.0", "npmlog": "^4.1.2", "prebuild-install": "^5.3.3", - "semver": "^6.3.0", + "semver": "^7.1.1", "simple-get": "^3.1.0", "tar": "^5.0.5", "tunnel-agent": "^0.6.0" @@ -126,7 +126,7 @@ "license-checker": "^25.0.1", "mocha": "^6.2.2", "mock-fs": "^4.10.4", - "nyc": "^14.1.1", + "nyc": "^15.0.0", "prebuild": "^9.1.1", "prebuild-ci": "^3.1.0", "rimraf": "^3.0.0", @@ -134,10 +134,10 @@ }, "license": "Apache-2.0", "config": { - "libvips": "8.8.1" + "libvips": "8.9.0-rc4" }, "engines": { - "node": ">=8.5.0" + "node": ">=10.13.0" }, "funding": { "url": "https://opencollective.com/libvips" diff --git a/src/common.cc b/src/common.cc index 8c9b4824..387d2a5e 100644 --- a/src/common.cc +++ b/src/common.cc @@ -197,7 +197,7 @@ namespace sharp { std::string const loader = load; if (EndsWith(loader, "JpegFile")) { imageType = ImageType::JPEG; - } else if (EndsWith(loader, "Png")) { + } else if (EndsWith(loader, "PngFile")) { imageType = ImageType::PNG; } else if (EndsWith(loader, "WebpFile")) { imageType = ImageType::WEBP; diff --git a/src/common.h b/src/common.h index 29977de3..6a1629a4 100644 --- a/src/common.h +++ b/src/common.h @@ -25,8 +25,8 @@ // Verify platform and compiler compatibility -#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 +#if (VIPS_MAJOR_VERSION < 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 9)) +#error libvips version 8.9.0+ is required - see sharp.pixelplumbing.com/page/install #endif #if ((!defined(__clang__)) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6))) diff --git a/src/libvips/cplusplus/VConnection.cpp b/src/libvips/cplusplus/VConnection.cpp new file mode 100644 index 00000000..be7afc5a --- /dev/null +++ b/src/libvips/cplusplus/VConnection.cpp @@ -0,0 +1,178 @@ +/* Object part of the VSource and VTarget class + */ + +/* + + Copyright (C) 1991-2001 The National Gallery + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA + + */ + +/* + + These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk + + */ + +#ifdef HAVE_CONFIG_H +#include +#endif /*HAVE_CONFIG_H*/ +#include + +#include + +#include + +/* +#define VIPS_DEBUG +#define VIPS_DEBUG_VERBOSE + */ + +VIPS_NAMESPACE_START + +VSource +VSource::new_from_descriptor( int descriptor ) +{ + VipsSource *input; + + if( !(input = vips_source_new_from_descriptor( descriptor )) ) + throw VError(); + + VSource out( input ); + + return( out ); +} + +VSource +VSource::new_from_file( const char *filename ) +{ + VipsSource *input; + + if( !(input = vips_source_new_from_file( filename )) ) + throw VError(); + + VSource out( input ); + + return( out ); +} + +VSource +VSource::new_from_blob( VipsBlob *blob ) +{ + VipsSource *input; + + if( !(input = vips_source_new_from_blob( blob )) ) + throw VError(); + + VSource out( input ); + + return( out ); +} + +VSource +VSource::new_from_memory( const void *data, + size_t size ) +{ + VipsSource *input; + + if( !(input = vips_source_new_from_memory( data, size )) ) + throw VError(); + + VSource out( input ); + + return( out ); +} + +VSource +VSource::new_from_options( const char *options ) +{ + VipsSource *input; + + if( !(input = vips_source_new_from_options( options )) ) + throw VError(); + + VSource out( input ); + + return( out ); +} + +VOption * +VOption::set( const char *name, const VSource value ) +{ + Pair *pair = new Pair( name ); + + pair->input = true; + g_value_init( &pair->value, VIPS_TYPE_SOURCE ); + g_value_set_object( &pair->value, value.get_source() ); + options.push_back( pair ); + + return( this ); +} + +VTarget +VTarget::new_to_descriptor( int descriptor ) +{ + VipsTarget *output; + + if( !(output = vips_target_new_to_descriptor( descriptor )) ) + throw VError(); + + VTarget out( output ); + + return( out ); +} + +VTarget +VTarget::new_to_file( const char *filename ) +{ + VipsTarget *output; + + if( !(output = vips_target_new_to_file( filename )) ) + throw VError(); + + VTarget out( output ); + + return( out ); +} + +VTarget +VTarget::new_to_memory() +{ + VipsTarget *output; + + if( !(output = vips_target_new_to_memory()) ) + throw VError(); + + VTarget out( output ); + + return( out ); +} + +VOption * +VOption::set( const char *name, const VTarget value ) +{ + Pair *pair = new Pair( name ); + + pair->input = true; + g_value_init( &pair->value, VIPS_TYPE_TARGET ); + g_value_set_object( &pair->value, value.get_target() ); + options.push_back( pair ); + + return( this ); +} + +VIPS_NAMESPACE_END diff --git a/src/libvips/cplusplus/VImage.cpp b/src/libvips/cplusplus/VImage.cpp index 205b46cb..5abe632c 100644 --- a/src/libvips/cplusplus/VImage.cpp +++ b/src/libvips/cplusplus/VImage.cpp @@ -169,7 +169,7 @@ VOption::set( const char *name, const char *value ) // input image VOption * -VOption::set( const char *name, VImage value ) +VOption::set( const char *name, const VImage value ) { Pair *pair = new Pair( name ); @@ -592,7 +592,30 @@ 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 ) ); + return( new_from_buffer( buf.c_str(), buf.size(), + option_string, options ) ); +} + +VImage +VImage::new_from_source( VSource source, const char *option_string, + VOption *options ) +{ + const char *operation_name; + VImage out; + + if( !(operation_name = vips_foreign_find_load_source( + source.get_source() )) ) { + delete options; + throw( VError() ); + } + + options = (options ? options : VImage::option())-> + set( "source", source )-> + set( "out", &out ); + + call_option_string( operation_name, option_string, options ); + + return( out ); } VImage @@ -679,6 +702,26 @@ VImage::write_to_buffer( const char *suffix, void **buf, size_t *size, } } +void +VImage::write_to_target( const char *suffix, VTarget target, + VOption *options ) const +{ + char filename[VIPS_PATH_MAX]; + char option_string[VIPS_PATH_MAX]; + const char *operation_name; + + vips__filename_split8( suffix, filename, option_string ); + if( !(operation_name = vips_foreign_find_save_target( filename )) ) { + delete options; + throw VError(); + } + + call_option_string( operation_name, option_string, + (options ? options : VImage::option())-> + set( "in", *this )-> + set( "target", target ) ); +} + #include "vips-operators.cpp" std::vector diff --git a/src/libvips/cplusplus/VInterpolate.cpp b/src/libvips/cplusplus/VInterpolate.cpp index 265bf66e..cb59715c 100644 --- a/src/libvips/cplusplus/VInterpolate.cpp +++ b/src/libvips/cplusplus/VInterpolate.cpp @@ -61,7 +61,7 @@ VInterpolate::new_from_name( const char *name, VOption *options ) } VOption * -VOption::set( const char *name, VInterpolate value ) +VOption::set( const char *name, const VInterpolate value ) { Pair *pair = new Pair( name ); diff --git a/src/libvips/cplusplus/vips-operators.cpp b/src/libvips/cplusplus/vips-operators.cpp index beae5057..12694762 100644 --- a/src/libvips/cplusplus/vips-operators.cpp +++ b/src/libvips/cplusplus/vips-operators.cpp @@ -1,5 +1,5 @@ // bodies for vips operations -// Wed Apr 24 15:50:21 CEST 2019 +// Wed 01 Jan 2020 12:22:12 PM CET // this file is generated automatically, do not edit! VImage VImage::CMC2LCh( VOption *options ) const @@ -491,6 +491,19 @@ VImage VImage::canny( VOption *options ) const return( out ); } +VImage VImage::case_image( std::vector cases, VOption *options ) const +{ + VImage out; + + call( "case", + (options ? options : VImage::option())-> + set( "index", *this )-> + set( "out", &out )-> + set( "cases", cases ) ); + + return( out ); +} + VImage VImage::cast( VipsBandFormat format, VOption *options ) const { VImage out; @@ -1615,6 +1628,18 @@ VImage VImage::jpegload_buffer( VipsBlob *buffer, VOption *options ) return( out ); } +VImage VImage::jpegload_source( VSource source, VOption *options ) +{ + VImage out; + + call( "jpegload_source", + (options ? options : VImage::option())-> + set( "out", &out )-> + set( "source", source ) ); + + return( out ); +} + void VImage::jpegsave( const char *filename, VOption *options ) const { call( "jpegsave", @@ -1642,6 +1667,14 @@ void VImage::jpegsave_mime( VOption *options ) const set( "in", *this ) ); } +void VImage::jpegsave_target( VTarget target, VOption *options ) const +{ + call( "jpegsave_target", + (options ? options : VImage::option())-> + set( "in", *this )-> + set( "target", target ) ); +} + VImage VImage::labelregions( VOption *options ) const { VImage mask; @@ -2286,6 +2319,18 @@ VImage VImage::pngload_buffer( VipsBlob *buffer, VOption *options ) return( out ); } +VImage VImage::pngload_source( VSource source, VOption *options ) +{ + VImage out; + + call( "pngload_source", + (options ? options : VImage::option())-> + set( "out", &out )-> + set( "source", source ) ); + + return( out ); +} + void VImage::pngsave( const char *filename, VOption *options ) const { call( "pngsave", @@ -2306,6 +2351,14 @@ VipsBlob *VImage::pngsave_buffer( VOption *options ) const return( buffer ); } +void VImage::pngsave_target( VTarget target, VOption *options ) const +{ + call( "pngsave_target", + (options ? options : VImage::option())-> + set( "in", *this )-> + set( "target", target ) ); +} + VImage VImage::ppmload( const char *filename, VOption *options ) { VImage out; @@ -2413,6 +2466,30 @@ VImage VImage::radload( const char *filename, VOption *options ) return( out ); } +VImage VImage::radload_buffer( VipsBlob *buffer, VOption *options ) +{ + VImage out; + + call( "radload_buffer", + (options ? options : VImage::option())-> + set( "out", &out )-> + set( "buffer", buffer ) ); + + return( out ); +} + +VImage VImage::radload_source( VSource source, VOption *options ) +{ + VImage out; + + call( "radload_source", + (options ? options : VImage::option())-> + set( "out", &out )-> + set( "source", source ) ); + + return( out ); +} + void VImage::radsave( const char *filename, VOption *options ) const { call( "radsave", @@ -2433,6 +2510,14 @@ VipsBlob *VImage::radsave_buffer( VOption *options ) const return( buffer ); } +void VImage::radsave_target( VTarget target, VOption *options ) const +{ + call( "radsave_target", + (options ? options : VImage::option())-> + set( "in", *this )-> + set( "target", target ) ); +} + VImage VImage::rank( int width, int height, int index, VOption *options ) const { VImage out; @@ -2977,6 +3062,30 @@ VImage VImage::svgload_buffer( VipsBlob *buffer, VOption *options ) return( out ); } +VImage VImage::svgload_source( VSource source, VOption *options ) +{ + VImage out; + + call( "svgload_source", + (options ? options : VImage::option())-> + set( "out", &out )-> + set( "source", source ) ); + + return( out ); +} + +VImage VImage::switch_image( std::vector tests, VOption *options ) +{ + VImage out; + + call( "switch", + (options ? options : VImage::option())-> + set( "out", &out )-> + set( "tests", tests ) ); + + return( out ); +} + void VImage::system( const char *cmd_format, VOption *options ) { call( "system", @@ -3035,6 +3144,19 @@ VImage VImage::thumbnail_image( int width, VOption *options ) const return( out ); } +VImage VImage::thumbnail_source( VSource source, int width, VOption *options ) +{ + VImage out; + + call( "thumbnail_source", + (options ? options : VImage::option())-> + set( "out", &out )-> + set( "source", source )-> + set( "width", width ) ); + + return( out ); +} + VImage VImage::tiffload( const char *filename, VOption *options ) { VImage out; @@ -3059,6 +3181,18 @@ VImage VImage::tiffload_buffer( VipsBlob *buffer, VOption *options ) return( out ); } +VImage VImage::tiffload_source( VSource source, VOption *options ) +{ + VImage out; + + call( "tiffload_source", + (options ? options : VImage::option())-> + set( "out", &out )-> + set( "source", source ) ); + + return( out ); +} + void VImage::tiffsave( const char *filename, VOption *options ) const { call( "tiffsave", @@ -3170,6 +3304,18 @@ VImage VImage::webpload_buffer( VipsBlob *buffer, VOption *options ) return( out ); } +VImage VImage::webpload_source( VSource source, VOption *options ) +{ + VImage out; + + call( "webpload_source", + (options ? options : VImage::option())-> + set( "out", &out )-> + set( "source", source ) ); + + return( out ); +} + void VImage::webpsave( const char *filename, VOption *options ) const { call( "webpsave", @@ -3190,6 +3336,14 @@ VipsBlob *VImage::webpsave_buffer( VOption *options ) const return( buffer ); } +void VImage::webpsave_target( VTarget target, VOption *options ) const +{ + call( "webpsave_target", + (options ? options : VImage::option())-> + set( "in", *this )-> + set( "target", target ) ); +} + VImage VImage::worley( int width, int height, VOption *options ) { VImage out; diff --git a/src/pipeline.cc b/src/pipeline.cc index d542688e..be329e7c 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -916,11 +916,9 @@ class PipelineWorker : public Nan::AsyncWorker { } else if (baton->formatOut == "heif" || (mightMatchInput && isHeif) || (willMatchInput && inputImageType == ImageType::HEIF)) { // Write HEIF to file - #ifdef VIPS_TYPE_FOREIGN_HEIF_COMPRESSION if (sharp::IsAvif(baton->fileOut)) { baton->heifCompression = VIPS_FOREIGN_HEIF_COMPRESSION_AV1; } - #endif image.heifsave(const_cast(baton->fileOut.data()), VImage::option() ->set("strip", !baton->withMetadata) ->set("Q", baton->heifQuality) @@ -966,29 +964,26 @@ class PipelineWorker : public Nan::AsyncWorker { }; suffix = AssembleSuffixString(extname, options); } - // Remove alpha channel from tile background if image does not contain an alpha channel if (!HasAlpha(image)) { baton->tileBackground.pop_back(); } // Write DZ to file vips::VOption *options = VImage::option() - ->set("strip", !baton->withMetadata) - ->set("tile_size", baton->tileSize) - ->set("overlap", baton->tileOverlap) - ->set("container", baton->tileContainer) - ->set("layout", baton->tileLayout) - ->set("suffix", const_cast(suffix.data())) - ->set("angle", CalculateAngleRotation(baton->tileAngle)) - ->set("background", baton->tileBackground) - ->set("skip_blanks", baton->tileSkipBlanks); - + ->set("strip", !baton->withMetadata) + ->set("tile_size", baton->tileSize) + ->set("overlap", baton->tileOverlap) + ->set("container", baton->tileContainer) + ->set("layout", baton->tileLayout) + ->set("suffix", const_cast(suffix.data())) + ->set("angle", CalculateAngleRotation(baton->tileAngle)) + ->set("background", baton->tileBackground) + ->set("skip_blanks", baton->tileSkipBlanks); // libvips chooses a default depth based on layout. Instead of replicating that logic here by // not passing anything - libvips will handle choice if (baton->tileDepth < VIPS_FOREIGN_DZ_DEPTH_LAST) { options->set("depth", baton->tileDepth); } - image.dzsave(const_cast(baton->fileOut.data()), options); baton->formatOut = "dz"; } else if (baton->formatOut == "v" || (mightMatchInput && isV) || @@ -1004,7 +999,12 @@ class PipelineWorker : public Nan::AsyncWorker { } } } catch (vips::VError const &err) { - (baton->err).append(err.what()); + char const *what = err.what(); + if (what && what[0]) { + (baton->err).append(what); + } else { + (baton->err).append("Unknown error"); + } } // Clean up libvips' per-request data and threads vips_error_clear(); @@ -1377,11 +1377,9 @@ NAN_METHOD(pipeline) { AttrAsStr(options, "tiffPredictor").data())); baton->heifQuality = AttrTo(options, "heifQuality"); baton->heifLossless = AttrTo(options, "heifLossless"); - #ifdef VIPS_TYPE_FOREIGN_HEIF_COMPRESSION baton->heifCompression = static_cast( vips_enum_from_nick(nullptr, VIPS_TYPE_FOREIGN_HEIF_COMPRESSION, AttrAsStr(options, "heifCompression").data())); - #endif // Tile output baton->tileSize = AttrTo(options, "tileSize"); baton->tileOverlap = AttrTo(options, "tileOverlap"); diff --git a/test/unit/stats.js b/test/unit/stats.js index 88726242..bb840835 100644 --- a/test/unit/stats.js +++ b/test/unit/stats.js @@ -242,11 +242,11 @@ describe('Image Stats', function () { // red channel assert.strictEqual(0, stats.channels[0].min); - assert.strictEqual(255, stats.channels[0].max); - assert.strictEqual(true, isInAcceptableRange(stats.channels[0].sum, 83291370)); - assert.strictEqual(true, isInAcceptableRange(stats.channels[0].squaresSum, 11379783198)); - assert.strictEqual(true, isInAcceptableRange(stats.channels[0].mean, 105.36169496842616)); - assert.strictEqual(true, isInAcceptableRange(stats.channels[0].stdev, 57.39412151419967)); + assert.strictEqual(true, isInRange(stats.channels[0].max, 254, 255)); + assert.strictEqual(true, isInAcceptableRange(stats.channels[0].sum, 82506996)); + assert.strictEqual(true, isInAcceptableRange(stats.channels[0].squaresSum, 11213984832)); + assert.strictEqual(true, isInAcceptableRange(stats.channels[0].mean, 104.36947963892487)); + assert.strictEqual(true, isInAcceptableRange(stats.channels[0].stdev, 57.379896254993135)); assert.strictEqual(true, isInteger(stats.channels[0].minX)); assert.strictEqual(true, isInRange(stats.channels[0].minX, 0, 1024)); assert.strictEqual(true, isInteger(stats.channels[0].minY)); @@ -258,11 +258,11 @@ describe('Image Stats', function () { // green channel assert.strictEqual(0, stats.channels[1].min); - assert.strictEqual(255, stats.channels[1].max); - assert.strictEqual(true, isInAcceptableRange(stats.channels[1].sum, 120877425)); - assert.strictEqual(true, isInAcceptableRange(stats.channels[1].squaresSum, 20774687595)); - assert.strictEqual(true, isInAcceptableRange(stats.channels[1].mean, 152.9072025279307)); - assert.strictEqual(true, isInAcceptableRange(stats.channels[1].stdev, 53.84143349689916)); + assert.strictEqual(true, isInRange(stats.channels[1].max, 254, 255)); + assert.strictEqual(true, isInAcceptableRange(stats.channels[1].sum, 120089056)); + assert.strictEqual(true, isInAcceptableRange(stats.channels[1].squaresSum, 20533721114)); + assert.strictEqual(true, isInAcceptableRange(stats.channels[1].mean, 151.90993361398964)); + assert.strictEqual(true, isInAcceptableRange(stats.channels[1].stdev, 53.83370206587037)); assert.strictEqual(true, isInteger(stats.channels[1].minX)); assert.strictEqual(true, isInRange(stats.channels[1].minX, 0, 1024)); assert.strictEqual(true, isInteger(stats.channels[1].minY)); @@ -274,11 +274,11 @@ describe('Image Stats', function () { // blue channel assert.strictEqual(0, stats.channels[2].min); - assert.strictEqual(255, stats.channels[2].max); - assert.strictEqual(true, isInAcceptableRange(stats.channels[2].sum, 138938859)); - assert.strictEqual(true, isInAcceptableRange(stats.channels[2].squaresSum, 28449125593)); - assert.strictEqual(true, isInAcceptableRange(stats.channels[2].mean, 175.75450711423252)); - assert.strictEqual(true, isInAcceptableRange(stats.channels[2].stdev, 71.39929031070358)); + assert.strictEqual(true, isInRange(stats.channels[2].max, 254, 255)); + assert.strictEqual(true, isInAcceptableRange(stats.channels[2].sum, 138153653)); + assert.strictEqual(true, isInAcceptableRange(stats.channels[2].squaresSum, 28172033081)); + assert.strictEqual(true, isInAcceptableRange(stats.channels[2].mean, 174.76123932359133)); + assert.strictEqual(true, isInAcceptableRange(stats.channels[2].stdev, 71.38276338513747)); assert.strictEqual(true, isInteger(stats.channels[2].minX)); assert.strictEqual(true, isInRange(stats.channels[2].minX, 0, 1024)); assert.strictEqual(true, isInteger(stats.channels[2].minY)); diff --git a/test/unit/toBuffer.js b/test/unit/toBuffer.js index 2f79c04c..25637a85 100644 --- a/test/unit/toBuffer.js +++ b/test/unit/toBuffer.js @@ -10,8 +10,8 @@ describe('toBuffer', () => { const image = sharp(fixtures.inputJpg); image.toBuffer({ resolveWithObject: true }).then((obj) => { image.toBuffer().then((buff) => { - assert.strict.equal(Buffer.isBuffer(buff), true); - assert.strict.equal(typeof obj, 'object'); + assert.strictEqual(Buffer.isBuffer(buff), true); + assert.strictEqual(typeof obj, 'object'); done(); }); });