Upgrade to libvips v8.13.0-rc1 (#3230)

* Switch from decompress-zip to extract-zip

The former seems to hang when unzipping a ZIP64 file that uses
the general purpose bit flag 3 as file entry.

See: https://github.com/thejoshwolfe/yauzl#no-streaming-unzip-api

* Prefer to call via static member instead

Makes it clearer that a static method is being called.

* `flatten-orange.jpg`: save without chroma subsampling

To ensure no down-scaling of the Cr/Cb channels.
This commit is contained in:
Kleis Auke Wolthuizen 2022-06-26 23:39:29 +02:00 committed by GitHub
parent e40a881ab4
commit afc4c5bf79
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 128 additions and 62 deletions

View File

@ -15,10 +15,11 @@
'_ALLOW_KEYWORD_MACROS' '_ALLOW_KEYWORD_MACROS'
], ],
'sources': [ 'sources': [
'src/libvips/cplusplus/VError.cpp',
'src/libvips/cplusplus/VConnection.cpp', 'src/libvips/cplusplus/VConnection.cpp',
'src/libvips/cplusplus/VError.cpp',
'src/libvips/cplusplus/VImage.cpp',
'src/libvips/cplusplus/VInterpolate.cpp', 'src/libvips/cplusplus/VInterpolate.cpp',
'src/libvips/cplusplus/VImage.cpp' 'src/libvips/cplusplus/VRegion.cpp'
], ],
'include_dirs': [ 'include_dirs': [
'<(sharp_vendor_dir)/include', '<(sharp_vendor_dir)/include',

View File

@ -140,9 +140,9 @@
"devDependencies": { "devDependencies": {
"async": "^3.2.4", "async": "^3.2.4",
"cc": "^3.0.1", "cc": "^3.0.1",
"decompress-zip": "^0.3.3",
"documentation": "^13.2.5", "documentation": "^13.2.5",
"exif-reader": "^1.0.3", "exif-reader": "^1.0.3",
"extract-zip": "^2.0.1",
"icc": "^2.0.0", "icc": "^2.0.0",
"license-checker": "^25.0.1", "license-checker": "^25.0.1",
"mocha": "^10.0.0", "mocha": "^10.0.0",
@ -154,19 +154,19 @@
}, },
"license": "Apache-2.0", "license": "Apache-2.0",
"config": { "config": {
"libvips": "8.12.2", "libvips": "8.13.0-rc1",
"integrity": { "integrity": {
"darwin-arm64v8": "sha512-p46s/bbJAjkOXzPISZt9HUpG9GWjwQkYnLLRLKzsBJHLtB3X6C6Y/zXI5Hd0DOojcFkks9a0kTN+uDQ/XJY19g==", "darwin-arm64v8": "sha512-tczrNbjU/+bUhTHilUNd2OL9DgwPvUX3L6LUTQHmLZlatxT5ztj6of1erNXYhgt4lLhruKcKkYYQyRicBoKsRA==",
"darwin-x64": "sha512-6vOHVZnvXwe6EXRsy29jdkUzBE6ElNpXUwd+m8vV7qy32AnXu7B9YemHsZ44vWviIwPZeXF6Nhd9EFLM0wWohw==", "darwin-x64": "sha512-eonsBwyPEHxFL++bCG+rEUokSOaCbImSJ5VA//Qkv34QAO+vZWzj9RMf/ETvT3pHzrx56Wm3SwpGgJ/BIeyKgg==",
"linux-arm64v8": "sha512-XwZdS63yhqLtbFtx/0eoLF/Agf5qtTrI11FMnMRpuBJWd4jHB60RAH+uzYUgoChCmKIS+AeXYMLm4d8Ns2QX8w==", "linux-arm64v8": "sha512-/hLYMwmWG3wKyUeDvNZCMJL3mZ+/8mj+VfVbo2DsNsI6MxBnZ4aXg3qMJ17FcEa2sPDHhkVqaJl5DnXGn87gGQ==",
"linux-armv6": "sha512-Rh0Q0kqwPG2MjXWOkPCuPEyiUKFgKJYWLgS835D4MrXgdKr8Tft/eVrc2iGIxt2re30VpDiZ1h0Rby1aCZt2zw==", "linux-armv6": "sha512-25Ml2+J+KWj7yKnZVcrxZmZHFIwzbW6d/kACT7duz48NmGWDD0jnu/nroAETYiMqS1W5fHlPRiwG82/d/PeIpg==",
"linux-armv7": "sha512-heTS/MsmRvu4JljINxP+vDiS9ZZfuGhr3IStb5F7Gc0/QLRhllYAg4rcO8L1eTK9sIIzG5ARvI19+YUZe7WbzA==", "linux-armv7": "sha512-7u6RS3IFptQMGRMujyvz1kh8YFPBRdEu9T1zJKYl0/cZkxeNNiljW4PenOQ6cxoPlXivUDpEOoifo4B6a3B4/A==",
"linux-x64": "sha512-SSWAwBFi0hx8V/h/v82tTFGKWTFv9FiCK3Timz5OExuI+sX1Ngrd0PVQaWXOThGNdel/fcD3Bz9YjSt4feBR1g==", "linux-x64": "sha512-v6/vcp+71p4NtoEpWUghgboVzavwX8FVa1NXBDVYMx/up4AmQEjEzOicSiLxXc97Ydhk6FJz8Qkrfp05AN0SfQ==",
"linuxmusl-arm64v8": "sha512-Rhks+5C7p7aO6AucLT1uvzo8ohlqcqCUPgZmN+LZjsPWob/Iix3MfiDYtv/+gTvdeEfXxbCU6/YuPBwHQ7/crA==", "linuxmusl-arm64v8": "sha512-8DNTwBbAna/R0/ksmaO/2TKZxjdkgSppTjmM9xIAZO7tbknuDCqi0YyJiiCP5Nh5yGtpf+PcQdSu/ca21ICwAQ==",
"linuxmusl-x64": "sha512-IOyjSQqpWVntqOUpCHVWuQwACwmmjdi15H8Pc+Ma1JkhPogTfVsFQWyL7DuOTD3Yr23EuYGzovUX00duOtfy/g==", "linuxmusl-x64": "sha512-3B12ehfury7m39sZ1lyTxzcf3hPAcCC/+4l16C0Mkoc6FGKPV/CJFtoCzNjUEsEJR5rMKOFBfsgZOoNk0KEzSQ==",
"win32-arm64v8": "sha512-A+Qe8Ipewtvw9ldvF6nWed2J8kphzrUE04nFeKCtNx6pfGQ/MAlCKMjt/U8VgUKNjB01zJDUW9XE0+FhGZ/UpQ==", "win32-arm64v8": "sha512-45gnLXiq4EtJNnhhgSY8Kgr5L0ed637Kn2SCW7jhQu9qZS3riLSM5Kk+6L1Kqc+cyNnsFbtWWBWCZp01Tg9HSw==",
"win32-ia32": "sha512-cMrAvwFdDeAVnLJt0IPMPRKaIFhyXYGTprsM0DND9VUHE8F7dJMR44tS5YkXsGh1QNDtjKT6YuxAVUglmiXtpA==", "win32-ia32": "sha512-LEodsYlTo0gkrfpHFNr9IwSMI7MTBBy/vry0MazcUAIPkiPhx3CCNbPZL7pd7vuHZ4CP5XNsArTb0RaHpMrc+w==",
"win32-x64": "sha512-vLFIfw6aW2zABa8jpgzWDhljnE6glktrddErVyazAIoHl6BFFe/Da+LK1DbXvIYHz7fyOoKhSfCJHCiJG1Vg6w==" "win32-x64": "sha512-5usGDnN1pmFoqfEuHmdvKF/35NbQLlnal5T2bMWDx9kvLIOy7WSahvSGAeDg9cXjHv9SONX/qdpKuJ55c6aD4g=="
}, },
"runtime": "napi", "runtime": "napi",
"target": 5 "target": 5

View File

@ -366,32 +366,33 @@ namespace sharp {
} }
} }
} else { } else {
if (descriptor->createChannels > 0) { int const channels = descriptor->createChannels;
if (channels > 0) {
// Create new image // Create new image
if (descriptor->createNoiseType == "gaussian") { if (descriptor->createNoiseType == "gaussian") {
int const channels = descriptor->createChannels;
image = VImage::new_matrix(descriptor->createWidth, descriptor->createHeight);
std::vector<VImage> bands = {}; std::vector<VImage> bands = {};
bands.reserve(channels); bands.reserve(channels);
for (int _band = 0; _band < channels; _band++) { for (int _band = 0; _band < channels; _band++) {
bands.push_back(image.gaussnoise( bands.push_back(VImage::gaussnoise(descriptor->createWidth, descriptor->createHeight, VImage::option()
descriptor->createWidth, ->set("mean", descriptor->createNoiseMean)
descriptor->createHeight, ->set("sigma", descriptor->createNoiseSigma)));
VImage::option()->set("mean", descriptor->createNoiseMean)->set("sigma", descriptor->createNoiseSigma)));
} }
image = image.bandjoin(bands); image = VImage::bandjoin(bands).copy(VImage::option()->set("interpretation",
channels < 3 ? VIPS_INTERPRETATION_B_W: VIPS_INTERPRETATION_sRGB));
} else { } else {
std::vector<double> background = { std::vector<double> background = {
descriptor->createBackground[0], descriptor->createBackground[0],
descriptor->createBackground[1], descriptor->createBackground[1],
descriptor->createBackground[2] descriptor->createBackground[2]
}; };
if (descriptor->createChannels == 4) { if (channels == 4) {
background.push_back(descriptor->createBackground[3]); background.push_back(descriptor->createBackground[3]);
} }
image = VImage::new_matrix(descriptor->createWidth, descriptor->createHeight).new_from_image(background); image = VImage::new_matrix(descriptor->createWidth, descriptor->createHeight)
.copy(VImage::option()->set("interpretation",
channels < 3 ? VIPS_INTERPRETATION_B_W : VIPS_INTERPRETATION_sRGB))
.new_from_image(background);
} }
image.get_image()->Type = image.guess_interpretation();
image = image.cast(VIPS_FORMAT_UCHAR); image = image.cast(VIPS_FORMAT_UCHAR);
imageType = ImageType::RAW; imageType = ImageType::RAW;
} else { } else {

View File

@ -31,7 +31,6 @@
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> #include <config.h>
#endif /*HAVE_CONFIG_H*/ #endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <vips/vips8> #include <vips/vips8>

View File

@ -30,7 +30,6 @@
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> #include <config.h>
#endif /*HAVE_CONFIG_H*/ #endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <vips/vips8> #include <vips/vips8>

View File

@ -38,7 +38,6 @@
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> #include <config.h>
#endif /*HAVE_CONFIG_H*/ #endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <vips/vips8> #include <vips/vips8>
@ -733,7 +732,7 @@ VImage::write_to_buffer( const char *suffix, void **buf, size_t *size,
set( "in", *this )-> set( "in", *this )->
set( "target", target ) ); set( "target", target ) );
g_object_get( target.get_target(), "blob", &blob, NULL ); g_object_get( target.get_target(), "blob", &blob, (void *) NULL );
} }
else if( (operation_name = vips_foreign_find_save_buffer( filename )) ) { else if( (operation_name = vips_foreign_find_save_buffer( filename )) ) {
call_option_string( operation_name, option_string, call_option_string( operation_name, option_string,
@ -778,6 +777,32 @@ VImage::write_to_target( const char *suffix, VTarget target,
set( "target", target ) ); set( "target", target ) );
} }
VRegion
VImage::region() const
{
return VRegion::new_from_image( *this );
}
VRegion
VImage::region( VipsRect *rect ) const
{
VRegion region = VRegion::new_from_image( *this );
region.prepare( rect );
return region;
}
VRegion
VImage::region( int left, int top, int width, int height ) const
{
VRegion region = VRegion::new_from_image( *this );
region.prepare( left, top, width, height );
return region;
}
#include "vips-operators.cpp" #include "vips-operators.cpp"
std::vector<VImage> std::vector<VImage>

View File

@ -31,7 +31,6 @@
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> #include <config.h>
#endif /*HAVE_CONFIG_H*/ #endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <vips/vips8> #include <vips/vips8>

View File

@ -0,0 +1,27 @@
// Object part of VRegion class
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/vips8>
#include <vips/debug.h>
VIPS_NAMESPACE_START
VRegion
VRegion::new_from_image( VImage image )
{
VipsRegion *region;
if( !(region = vips_region_new( image.get_image() )) ) {
throw VError();
}
VRegion out( region );
return( out );
}
VIPS_NAMESPACE_END

View File

@ -1,5 +1,4 @@
// bodies for vips operations // bodies for vips operations
// Mon Nov 1 03:31:09 PM CET 2021
// this file is generated automatically, do not edit! // this file is generated automatically, do not edit!
VImage VImage::CMC2LCh( VOption *options ) const VImage VImage::CMC2LCh( VOption *options ) const
@ -943,6 +942,14 @@ VipsBlob *VImage::dzsave_buffer( VOption *options ) const
return( buffer ); return( buffer );
} }
void VImage::dzsave_target( VTarget target, VOption *options ) const
{
call( "dzsave_target",
(options ? options : VImage::option())->
set( "in", *this )->
set( "target", target ) );
}
VImage VImage::embed( int x, int y, int width, int height, VOption *options ) const VImage VImage::embed( int x, int y, int width, int height, VOption *options ) const
{ {
VImage out; VImage out;
@ -3521,6 +3528,14 @@ VipsBlob *VImage::tiffsave_buffer( VOption *options ) const
return( buffer ); return( buffer );
} }
void VImage::tiffsave_target( VTarget target, VOption *options ) const
{
call( "tiffsave_target",
(options ? options : VImage::option())->
set( "in", *this )->
set( "target", target ) );
}
VImage VImage::tilecache( VOption *options ) const VImage VImage::tilecache( VOption *options ) const
{ {
VImage out; VImage out;

View File

@ -668,7 +668,7 @@ class PipelineWorker : public Napi::AsyncWorker {
xs.push_back(left); xs.push_back(left);
ys.push_back(top); ys.push_back(top);
} }
image = image.composite(images, modes, VImage::option()->set("x", xs)->set("y", ys)); image = VImage::composite(images, modes, VImage::option()->set("x", xs)->set("y", ys));
} }
// Reverse premultiplication after all transformations: // Reverse premultiplication after all transformations:

View File

@ -22,7 +22,6 @@
#include "stats.h" #include "stats.h"
static void* sharp_vips_init(void*) { static void* sharp_vips_init(void*) {
g_setenv("VIPS_MIN_STACK_SIZE", "2m", FALSE);
vips_init("sharp"); vips_init("sharp");
return nullptr; return nullptr;
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 424 KiB

After

Width:  |  Height:  |  Size: 424 KiB

View File

@ -23,6 +23,7 @@ describe('Alpha transparency', function () {
.flatten({ .flatten({
background: { r: 255, g: 102, b: 0 } background: { r: 255, g: 102, b: 0 }
}) })
.jpeg({ chromaSubsampling: '4:4:4' })
.toBuffer(function (err, data, info) { .toBuffer(function (err, data, info) {
if (err) throw err; if (err) throw err;
assert.strictEqual(400, info.width); assert.strictEqual(400, info.width);
@ -35,6 +36,7 @@ describe('Alpha transparency', function () {
sharp(fixtures.inputPngWithTransparency) sharp(fixtures.inputPngWithTransparency)
.resize(400, 300) .resize(400, 300)
.flatten({ background: '#ff6600' }) .flatten({ background: '#ff6600' })
.jpeg({ chromaSubsampling: '4:4:4' })
.toBuffer(function (err, data, info) { .toBuffer(function (err, data, info) {
if (err) throw err; if (err) throw err;
assert.strictEqual(400, info.width); assert.strictEqual(400, info.width);

View File

@ -27,7 +27,9 @@ describe('AVIF', () => {
format: 'jpeg', format: 'jpeg',
hasAlpha: false, hasAlpha: false,
hasProfile: false, hasProfile: false,
height: 14, // 32 / (2048 / 858) = 13.40625
// Math.round(13.40625) = 13
height: 13,
isProgressive: false, isProgressive: false,
space: 'srgb', space: 'srgb',
width: 32 width: 32
@ -70,7 +72,11 @@ describe('AVIF', () => {
format: 'heif', format: 'heif',
hasAlpha: false, hasAlpha: false,
hasProfile: false, hasProfile: false,
height: 14, // FIXME(kleisauke): https://github.com/strukturag/libheif/issues/365
// $ vips black x.avif 32 13
// $ vipsheader x.avif
// x.avif: 32x12 uchar, 3 bands, srgb, heifload
height: 12,
isProgressive: false, isProgressive: false,
pagePrimary: 0, pagePrimary: 0,
pages: 1, pages: 1,

View File

@ -5,11 +5,9 @@ const sharp = require('../../');
const libcFamily = detectLibc.familySync(); const libcFamily = detectLibc.familySync();
const usingCache = libcFamily !== detectLibc.MUSL; const usingCache = libcFamily !== detectLibc.MUSL;
const usingSimd = !process.env.G_DEBUG; const usingSimd = !(process.env.G_DEBUG || process.env.VIPS_NOVECTOR);
const concurrency = const concurrency = process.env.VIPS_CONCURRENCY ||
libcFamily === detectLibc.MUSL || process.arch === 'arm' (libcFamily === detectLibc.MUSL || process.arch === 'arm' ? 1 : undefined);
? 1
: undefined;
beforeEach(function () { beforeEach(function () {
sharp.cache(usingCache); sharp.cache(usingCache);

View File

@ -343,7 +343,7 @@ describe('Image metadata', function () {
assert.strictEqual(depth, 'uchar'); assert.strictEqual(depth, 'uchar');
assert.strictEqual(isProgressive, false); assert.strictEqual(isProgressive, false);
assert.strictEqual(pages, 10); assert.strictEqual(pages, 10);
assert.strictEqual(loop, 2); assert.strictEqual(loop, 3);
assert.deepStrictEqual(delay, [...Array(9).fill(3000), 15000]); assert.deepStrictEqual(delay, [...Array(9).fill(3000), 15000]);
assert.strictEqual(hasProfile, false); assert.strictEqual(hasProfile, false);
assert.strictEqual(hasAlpha, true); assert.strictEqual(hasAlpha, true);

View File

@ -6,7 +6,7 @@ const assert = require('assert');
const eachLimit = require('async/eachLimit'); const eachLimit = require('async/eachLimit');
const rimraf = require('rimraf'); const rimraf = require('rimraf');
const DecompressZip = require('decompress-zip'); const extractZip = require('extract-zip');
const sharp = require('../../'); const sharp = require('../../');
const fixtures = require('../fixtures'); const fixtures = require('../fixtures');
@ -14,7 +14,8 @@ const fixtures = require('../fixtures');
// Verifies all tiles in a given dz output directory are <= size // Verifies all tiles in a given dz output directory are <= size
const assertDeepZoomTiles = function (directory, expectedSize, expectedLevels, done) { const assertDeepZoomTiles = function (directory, expectedSize, expectedLevels, done) {
// Get levels // Get levels
const levels = fs.readdirSync(directory); const dirents = fs.readdirSync(directory, { withFileTypes: true });
const levels = dirents.filter(dirent => dirent.isDirectory()).map(dirent => dirent.name);
assert.strictEqual(expectedLevels, levels.length); assert.strictEqual(expectedLevels, levels.length);
// Get tiles // Get tiles
const tiles = []; const tiles = [];
@ -67,8 +68,10 @@ const assertZoomifyTiles = function (directory, expectedTileSize, expectedLevels
}; };
const assertGoogleTiles = function (directory, expectedTileSize, expectedLevels, done) { const assertGoogleTiles = function (directory, expectedTileSize, expectedLevels, done) {
const levels = fs.readdirSync(directory); // Get levels
assert.strictEqual(expectedLevels, levels.length - 1); // subtract one to account for default blank tile const dirents = fs.readdirSync(directory, { withFileTypes: true });
const levels = dirents.filter(dirent => dirent.isDirectory()).map(dirent => dirent.name);
assert.strictEqual(expectedLevels, levels.length);
fs.stat(path.join(directory, 'blank.png'), function (err, stat) { fs.stat(path.join(directory, 'blank.png'), function (err, stat) {
if (err) throw err; if (err) throw err;
@ -94,7 +97,8 @@ const assertGoogleTiles = function (directory, expectedTileSize, expectedLevels,
// Verifies tiles at specified level in a given output directory are > size+overlap // Verifies tiles at specified level in a given output directory are > size+overlap
const assertTileOverlap = function (directory, tileSize, done) { const assertTileOverlap = function (directory, tileSize, done) {
// Get sorted levels // Get sorted levels
const levels = fs.readdirSync(directory).sort((a, b) => a - b); const dirents = fs.readdirSync(directory, { withFileTypes: true });
const levels = dirents.filter(dirent => dirent.isDirectory()).map(dirent => dirent.name).sort((a, b) => a - b);
// Select the highest tile level // Select the highest tile level
const highestLevel = levels[levels.length - 1]; const highestLevel = levels[levels.length - 1];
// Get sorted tiles from greatest level // Get sorted tiles from greatest level
@ -908,14 +912,10 @@ describe('Tile', function () {
if (err) throw err; if (err) throw err;
assert.strictEqual(true, stat.isFile()); assert.strictEqual(true, stat.isFile());
assert.strictEqual(true, stat.size > 0); assert.strictEqual(true, stat.size > 0);
new DecompressZip(container) extractZip(container, { dir: path.dirname(extractTo) })
.on('extract', function () { .then(() => {
assertDeepZoomTiles(directory, 256, 13, done); assertDeepZoomTiles(directory, 256, 13, done);
}) });
.on('error', function (err) {
throw err;
})
.extract({ path: path.dirname(extractTo) });
}); });
}); });
}); });
@ -942,14 +942,10 @@ describe('Tile', function () {
if (err) throw err; if (err) throw err;
assert.strictEqual(true, stat.isFile()); assert.strictEqual(true, stat.isFile());
assert.strictEqual(true, stat.size > 0); assert.strictEqual(true, stat.size > 0);
new DecompressZip(container) extractZip(container, { dir: path.dirname(extractTo) })
.on('extract', function () { .then(() => {
assertDeepZoomTiles(directory, 256, 13, done); assertDeepZoomTiles(directory, 256, 13, done);
}) });
.on('error', function (err) {
throw err;
})
.extract({ path: path.dirname(extractTo) });
}); });
}); });
}); });

View File

@ -140,7 +140,6 @@ describe('Utilities', function () {
assert.strictEqual('object', typeof sharp.vendor); assert.strictEqual('object', typeof sharp.vendor);
assert.strictEqual('string', typeof sharp.vendor.current); assert.strictEqual('string', typeof sharp.vendor.current);
assert.strictEqual(true, Array.isArray(sharp.vendor.installed)); assert.strictEqual(true, Array.isArray(sharp.vendor.installed));
assert.strictEqual(true, sharp.vendor.installed.length > 0);
}); });
}); });
}); });