From e922ef7450eb17ea52fe7b549147e85874bc6338 Mon Sep 17 00:00:00 2001 From: Hans Date: Thu, 17 Apr 2025 11:53:05 +0800 Subject: [PATCH 001/115] Add support for prebuilt Windows ARM64 binaries #4375 --- .github/workflows/ci.yml | 11 +++++++++ docs/public/humans.txt | 3 +++ docs/src/content/docs/changelog.md | 4 +++ docs/src/content/docs/install.md | 1 + lib/libvips.js | 2 +- npm/package.json | 1 + npm/win32-arm64/package.json | 39 ++++++++++++++++++++++++++++++ package.json | 2 ++ test/unit/text.js | 2 +- 9 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 npm/win32-arm64/package.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a94483a33..53b5e12db 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -110,6 +110,17 @@ jobs: nodejs_version: "^22.9.0" nodejs_version_major: 22 platform: win32-x64 + - os: windows-11-arm + nodejs_arch: arm64 + nodejs_version: "^20.3.0" + nodejs_version_major: 20 + platform: win32-arm64 + prebuild: true + - os: windows-11-arm + nodejs_arch: arm64 + nodejs_version: "^22.9.0" + nodejs_version_major: 22 + platform: win32-arm64 steps: - name: Dependencies (Rocky Linux glibc) if: contains(matrix.container, 'rockylinux') diff --git a/docs/public/humans.txt b/docs/public/humans.txt index f8bd272fa..01af76f07 100644 --- a/docs/public/humans.txt +++ b/docs/public/humans.txt @@ -317,3 +317,6 @@ GitHub: https://github.com/florentzabera Name: Quentin Pinçon GitHub: https://github.com/qpincon + +Name: Hans Chen +GitHub: https://github.com/hans00 diff --git a/docs/src/content/docs/changelog.md b/docs/src/content/docs/changelog.md index d45e433e8..5026a6025 100644 --- a/docs/src/content/docs/changelog.md +++ b/docs/src/content/docs/changelog.md @@ -14,6 +14,10 @@ Requires libvips v8.16.1 * Ensure `pdfBackground` constructor property is used. [#4207](https://github.com/lovell/sharp/pull/4207) +* Add support for prebuilt Windows ARM64 binaries. + [#4375](https://github.com/lovell/sharp/pull/4375) + [@hans00](https://github.com/hans00) + * TypeScript: Ensure `smartDeblock` property is included in WebP definition. [#4387](https://github.com/lovell/sharp/pull/4387) [@Stephen-X](https://github.com/Stephen-X) diff --git a/docs/src/content/docs/install.md b/docs/src/content/docs/install.md index 0ca0290b1..3e0a4a014 100644 --- a/docs/src/content/docs/install.md +++ b/docs/src/content/docs/install.md @@ -53,6 +53,7 @@ Ready-compiled sharp and libvips binaries are provided for use on the most commo * Linux x64 (glibc >= 2.26, musl >= 1.2.2, CPU with SSE4.2) * Windows x64 * Windows x86 +* Windows ARM64 This provides support for the JPEG, PNG, WebP, AVIF (limited to 8-bit depth), TIFF, GIF and SVG (input) image formats. diff --git a/lib/libvips.js b/lib/libvips.js index 9a5639750..254361e3a 100644 --- a/lib/libvips.js +++ b/lib/libvips.js @@ -20,7 +20,7 @@ const prebuiltPlatforms = [ 'darwin-arm64', 'darwin-x64', 'linux-arm', 'linux-arm64', 'linux-s390x', 'linux-x64', 'linuxmusl-arm64', 'linuxmusl-x64', - 'win32-ia32', 'win32-x64' + 'win32-arm64', 'win32-ia32', 'win32-x64' ]; const spawnSyncOptions = { diff --git a/npm/package.json b/npm/package.json index fd921905e..5c15b996b 100644 --- a/npm/package.json +++ b/npm/package.json @@ -13,6 +13,7 @@ "linuxmusl-arm64", "linuxmusl-x64", "wasm32", + "win32-arm64", "win32-ia32", "win32-x64" ] diff --git a/npm/win32-arm64/package.json b/npm/win32-arm64/package.json new file mode 100644 index 000000000..b7e2acb20 --- /dev/null +++ b/npm/win32-arm64/package.json @@ -0,0 +1,39 @@ +{ + "name": "@img/sharp-win32-arm64", + "version": "0.34.1", + "description": "Prebuilt sharp for use with Windows 64-bit ARM", + "author": "Lovell Fuller ", + "homepage": "https://sharp.pixelplumbing.com", + "repository": { + "type": "git", + "url": "git+https://github.com/lovell/sharp.git", + "directory": "npm/win32-arm64" + }, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "funding": { + "url": "https://opencollective.com/libvips" + }, + "preferUnplugged": true, + "files": [ + "lib", + "versions.json" + ], + "publishConfig": { + "access": "public" + }, + "type": "commonjs", + "exports": { + "./sharp.node": "./lib/sharp-win32-arm64.node", + "./package": "./package.json", + "./versions": "./versions.json" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "os": [ + "win32" + ], + "cpu": [ + "arm64" + ] +} diff --git a/package.json b/package.json index 6970f9ec1..85ade9909 100644 --- a/package.json +++ b/package.json @@ -160,6 +160,7 @@ "@img/sharp-linuxmusl-arm64": "0.34.1", "@img/sharp-linuxmusl-x64": "0.34.1", "@img/sharp-wasm32": "0.34.1", + "@img/sharp-win32-arm64": "0.34.1", "@img/sharp-win32-ia32": "0.34.1", "@img/sharp-win32-x64": "0.34.1" }, @@ -167,6 +168,7 @@ "@emnapi/runtime": "^1.4.0", "@img/sharp-libvips-dev": "1.1.0", "@img/sharp-libvips-dev-wasm32": "1.1.0", + "@img/sharp-libvips-win32-arm64": "1.1.0", "@img/sharp-libvips-win32-ia32": "1.1.0", "@img/sharp-libvips-win32-x64": "1.1.0", "@types/node": "*", diff --git a/test/unit/text.js b/test/unit/text.js index a81a88c93..0efe05bca 100644 --- a/test/unit/text.js +++ b/test/unit/text.js @@ -59,7 +59,7 @@ describe('Text to image', function () { assert.strictEqual('png', info.format); assert.strictEqual(3, info.channels); assert.ok(inRange(info.width, 400, 600), `Actual width ${info.width}`); - assert.ok(inRange(info.height, 300, 500), `Actual height ${info.height}`); + assert.ok(inRange(info.height, 290, 500), `Actual height ${info.height}`); assert.ok(inRange(info.textAutofitDpi, 900, 1300), `Actual textAutofitDpi ${info.textAutofitDpi}`); done(); }); From 0b5f131df8a632e57d891c7e7893e1bde10b3664 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Sun, 11 May 2025 09:44:15 +0200 Subject: [PATCH 002/115] Improve install error help text for ppc64le architecture (#4392) --- lib/libvips.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/libvips.js b/lib/libvips.js index 254361e3a..1bab0ca51 100644 --- a/lib/libvips.js +++ b/lib/libvips.js @@ -18,7 +18,7 @@ const minimumLibvipsVersion = semverCoerce(minimumLibvipsVersionLabelled).versio const prebuiltPlatforms = [ 'darwin-arm64', 'darwin-x64', - 'linux-arm', 'linux-arm64', 'linux-s390x', 'linux-x64', + 'linux-arm', 'linux-arm64', 'linux-ppc64', 'linux-s390x', 'linux-x64', 'linuxmusl-arm64', 'linuxmusl-x64', 'win32-arm64', 'win32-ia32', 'win32-x64' ]; From 7c7f960b60c63d5dc767d5e12b9ccd0c8d385081 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Tue, 13 May 2025 08:53:37 +0100 Subject: [PATCH 003/115] Ensure support for wide-char filenames on Windows #4391 --- docs/src/content/docs/changelog.md | 3 +++ src/pipeline.cc | 3 ++- test/unit/io.js | 17 +++++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/docs/src/content/docs/changelog.md b/docs/src/content/docs/changelog.md index 5026a6025..ef2f78b64 100644 --- a/docs/src/content/docs/changelog.md +++ b/docs/src/content/docs/changelog.md @@ -22,6 +22,9 @@ Requires libvips v8.16.1 [#4387](https://github.com/lovell/sharp/pull/4387) [@Stephen-X](https://github.com/Stephen-X) +* Ensure support for wide-character filenames on Windows (regression in 0.34.0). + [#4391](https://github.com/lovell/sharp/issues/4391) + ### v0.34.1 - 7th April 2025 * TypeScript: Ensure new `autoOrient` property is optional. diff --git a/src/pipeline.cc b/src/pipeline.cc index 21529acf1..bb12a4002 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -1359,7 +1359,8 @@ class PipelineWorker : public Napi::AsyncWorker { // Add file size to info if (baton->formatOut != "dz" || sharp::IsDzZip(baton->fileOut)) { try { - uint32_t const size = static_cast(std::filesystem::file_size(baton->fileOut)); + uint32_t const size = static_cast( + std::filesystem::file_size(std::filesystem::u8path(baton->fileOut))); info.Set("size", size); } catch (...) {} } diff --git a/test/unit/io.js b/test/unit/io.js index 98b96a571..038bfe1f8 100644 --- a/test/unit/io.js +++ b/test/unit/io.js @@ -1036,4 +1036,21 @@ describe('Input/output', function () { }); readable.pipe(inPipeline).pipe(badPipeline); }); + + it('supports wide-character filenames', async () => { + const filename = fixtures.path('output.图片.jpg'); + const create = { + width: 8, + height: 8, + channels: 3, + background: 'green' + }; + await sharp({ create }).toFile(filename); + + const { width, height, channels, format } = await sharp(filename).metadata(); + assert.strictEqual(width, 8); + assert.strictEqual(height, 8); + assert.strictEqual(channels, 3); + assert.strictEqual(format, 'jpeg'); + }); }); From 32872ef8403079e2d4449b2a3f465708ed32d1a6 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Tue, 13 May 2025 14:26:25 +0100 Subject: [PATCH 004/115] TypeScript: ensure metadata response matches reality #4383 --- docs/src/content/docs/changelog.md | 3 ++ lib/index.d.ts | 53 +++++++++++++++++++++++------- 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/docs/src/content/docs/changelog.md b/docs/src/content/docs/changelog.md index ef2f78b64..5e37a4959 100644 --- a/docs/src/content/docs/changelog.md +++ b/docs/src/content/docs/changelog.md @@ -18,6 +18,9 @@ Requires libvips v8.16.1 [#4375](https://github.com/lovell/sharp/pull/4375) [@hans00](https://github.com/hans00) +* TypeScript: Ensure `metadata` response more closely matches reality. + [#4383](https://github.com/lovell/sharp/issues/4383) + * TypeScript: Ensure `smartDeblock` property is included in WebP definition. [#4387](https://github.com/lovell/sharp/pull/4387) [@Stephen-X](https://github.com/Stephen-X) diff --git a/lib/index.d.ts b/lib/index.d.ts index c87e240e6..a8f1d98df 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1146,13 +1146,13 @@ declare namespace sharp { /** Number value of the EXIF Orientation header, if present */ orientation?: number | undefined; /** Name of decoder used to decompress image data e.g. jpeg, png, webp, gif, svg */ - format?: keyof FormatEnum | undefined; + format: keyof FormatEnum; /** Total size of image in bytes, for Stream and Buffer input only */ size?: number | undefined; /** Number of pixels wide (EXIF orientation is not taken into consideration) */ - width?: number | undefined; + width: number; /** Number of pixels high (EXIF orientation is not taken into consideration) */ - height?: number | undefined; + height: number; /** Any changed metadata after the image orientation is applied. */ autoOrient: { /** Number of pixels wide (EXIF orientation is taken into consideration) */ @@ -1161,19 +1161,19 @@ declare namespace sharp { height: number; }; /** Name of colour space interpretation */ - space?: keyof ColourspaceEnum | undefined; + space: keyof ColourspaceEnum; /** Number of bands e.g. 3 for sRGB, 4 for CMYK */ - channels?: Channels | undefined; + channels: Channels; /** Name of pixel depth format e.g. uchar, char, ushort, float ... */ - depth?: string | undefined; + depth: keyof DepthEnum; /** Number of pixels per inch (DPI), if present */ density?: number | undefined; /** String containing JPEG chroma subsampling, 4:2:0 or 4:4:4 for RGB, 4:2:0:4 or 4:4:4:4 for CMYK */ chromaSubsampling?: string | undefined; /** Boolean indicating whether the image is interlaced using a progressive scan */ - isProgressive?: boolean | undefined; + isProgressive: boolean; /** Boolean indicating whether the image is palette-based (GIF, PNG). */ - isPalette?: boolean | undefined; + isPalette: boolean; /** Number of bits per sample for each channel (GIF, PNG). */ bitsPerSample?: number | undefined; /** Number of pages/frames contained within the image, with support for TIFF, HEIF, PDF, animated GIF and animated WebP */ @@ -1187,9 +1187,9 @@ declare namespace sharp { /** Number of the primary page in a HEIF image */ pagePrimary?: number | undefined; /** Boolean indicating the presence of an embedded ICC profile */ - hasProfile?: boolean | undefined; + hasProfile: boolean; /** Boolean indicating the presence of an alpha transparency channel */ - hasAlpha?: boolean | undefined; + hasAlpha: boolean; /** Buffer containing raw EXIF data, if present */ exif?: Buffer | undefined; /** Buffer containing raw ICC profile data, if present */ @@ -1745,11 +1745,38 @@ declare namespace sharp { } interface ColourspaceEnum { - multiband: string; 'b-w': string; - bw: string; + cmc: string; cmyk: string; + fourier: string; + grey16: string; + histogram: string; + hsv: string; + lab: string; + labq: string; + labs: string; + lch: string; + matrix: string; + multiband: string; + rgb: string; + rgb16: string; + scrgb: string; srgb: string; + xyz: string; + yxy: string; + } + + interface DepthEnum { + char: string; + complex: string; + double: string; + dpcomplex: string; + float: string; + int: string; + short: string; + uchar: string; + uint: string; + ushort: string; } type FailOnOptions = 'none' | 'truncated' | 'error' | 'warning'; @@ -1818,6 +1845,7 @@ declare namespace sharp { interface FormatEnum { avif: AvailableFormatInfo; dz: AvailableFormatInfo; + exr: AvailableFormatInfo; fits: AvailableFormatInfo; gif: AvailableFormatInfo; heif: AvailableFormatInfo; @@ -1831,6 +1859,7 @@ declare namespace sharp { pdf: AvailableFormatInfo; png: AvailableFormatInfo; ppm: AvailableFormatInfo; + rad: AvailableFormatInfo; raw: AvailableFormatInfo; svg: AvailableFormatInfo; tiff: AvailableFormatInfo; From 94481a967ee9e4f925ee2acf078d36cc6464948f Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Tue, 13 May 2025 14:30:34 +0100 Subject: [PATCH 005/115] Ensure fit=contain resizing supports multiple alpha channels #4382 --- docs/src/content/docs/changelog.md | 3 +++ src/common.cc | 6 ++++-- test/unit/resize-contain.js | 29 +++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/docs/src/content/docs/changelog.md b/docs/src/content/docs/changelog.md index 5e37a4959..5d202f981 100644 --- a/docs/src/content/docs/changelog.md +++ b/docs/src/content/docs/changelog.md @@ -18,6 +18,9 @@ Requires libvips v8.16.1 [#4375](https://github.com/lovell/sharp/pull/4375) [@hans00](https://github.com/hans00) +* Ensure resizing with a `fit` of `contain` supports multiple alpha channels. + [#4382](https://github.com/lovell/sharp/issues/4382) + * TypeScript: Ensure `metadata` response more closely matches reality. [#4383](https://github.com/lovell/sharp/issues/4383) diff --git a/src/common.cc b/src/common.cc index 0f68be341..575b54e79 100644 --- a/src/common.cc +++ b/src/common.cc @@ -1001,9 +1001,11 @@ namespace sharp { 0.0722 * colour[2]) }; } - // Add alpha channel to alphaColour colour + // Add alpha channel(s) to alphaColour colour if (colour[3] < 255.0 || image.has_alpha()) { - alphaColour.push_back(colour[3] * multiplier); + do { + alphaColour.push_back(colour[3] * multiplier); + } while (alphaColour.size() < static_cast(image.bands())); } // Ensure alphaColour colour uses correct colourspace alphaColour = sharp::GetRgbaAsColourspace(alphaColour, image.interpretation(), premultiply); diff --git a/test/unit/resize-contain.js b/test/unit/resize-contain.js index 04c70df17..6e7f9ccc8 100644 --- a/test/unit/resize-contain.js +++ b/test/unit/resize-contain.js @@ -806,4 +806,33 @@ describe('Resize fit=contain', function () { fixtures.assertSimilar(fixtures.expected('./embedgravitybird/9-c.png'), data, done); }); }); + + it('multiple alpha channels', async () => { + const create = { + width: 20, + height: 12, + channels: 4, + background: 'green' + }; + const multipleAlphaChannels = await sharp({ create }) + .joinChannel({ create }) + .tiff({ compression: 'deflate' }) + .toBuffer(); + + const data = await sharp(multipleAlphaChannels) + .resize({ + width: 8, + height: 8, + fit: 'contain', + background: 'blue' + }) + .tiff({ compression: 'deflate' }) + .toBuffer(); + const { format, width, height, space, channels } = await sharp(data).metadata(); + assert.deepStrictEqual(format, 'tiff'); + assert.deepStrictEqual(width, 8); + assert.deepStrictEqual(height, 8); + assert.deepStrictEqual(space, 'srgb'); + assert.deepStrictEqual(channels, 8); + }); }); From 8e17c6f518316eea1f30361083b42800e1c874a3 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Tue, 13 May 2025 17:12:23 +0200 Subject: [PATCH 006/115] Prefer use of `vips_interpretation_max_alpha()` This also ensures we handle scRGB correctly, see: https://github.com/libvips/libvips/commit/e9c5a3155272b7328f5a0f1a21d0afcfbd1d7490 --- src/common.cc | 10 +--------- src/common.h | 6 ------ src/stats.cc | 2 +- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/src/common.cc b/src/common.cc index 575b54e79..b00483c50 100644 --- a/src/common.cc +++ b/src/common.cc @@ -951,14 +951,6 @@ namespace sharp { return interpretation == VIPS_INTERPRETATION_RGB16 || interpretation == VIPS_INTERPRETATION_GREY16; } - /* - Return the image alpha maximum. Useful for combining alpha bands. scRGB - images are 0 - 1 for image data, but the alpha is 0 - 255. - */ - double MaximumImageAlpha(VipsInterpretation const interpretation) { - return Is16Bit(interpretation) ? 65535.0 : 255.0; - } - /* Convert RGBA value to another colourspace */ @@ -1033,7 +1025,7 @@ namespace sharp { VImage EnsureAlpha(VImage image, double const value) { if (!image.has_alpha()) { std::vector alpha; - alpha.push_back(value * sharp::MaximumImageAlpha(image.interpretation())); + alpha.push_back(value * vips_interpretation_max_alpha(image.interpretation())); image = image.bandjoin_const(alpha); } return image; diff --git a/src/common.h b/src/common.h index bd942806f..1a61e47d6 100644 --- a/src/common.h +++ b/src/common.h @@ -357,12 +357,6 @@ namespace sharp { */ bool Is16Bit(VipsInterpretation const interpretation); - /* - Return the image alpha maximum. Useful for combining alpha bands. scRGB - images are 0 - 1 for image data, but the alpha is 0 - 255. - */ - double MaximumImageAlpha(VipsInterpretation const interpretation); - /* Convert RGBA value to another colourspace */ diff --git a/src/stats.cc b/src/stats.cc index 61df71a2f..bc9b243cc 100644 --- a/src/stats.cc +++ b/src/stats.cc @@ -60,7 +60,7 @@ class StatsWorker : public Napi::AsyncWorker { // Image is not opaque when alpha layer is present and contains a non-mamixa value if (image.has_alpha()) { double const minAlpha = static_cast(stats.getpoint(STAT_MIN_INDEX, bands).front()); - if (minAlpha != sharp::MaximumImageAlpha(image.interpretation())) { + if (minAlpha != vips_interpretation_max_alpha(image.interpretation())) { baton->isOpaque = false; } } From d36fd5064d3603597af9121c07c9cc0720fc7477 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Tue, 13 May 2025 17:17:36 +0200 Subject: [PATCH 007/115] Prefer use of `bandjoin_const()` and list-initialization --- src/common.cc | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/common.cc b/src/common.cc index b00483c50..55571ccd2 100644 --- a/src/common.cc +++ b/src/common.cc @@ -1003,8 +1003,7 @@ namespace sharp { alphaColour = sharp::GetRgbaAsColourspace(alphaColour, image.interpretation(), premultiply); // Add non-transparent alpha channel, if required if (colour[3] < 255.0 && !image.has_alpha()) { - image = image.bandjoin( - VImage::new_matrix(image.width(), image.height()).new_from_image(255 * multiplier).cast(image.format())); + image = image.bandjoin_const({ 255 * multiplier }); } return std::make_tuple(image, alphaColour); } @@ -1024,9 +1023,7 @@ namespace sharp { */ VImage EnsureAlpha(VImage image, double const value) { if (!image.has_alpha()) { - std::vector alpha; - alpha.push_back(value * vips_interpretation_max_alpha(image.interpretation())); - image = image.bandjoin_const(alpha); + image = image.bandjoin_const({ value * vips_interpretation_max_alpha(image.interpretation()) }); } return image; } From db3a4528eb65fe2358a6334a3536aca73c3df5de Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Tue, 13 May 2025 17:19:02 +0200 Subject: [PATCH 008/115] Simplify 94481a9 --- src/common.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/common.cc b/src/common.cc index 55571ccd2..abbfe705e 100644 --- a/src/common.cc +++ b/src/common.cc @@ -995,9 +995,8 @@ namespace sharp { } // Add alpha channel(s) to alphaColour colour if (colour[3] < 255.0 || image.has_alpha()) { - do { - alphaColour.push_back(colour[3] * multiplier); - } while (alphaColour.size() < static_cast(image.bands())); + int extraBands = image.bands() > 4 ? image.bands() - 3 : 1; + alphaColour.insert(alphaColour.end(), extraBands, colour[3] * multiplier); } // Ensure alphaColour colour uses correct colourspace alphaColour = sharp::GetRgbaAsColourspace(alphaColour, image.interpretation(), premultiply); From 00e66efbeec365f260da7abf6fe49ba9ad030198 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Wed, 14 May 2025 12:24:23 +0100 Subject: [PATCH 009/115] Bump deps --- npm/wasm32/package.json | 2 +- package.json | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/npm/wasm32/package.json b/npm/wasm32/package.json index 0bc0d4eb4..dc031d0c7 100644 --- a/npm/wasm32/package.json +++ b/npm/wasm32/package.json @@ -31,7 +31,7 @@ "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "dependencies": { - "@emnapi/runtime": "^1.4.0" + "@emnapi/runtime": "^1.4.3" }, "cpu": [ "wasm32" diff --git a/package.json b/package.json index 85ade9909..7741652f0 100644 --- a/package.json +++ b/package.json @@ -138,8 +138,8 @@ ], "dependencies": { "color": "^4.2.3", - "detect-libc": "^2.0.3", - "semver": "^7.7.1" + "detect-libc": "^2.0.4", + "semver": "^7.7.2" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.1", @@ -165,7 +165,7 @@ "@img/sharp-win32-x64": "0.34.1" }, "devDependencies": { - "@emnapi/runtime": "^1.4.0", + "@emnapi/runtime": "^1.4.3", "@img/sharp-libvips-dev": "1.1.0", "@img/sharp-libvips-dev-wasm32": "1.1.0", "@img/sharp-libvips-win32-arm64": "1.1.0", @@ -173,19 +173,19 @@ "@img/sharp-libvips-win32-x64": "1.1.0", "@types/node": "*", "cc": "^3.0.1", - "emnapi": "^1.4.0", + "emnapi": "^1.4.3", "exif-reader": "^2.0.2", "extract-zip": "^2.0.1", "icc": "^3.0.0", "jsdoc-to-markdown": "^9.1.1", "license-checker": "^25.0.1", - "mocha": "^11.1.0", + "mocha": "^11.2.2", "node-addon-api": "^8.3.1", "nyc": "^17.1.0", "prebuild": "^13.0.1", "semistandard": "^17.0.0", "tar-fs": "^3.0.8", - "tsd": "^0.31.2" + "tsd": "^0.32.0" }, "license": "Apache-2.0", "engines": { From 956d72ddc009a477bbb172b25fed006223341df9 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Wed, 14 May 2025 12:35:49 +0100 Subject: [PATCH 010/115] Prerelease v0.34.2-rc.0 --- npm/darwin-arm64/package.json | 2 +- npm/darwin-x64/package.json | 2 +- npm/linux-arm/package.json | 2 +- npm/linux-arm64/package.json | 2 +- npm/linux-ppc64/package.json | 2 +- npm/linux-s390x/package.json | 2 +- npm/linux-x64/package.json | 2 +- npm/linuxmusl-arm64/package.json | 2 +- npm/linuxmusl-x64/package.json | 2 +- npm/package.json | 2 +- npm/wasm32/package.json | 2 +- npm/win32-arm64/package.json | 2 +- npm/win32-ia32/package.json | 2 +- npm/win32-x64/package.json | 2 +- package.json | 26 +++++++++++++------------- 15 files changed, 27 insertions(+), 27 deletions(-) diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index 69e1c310b..28fb7e988 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-arm64", - "version": "0.34.1", + "version": "0.34.2-rc.0", "description": "Prebuilt sharp for use with macOS 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index ff6285950..e9210a3ba 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-x64", - "version": "0.34.1", + "version": "0.34.2-rc.0", "description": "Prebuilt sharp for use with macOS x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm/package.json b/npm/linux-arm/package.json index d8565b565..3e1c01380 100644 --- a/npm/linux-arm/package.json +++ b/npm/linux-arm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm", - "version": "0.34.1", + "version": "0.34.2-rc.0", "description": "Prebuilt sharp for use with Linux (glibc) ARM (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm64/package.json b/npm/linux-arm64/package.json index 3264e375b..03543c03a 100644 --- a/npm/linux-arm64/package.json +++ b/npm/linux-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm64", - "version": "0.34.1", + "version": "0.34.2-rc.0", "description": "Prebuilt sharp for use with Linux (glibc) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-ppc64/package.json b/npm/linux-ppc64/package.json index f74d5a39c..71370b5ca 100644 --- a/npm/linux-ppc64/package.json +++ b/npm/linux-ppc64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-ppc64", - "version": "0.34.1", + "version": "0.34.2-rc.0", "description": "Prebuilt sharp for use with Linux (glibc) ppc64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-s390x/package.json b/npm/linux-s390x/package.json index 98af5a923..8863303f3 100644 --- a/npm/linux-s390x/package.json +++ b/npm/linux-s390x/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-s390x", - "version": "0.34.1", + "version": "0.34.2-rc.0", "description": "Prebuilt sharp for use with Linux (glibc) s390x", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-x64/package.json b/npm/linux-x64/package.json index e5ce63c70..ff375a8df 100644 --- a/npm/linux-x64/package.json +++ b/npm/linux-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-x64", - "version": "0.34.1", + "version": "0.34.2-rc.0", "description": "Prebuilt sharp for use with Linux (glibc) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-arm64/package.json b/npm/linuxmusl-arm64/package.json index 9e3a86f6e..8b35fc7ad 100644 --- a/npm/linuxmusl-arm64/package.json +++ b/npm/linuxmusl-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-arm64", - "version": "0.34.1", + "version": "0.34.2-rc.0", "description": "Prebuilt sharp for use with Linux (musl) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-x64/package.json b/npm/linuxmusl-x64/package.json index 8c253f578..7a08a0ccf 100644 --- a/npm/linuxmusl-x64/package.json +++ b/npm/linuxmusl-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-x64", - "version": "0.34.1", + "version": "0.34.2-rc.0", "description": "Prebuilt sharp for use with Linux (musl) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/package.json b/npm/package.json index 5c15b996b..e1403403a 100644 --- a/npm/package.json +++ b/npm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp", - "version": "0.34.1", + "version": "0.34.2-rc.0", "private": "true", "workspaces": [ "darwin-arm64", diff --git a/npm/wasm32/package.json b/npm/wasm32/package.json index dc031d0c7..416dae28b 100644 --- a/npm/wasm32/package.json +++ b/npm/wasm32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-wasm32", - "version": "0.34.1", + "version": "0.34.2-rc.0", "description": "Prebuilt sharp for use with wasm32", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-arm64/package.json b/npm/win32-arm64/package.json index b7e2acb20..28a8ef70a 100644 --- a/npm/win32-arm64/package.json +++ b/npm/win32-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-arm64", - "version": "0.34.1", + "version": "0.34.2-rc.0", "description": "Prebuilt sharp for use with Windows 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-ia32/package.json b/npm/win32-ia32/package.json index 641d90fa2..4c119908c 100644 --- a/npm/win32-ia32/package.json +++ b/npm/win32-ia32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-ia32", - "version": "0.34.1", + "version": "0.34.2-rc.0", "description": "Prebuilt sharp for use with Windows x86 (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-x64/package.json b/npm/win32-x64/package.json index 2de9d2e13..e29dd2eb8 100644 --- a/npm/win32-x64/package.json +++ b/npm/win32-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-x64", - "version": "0.34.1", + "version": "0.34.2-rc.0", "description": "Prebuilt sharp for use with Windows x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/package.json b/package.json index 7741652f0..beae84522 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "sharp", "description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images", - "version": "0.34.1", + "version": "0.34.2-rc.0", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", "contributors": [ @@ -142,8 +142,8 @@ "semver": "^7.7.2" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.1", - "@img/sharp-darwin-x64": "0.34.1", + "@img/sharp-darwin-arm64": "0.34.2-rc.0", + "@img/sharp-darwin-x64": "0.34.2-rc.0", "@img/sharp-libvips-darwin-arm64": "1.1.0", "@img/sharp-libvips-darwin-x64": "1.1.0", "@img/sharp-libvips-linux-arm": "1.1.0", @@ -153,16 +153,16 @@ "@img/sharp-libvips-linux-x64": "1.1.0", "@img/sharp-libvips-linuxmusl-arm64": "1.1.0", "@img/sharp-libvips-linuxmusl-x64": "1.1.0", - "@img/sharp-linux-arm": "0.34.1", - "@img/sharp-linux-arm64": "0.34.1", - "@img/sharp-linux-s390x": "0.34.1", - "@img/sharp-linux-x64": "0.34.1", - "@img/sharp-linuxmusl-arm64": "0.34.1", - "@img/sharp-linuxmusl-x64": "0.34.1", - "@img/sharp-wasm32": "0.34.1", - "@img/sharp-win32-arm64": "0.34.1", - "@img/sharp-win32-ia32": "0.34.1", - "@img/sharp-win32-x64": "0.34.1" + "@img/sharp-linux-arm": "0.34.2-rc.0", + "@img/sharp-linux-arm64": "0.34.2-rc.0", + "@img/sharp-linux-s390x": "0.34.2-rc.0", + "@img/sharp-linux-x64": "0.34.2-rc.0", + "@img/sharp-linuxmusl-arm64": "0.34.2-rc.0", + "@img/sharp-linuxmusl-x64": "0.34.2-rc.0", + "@img/sharp-wasm32": "0.34.2-rc.0", + "@img/sharp-win32-arm64": "0.34.2-rc.0", + "@img/sharp-win32-ia32": "0.34.2-rc.0", + "@img/sharp-win32-x64": "0.34.2-rc.0" }, "devDependencies": { "@emnapi/runtime": "^1.4.3", From e75ae970ed6122a68b971148ceb3a95121978bc4 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Fri, 16 May 2025 14:38:00 +0100 Subject: [PATCH 011/115] Ensure PDF scale-on-load optimisation uses background #4398 --- docs/src/content/docs/changelog.md | 1 + src/pipeline.cc | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/src/content/docs/changelog.md b/docs/src/content/docs/changelog.md index 5d202f981..1cec81bcf 100644 --- a/docs/src/content/docs/changelog.md +++ b/docs/src/content/docs/changelog.md @@ -13,6 +13,7 @@ Requires libvips v8.16.1 * Ensure `pdfBackground` constructor property is used. [#4207](https://github.com/lovell/sharp/pull/4207) + [#4398](https://github.com/lovell/sharp/issues/4398) * Add support for prebuilt Windows ARM64 binaries. [#4375](https://github.com/lovell/sharp/pull/4375) diff --git a/src/pipeline.cc b/src/pipeline.cc index bb12a4002..7acbd967a 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -294,6 +294,7 @@ class PipelineWorker : public Napi::AsyncWorker { option->set("n", baton->input->pages); option->set("page", baton->input->page); option->set("dpi", baton->input->density); + option->set("background", baton->input->pdfBackground); if (baton->input->buffer != nullptr) { // Reload PDF buffer From c4d6aec48c55227b28425d8f7e46ff1373861ba9 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Mon, 19 May 2025 22:04:08 +0100 Subject: [PATCH 012/115] Docs: Highlight that Windows ARM64 support is experimental --- docs/src/content/docs/api-output.md | 3 +++ docs/src/content/docs/changelog.md | 2 +- docs/src/content/docs/install.md | 2 +- lib/output.js | 3 +++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/src/content/docs/api-output.md b/docs/src/content/docs/api-output.md index 945da137f..9cca1d554 100644 --- a/docs/src/content/docs/api-output.md +++ b/docs/src/content/docs/api-output.md @@ -626,6 +626,9 @@ Use these AVIF options for output image. AVIF image sequences are not supported. Prebuilt binaries support a bitdepth of 8 only. +This feature is experimental on the Windows ARM64 platform +and requires a CPU with ARM64v8.4 or later. + **Throws**: diff --git a/docs/src/content/docs/changelog.md b/docs/src/content/docs/changelog.md index 1cec81bcf..e45414060 100644 --- a/docs/src/content/docs/changelog.md +++ b/docs/src/content/docs/changelog.md @@ -15,7 +15,7 @@ Requires libvips v8.16.1 [#4207](https://github.com/lovell/sharp/pull/4207) [#4398](https://github.com/lovell/sharp/issues/4398) -* Add support for prebuilt Windows ARM64 binaries. +* Add experimental support for prebuilt Windows ARM64 binaries. [#4375](https://github.com/lovell/sharp/pull/4375) [@hans00](https://github.com/hans00) diff --git a/docs/src/content/docs/install.md b/docs/src/content/docs/install.md index 3e0a4a014..de8d6df14 100644 --- a/docs/src/content/docs/install.md +++ b/docs/src/content/docs/install.md @@ -53,7 +53,7 @@ Ready-compiled sharp and libvips binaries are provided for use on the most commo * Linux x64 (glibc >= 2.26, musl >= 1.2.2, CPU with SSE4.2) * Windows x64 * Windows x86 -* Windows ARM64 +* Windows ARM64 (experimental, CPU with ARMv8.4 required for all features) This provides support for the JPEG, PNG, WebP, AVIF (limited to 8-bit depth), TIFF, GIF and SVG (input) image formats. diff --git a/lib/output.js b/lib/output.js index 5c2bdf295..08d596ade 100644 --- a/lib/output.js +++ b/lib/output.js @@ -1019,6 +1019,9 @@ function tiff (options) { * AVIF image sequences are not supported. * Prebuilt binaries support a bitdepth of 8 only. * + * This feature is experimental on the Windows ARM64 platform + * and requires a CPU with ARM64v8.4 or later. + * * @example * const data = await sharp(input) * .avif({ effort: 2 }) From 63b0a11b5b1c98167f65e96557c735349f920f1b Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Mon, 19 May 2025 23:21:55 +0100 Subject: [PATCH 013/115] Tests: remove a possible race condition --- package.json | 2 +- test/unit/util.js | 24 +++++++++++++----------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index beae84522..d5be67117 100644 --- a/package.json +++ b/package.json @@ -179,7 +179,7 @@ "icc": "^3.0.0", "jsdoc-to-markdown": "^9.1.1", "license-checker": "^25.0.1", - "mocha": "^11.2.2", + "mocha": "^11.4.0", "node-addon-api": "^8.3.1", "nyc": "^17.1.0", "prebuild": "^13.0.1", diff --git a/test/unit/util.js b/test/unit/util.js index 9d5b9c620..ecec8a06a 100644 --- a/test/unit/util.js +++ b/test/unit/util.js @@ -10,18 +10,20 @@ const sharp = require('../../'); describe('Utilities', function () { describe('Cache', function () { it('Can be disabled', function (done) { - queueMicrotask(() => { - sharp.cache(false); + const check = setInterval(() => { const cache = sharp.cache(false); - assert.strictEqual(cache.memory.current, 0); - assert.strictEqual(cache.memory.max, 0); - assert.strictEqual(typeof cache.memory.high, 'number'); - assert.strictEqual(cache.files.current, 0); - assert.strictEqual(cache.files.max, 0); - assert.strictEqual(cache.items.current, 0); - assert.strictEqual(cache.items.max, 0); - done(); - }); + const empty = + cache.memory.current + + cache.memory.max + + cache.files.current + + cache.files.max + + cache.items.current + + cache.items.max === 0; + if (empty) { + clearInterval(check); + done(); + } + }, 2000); }); it('Can be enabled with defaults', function () { const cache = sharp.cache(true); From 7f03502003033760106200ef1a28c7f9f2a31806 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Tue, 20 May 2025 12:57:28 +0100 Subject: [PATCH 014/115] Docs: upgrade to latest Astro Starlight --- docs/astro.config.mjs | 8 ++++---- docs/package.json | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index 5c7209359..87ffdab2b 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -70,10 +70,10 @@ export default defineConfig({ { label: 'Performance', slug: 'performance' }, { label: 'Changelog', slug: 'changelog' } ], - social: { - openCollective: 'https://opencollective.com/libvips', - github: 'https://github.com/lovell/sharp' - } + social: [ + { icon: 'openCollective', label: 'Open Collective', href: 'https://opencollective.com/libvips' }, + { icon: 'github', label: 'GitHub', href: 'https://github.com/lovell/sharp' } + ] }) ] }); diff --git a/docs/package.json b/docs/package.json index 36bfd5b4b..cfb0f6520 100644 --- a/docs/package.json +++ b/docs/package.json @@ -11,7 +11,7 @@ "astro": "astro" }, "dependencies": { - "@astrojs/starlight": "^0.32.3", - "astro": "^5.5.3" + "@astrojs/starlight": "^0.34.3", + "astro": "^5.7.13" } } From d4b30b73924322fc67ef50238221386e3f2e53db Mon Sep 17 00:00:00 2001 From: Harshal Bhakta Date: Fri, 16 May 2025 10:48:31 +0530 Subject: [PATCH 015/115] Docs: Update pnpm settings documentation URLs --- docs/src/content/docs/install.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/src/content/docs/install.md b/docs/src/content/docs/install.md index de8d6df14..69d1c1064 100644 --- a/docs/src/content/docs/install.md +++ b/docs/src/content/docs/install.md @@ -21,7 +21,7 @@ pnpm add sharp ``` When using `pnpm`, you may need to add `sharp` to -[ignoredBuiltDependencies](https://pnpm.io/package_json#pnpmignoredbuiltdependencies) +[ignoredBuiltDependencies](https://pnpm.io/settings#ignoredbuiltdependencies) to silence warnings. ```sh @@ -94,7 +94,7 @@ Use the [supportedArchitectures](https://yarnpkg.com/configuration/yarnrc#suppor ### pnpm v8+ -Use the [supportedArchitectures](https://pnpm.io/package_json#pnpmsupportedarchitectures) configuration. +Use the [supportedArchitectures](https://pnpm.io/settings#supportedarchitectures) configuration. ## Custom libvips @@ -134,7 +134,7 @@ npm install --save node-addon-api node-gyp ``` When using `pnpm`, you may need to add `sharp` to -[onlyBuiltDependencies](https://pnpm.io/package_json#pnpmonlybuiltdependencies) +[onlyBuiltDependencies](https://pnpm.io/settings#onlybuiltdependencies) to ensure the installation script can be run. For cross-compiling, the `--platform`, `--arch` and `--libc` npm flags From 6d04b7c1fa813e3bbacee831e81c60bd138da597 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Tue, 20 May 2025 14:36:42 +0100 Subject: [PATCH 016/115] Release v0.34.2 --- docs/src/content/docs/changelog.md | 2 +- npm/darwin-arm64/package.json | 2 +- npm/darwin-x64/package.json | 2 +- npm/linux-arm/package.json | 2 +- npm/linux-arm64/package.json | 2 +- npm/linux-ppc64/package.json | 2 +- npm/linux-s390x/package.json | 2 +- npm/linux-x64/package.json | 2 +- npm/linuxmusl-arm64/package.json | 2 +- npm/linuxmusl-x64/package.json | 2 +- npm/package.json | 2 +- npm/wasm32/package.json | 2 +- npm/win32-arm64/package.json | 2 +- npm/win32-ia32/package.json | 2 +- npm/win32-x64/package.json | 2 +- package.json | 26 +++++++++++++------------- 16 files changed, 28 insertions(+), 28 deletions(-) diff --git a/docs/src/content/docs/changelog.md b/docs/src/content/docs/changelog.md index e45414060..b9cbc7b6e 100644 --- a/docs/src/content/docs/changelog.md +++ b/docs/src/content/docs/changelog.md @@ -6,7 +6,7 @@ title: Changelog Requires libvips v8.16.1 -### v0.34.2 - TBD +### v0.34.2 - 20th May 2025 * Ensure animated GIF to WebP conversion retains loop (regression in 0.34.0). [#3394](https://github.com/lovell/sharp/issues/3394) diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index 28fb7e988..0132543e6 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-arm64", - "version": "0.34.2-rc.0", + "version": "0.34.2", "description": "Prebuilt sharp for use with macOS 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index e9210a3ba..0161956a4 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-x64", - "version": "0.34.2-rc.0", + "version": "0.34.2", "description": "Prebuilt sharp for use with macOS x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm/package.json b/npm/linux-arm/package.json index 3e1c01380..f03525108 100644 --- a/npm/linux-arm/package.json +++ b/npm/linux-arm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm", - "version": "0.34.2-rc.0", + "version": "0.34.2", "description": "Prebuilt sharp for use with Linux (glibc) ARM (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm64/package.json b/npm/linux-arm64/package.json index 03543c03a..9142b138b 100644 --- a/npm/linux-arm64/package.json +++ b/npm/linux-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm64", - "version": "0.34.2-rc.0", + "version": "0.34.2", "description": "Prebuilt sharp for use with Linux (glibc) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-ppc64/package.json b/npm/linux-ppc64/package.json index 71370b5ca..72fd443c9 100644 --- a/npm/linux-ppc64/package.json +++ b/npm/linux-ppc64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-ppc64", - "version": "0.34.2-rc.0", + "version": "0.34.2", "description": "Prebuilt sharp for use with Linux (glibc) ppc64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-s390x/package.json b/npm/linux-s390x/package.json index 8863303f3..d4a889371 100644 --- a/npm/linux-s390x/package.json +++ b/npm/linux-s390x/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-s390x", - "version": "0.34.2-rc.0", + "version": "0.34.2", "description": "Prebuilt sharp for use with Linux (glibc) s390x", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-x64/package.json b/npm/linux-x64/package.json index ff375a8df..768a0f2fa 100644 --- a/npm/linux-x64/package.json +++ b/npm/linux-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-x64", - "version": "0.34.2-rc.0", + "version": "0.34.2", "description": "Prebuilt sharp for use with Linux (glibc) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-arm64/package.json b/npm/linuxmusl-arm64/package.json index 8b35fc7ad..55ca0cf76 100644 --- a/npm/linuxmusl-arm64/package.json +++ b/npm/linuxmusl-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-arm64", - "version": "0.34.2-rc.0", + "version": "0.34.2", "description": "Prebuilt sharp for use with Linux (musl) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-x64/package.json b/npm/linuxmusl-x64/package.json index 7a08a0ccf..9f591441a 100644 --- a/npm/linuxmusl-x64/package.json +++ b/npm/linuxmusl-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-x64", - "version": "0.34.2-rc.0", + "version": "0.34.2", "description": "Prebuilt sharp for use with Linux (musl) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/package.json b/npm/package.json index e1403403a..fde3bf4ed 100644 --- a/npm/package.json +++ b/npm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp", - "version": "0.34.2-rc.0", + "version": "0.34.2", "private": "true", "workspaces": [ "darwin-arm64", diff --git a/npm/wasm32/package.json b/npm/wasm32/package.json index 416dae28b..9ad9d08f5 100644 --- a/npm/wasm32/package.json +++ b/npm/wasm32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-wasm32", - "version": "0.34.2-rc.0", + "version": "0.34.2", "description": "Prebuilt sharp for use with wasm32", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-arm64/package.json b/npm/win32-arm64/package.json index 28a8ef70a..cc46b899d 100644 --- a/npm/win32-arm64/package.json +++ b/npm/win32-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-arm64", - "version": "0.34.2-rc.0", + "version": "0.34.2", "description": "Prebuilt sharp for use with Windows 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-ia32/package.json b/npm/win32-ia32/package.json index 4c119908c..2fa8c41a1 100644 --- a/npm/win32-ia32/package.json +++ b/npm/win32-ia32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-ia32", - "version": "0.34.2-rc.0", + "version": "0.34.2", "description": "Prebuilt sharp for use with Windows x86 (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-x64/package.json b/npm/win32-x64/package.json index e29dd2eb8..99f54be02 100644 --- a/npm/win32-x64/package.json +++ b/npm/win32-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-x64", - "version": "0.34.2-rc.0", + "version": "0.34.2", "description": "Prebuilt sharp for use with Windows x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/package.json b/package.json index d5be67117..51a7069a4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "sharp", "description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images", - "version": "0.34.2-rc.0", + "version": "0.34.2", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", "contributors": [ @@ -142,8 +142,8 @@ "semver": "^7.7.2" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.2-rc.0", - "@img/sharp-darwin-x64": "0.34.2-rc.0", + "@img/sharp-darwin-arm64": "0.34.2", + "@img/sharp-darwin-x64": "0.34.2", "@img/sharp-libvips-darwin-arm64": "1.1.0", "@img/sharp-libvips-darwin-x64": "1.1.0", "@img/sharp-libvips-linux-arm": "1.1.0", @@ -153,16 +153,16 @@ "@img/sharp-libvips-linux-x64": "1.1.0", "@img/sharp-libvips-linuxmusl-arm64": "1.1.0", "@img/sharp-libvips-linuxmusl-x64": "1.1.0", - "@img/sharp-linux-arm": "0.34.2-rc.0", - "@img/sharp-linux-arm64": "0.34.2-rc.0", - "@img/sharp-linux-s390x": "0.34.2-rc.0", - "@img/sharp-linux-x64": "0.34.2-rc.0", - "@img/sharp-linuxmusl-arm64": "0.34.2-rc.0", - "@img/sharp-linuxmusl-x64": "0.34.2-rc.0", - "@img/sharp-wasm32": "0.34.2-rc.0", - "@img/sharp-win32-arm64": "0.34.2-rc.0", - "@img/sharp-win32-ia32": "0.34.2-rc.0", - "@img/sharp-win32-x64": "0.34.2-rc.0" + "@img/sharp-linux-arm": "0.34.2", + "@img/sharp-linux-arm64": "0.34.2", + "@img/sharp-linux-s390x": "0.34.2", + "@img/sharp-linux-x64": "0.34.2", + "@img/sharp-linuxmusl-arm64": "0.34.2", + "@img/sharp-linuxmusl-x64": "0.34.2", + "@img/sharp-wasm32": "0.34.2", + "@img/sharp-win32-arm64": "0.34.2", + "@img/sharp-win32-ia32": "0.34.2", + "@img/sharp-win32-x64": "0.34.2" }, "devDependencies": { "@emnapi/runtime": "^1.4.3", From 91f1b58f319689f9def4c7b39ca35ed0af438d9d Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Mon, 9 Jun 2025 00:31:07 +0200 Subject: [PATCH 017/115] Tests: Regenerate expected fixtures ahead of libvips v8.17.0 (#4402) --- test/fixtures/expected/extract.tiff | Bin 10846 -> 15398 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/test/fixtures/expected/extract.tiff b/test/fixtures/expected/extract.tiff index 74c2cac3f30c017de810c8302c4c76d632fbdf4d..e02db48b28e1e88fab722b266326edd4d095993b 100644 GIT binary patch literal 15398 zcmeHucU)6j*60bL_ue6t(3^Awq^Lj;0a1EYnzYcXRO!7bpduZlgY+uB2!a&pAP|tM zKmv+Uk-T`{z4KV!F3Mb013tshyqNO4*Kzz|Tz4Cnwu1`k4U(OdI4=sLg+bD-6g>uRf?YRSPJ!;LDPdAZPSpO;*LlA?(Ehhf%6* z%$Xk2cVD5FkmZO9O?H?)f!tTye!I8FX_dR!<_N%t?+lZ@)^s#l-pwZu?dcMmI`cqu z1iSTrX7?%X7Am@}i5o^X^|HIKpF25{Qk5h89`SK461H+mJ_xpoAIpY(Rb)?S)eK=4GHu>fds$4SAHf89Bm}GYXGBa+YXVR?_+O zg(O(AvDMHC`1nuc|2-@IEdB>rXHXc=57ZcKK*AIiP~dA?5bDK%Rh<(z4;I=dZy&px zFoqB~j;2?px(ihlhACbi9$Mu_>-pR*4l>Ra!T{v3B(j*e1M9T4dznIP(}{WFsic$? zI`u(^U9*l}cw1GnhF)ry8h7i}gmsvp>P)1??y9(yY7D-UmZsy*0i?HZCELtla8i`a3MT}6{cOwU9>J^S|78EzxJlK{1r)us^>!#6y zmv?K75IZSnKNcQ%L}vMARj1d(jq4$H;huCe=iKh2>DA%x&K3V`M*oUy@srfm8q^A+ z<1hfvG6M2_5CeS7Z~)Ib6vhMmzru-C>>6oki?k6+IkL$tj~xA4?yASCnbLymX?=ak z=|(`|2p61R*r^(%x{(sma?=#u zY2}~NL=49U4lTpQ@>&Ucpgi}iNaHdE_}KhbH|m0&7T zys+!97*5C$frT*De6oMokAGGOe~ka5g7`xie}h`)*>iU15ZpQ4*e>eE`d;a&2RD$# z^CWCJeM&v!`0iM@BjUlNyOP22@}fgNxe%gu01g>8WNdMJ?)=wtMHd}Rq1DHI-q zTV{=a26{MScmomMblI2RJu=;Jyf93wO z7&*^6k9Ki|j`*TAFn~wscOFyVlj-j@uexy9(c zN?@3@m@1dB+LRyM*S*n%7J_2{F(pZKurtLss?|Ml;k>7#+-|pJLSOM%21oQOaZR1+ zm1vav2kJG?2-*p6WV}RD~ z^Ym)qUNx6nHj;#f4~Z<$p7ih`BygM&w^bmh)U^OEcHb^^}1tMYAdEx*qxC(8-AzT6}gNk*9AiuNe$=oqx zX>$(qMe7VOG`1hln4OR#Rkhq9pMtUrsT+GvYhmex0f^S)F+hJh*LWx*q1@JQwd9JX z(=gwdEdj@aH^q5eVufdlC=Bp}Te`uB$~A?N1yPZAH-B*Ja(mu@E7MJb=Q?CQ2HV|K zU5psO)v0zPl*p+?i4FDCJ$AFRIr#b813NpdhrO%a99GX{35Y9I*fZ1uj3T-OG#TPp zde^9LH%}>A?YJ~wi224|#6o|(O5n07w;X*@BuvR#FWB&paqmCHxnG44oQIl^lnQ0_ zcip^-!t2g)6dOx!rB>x2a7k-HJ|EdBzzrvaLM~WQ`WLMq%w%?nF|2YUS>B4JZSZA{ zcf6Utyv8$nJPjW;d~<5PaYHTk|Uf@ z4hy)qQ zv|d>=wcI9rRA#v3k@J?uQ{dCrKVXk)A=nJS{CaiEStoh|@u^DrgGONSKz)c8f6|Mv zMGPRE5deHP6%zUb2Fc-Xj>13drhoLy{;)y)ZKwYacg2W7WztW&6izLcd}w7Kc;UV_ zaY8lCOFg^t02kt#mHRYwq#e*SO{&I$FztZBUkU;ybVo(cP46E!#o)Rm!!mx`N00-Tz zff|lJ_|#3Y5-^v3R+DreN)5R;PpQZ8mp3vCBwfG z(EM-D{FmULUGtwJynpx2{`UO8|At5BecrRNyo}$_l{tU!-tauOytU&_VwD5zwFHs% z9AN0Yi>m0Lk(M z`$os6k6=GXxCGHV)_J0G$M%%CGik5FS7lo8O)CmTFH+iZ0IK3hS>&S}1u{o3b@nwPM;n;WzlZw1_+053fxjxCs;M?$?>o z6`-!Y`o{MmMBxqmq}%~=Y3HF*V71iF0cBne7=F`UWdO0s2oWD^mp;uvc_B(>zz@%SS~nGY7In@tD9k4$>G2ZjMr{z>7-E&>l6G`}FOZDYYwVvauh9itgUqFNfqt zx`l7PGJ+Sv9-Fb=i3r1Axq+)BHw6!Y2FY>5+80G;#GT|Xp~tjI*NHeXjLRLq;i!<( zJtCzsuZ=l#gf3B`x=I{RFI~C*xY3Hv+SG5b=}9-w>u82eG>^YG*{zkMVaaclljpR7=V@`SwxAG@9-l@ ztdTZ~x%5U!SaUm7qMM!X!kFI$b&ydFfYp&3ope&UkXbvV#mSMGgZ5k!)c3H=`;(no z)YEikV@-X>^+BHUlOKuBC2WMu_76ZOM z%O*`*(ZDq;eNoTRuv|(Y%nFSaf5khNpSILq!4DqoR4WhdW7rf@W?HuVUfP?>{q0gs zAy<~S%*k_uh#RY#s#Gdz7xD0AWM8}Ew+yuMPP%24YP=15MY5kCmJ4phIoz3D|S4B)R}GjasULEKktqfmD6UO|OdDYShm*ekp{s zwOXY+SV|a|@j-=7nzFc`j35<9){kh-(e%gLR?pi>y2)7{n=DqJZkVb0sn;TqBzC<3inQ5O+uUDBF^&})xfITFT=qgG7V zeJT}%?%1jhtFT#HtM_OqJC>WG0|%bCHWc-D^yZ2kZ>5_#OUC*TC0aABrH(dK3bH-} z7gDRH#r?@t@V_I3SV6?bRKw9lD4j@`uBlUn1^f8pp^ul-n@Yy6vtKkYr*u~*+!QqN zl(f9FNp^Y17-nxD zaD|`=1PqL}YJJNP*AgME1!8Ld} zq5`_>$rJ1$C6>UPk=4J<*t9*HDpP6a$j#H76H=ccIUy&)$_pDYeGsH za^^cMrG$3|2H2E3D^bGoGq;_~(uoetaEK_+T0y4Ji%egNMpm}e1)ZjYw6h1#8IjUS zjpsD8ccS;TjSP}D<5x8;(v6y01W6w|Sj^;vnM23MJe%UY-~@?huF{O0(@I?E*ChJQ znQ}MO@*Som$Z9?;Cyh`mCIZ%DierLOP6T&KRjd4UH|ZlP(A&q$H(F8jkG@{BQl*M# zVJVQ*X)gb)@o?0)Ao#dr_>3b>g}t}9*9Tr=(pzR3+dD3>DkEGMdJPG%@j9gwHdQ%V9m2TgWJ({G z?_Xr_wh(>q)7>{AeIK$stAzVjUdcxi#XjN|(#3Ho!^C~2}?<>V1oAuH> zqS*h9NY<6KYR+8u4cOWZ^_|ZJtPKL3=65}9+rEbUf$SXMz$}x4IADIGIR)oxcvF4r zRW#!;v3#yBG+h(=4h!kd3>%?Q$_Q~J{O~buxBW~OgS^iIJPGc@^p-Y$ojUJAuN_Ns z18A;J5mdD=&)c9J9%SPuycDmP?vOQ4;4$;Ti195S=#ZNgcA=Ef}jcv>;Cg0=Hb^4ns(jkogwdXVt{6#0P!Be=V7rbnV zZeea-FQ^;9tXhKd0`0KWJ5ZQnO9Ec( z12-%4+JOKUxD?Fou*pJJb4GYu($UW}W3(S=KQ1=V5ScY$R=cePuNrjkxd7~(i|l5?L&xnGnbN6@=Y8+ugcB4TAEc$Y#NC?b1?jpma8dp`=v?ImqNc} zj{Ut80WeqCrHbWEqcAt=2gQ3!D=lAR{gUp~y*YHf9_49vCs~I40@3KZ+jr%vFaX*- z?~{%a6kBVNf&m)JAM``0YZ~D)xTu(zGjX1J#_?xy1w`wF7pSi2@~Ko@pu5Gy{S%ts#Zkv}305nQ%1rSqe}5{3f*=k)n%23a{5yKKH7#t7 zVq+Zo9@BCG9mV8p+yTz7RS2d&8bvwY>mCRtb4WAa_512JFit-q{^84? z%UJ8>QN%Oht!q1J`(5Oy5bVJNejcn91HfXoI_k2CyzF>Qu6qs6GD^txt{*_DFXoen z|4-rXzpLnei|htbq4ABn1Ptf@+7M3~-GZD@Mg zmx0T8+nuuWY1Z*AM~cY9a~}U&=hSOt-*cC&8um{mMGH#IGy8f2DS7$sM3c73-8N|D z1IuwcTTSQBOF6%g+1pB1h+N`{ybl$$5Y4+kvJFVNcyoc^dVP?A1h?w$!!s3~bmN%T%CJRfDkrnFLt zS5$O)c}YtNwlDXZJ*7Wz9(21sC+cI^n0~ydB;p`*(|p0gbih!=O_vlfix6w8B9x-PSinB?;bKh#X(>BQ*p;G$mfvTf z4G>3YwGdW+FZDpHdUG=qjnhX#6Ot|;WXDfzBfbrJ^$sg~#P65=h`!cP+}$lG)1c<& z8zb~p43#FgyB{~&1YX^A$9>AZf@kOleA2&xAJSdqxXL+I^D)P1T4-E;PqD2a)xE#$ zohKm&r8*W=aoVh+m&RA9E&LS*T0FEjE>Te#y1Zo3Yg{T+cn(R|e>}y9!GZIfJ z314!DOB()S<-t+tj$$WSW?Xp;5N#cIria*Z{;nvcboZ$Y-IFzt78TSkdR9;i_ni%Q z3X(5bX?F7k{`u7BT`NlA;!dp~*T75H=Ag+wD+Ux9TLYDO*`kj@`X>hlC##+1>*FlL z^zDY(m1CY_v zL$7DpNM=aprQSGGebaceReMMvjQa9sOuP!wGS>ycSGi2E15>(D4DhmLqxQ>I{yx?V zF`UP07}nsT&~HN9YO9)GfbCA`^Po$p53A&kJmcyHabnYKVU!EhNd}h3 zRr`9ACq^mHe11TeTsiJc>{7|oG}TJ8cFVo2n}T@_ZwHn)LLZxf-9gWZ1jiJnkVgY< z8=)k?STNccU2a|)?ONSvg}bou z_I(TC-E`+KgpGBPtOSoZSFcCXs)5sMykeKaSK6q>-Q|Cw!@B zcdZ%UIc&Cx#De=Y{l!cZQBby!GWgQKFv-H6Z+Bz72} zkh;BMD})9Ej0hv$zTbE0{&?BQ;P=Y`{*BDx-|7~O!u$(9c#EM;=w+B?bIKi=XS0$- z4i4FFO~eN09P&o3Jm^>RtQx%_d%*O1>GM}qZM?ibeK&1mj)q}?dfY}euN(e~78UVn z{pdLKdZ)PcjweNy)20`zhYEX3F*XI)m2tP+@%YP}QEJHmHC(7m_Qt5Y3O7eG;kaq7 z;P>25mD|X-pCisxWZs`sKXPn9Fc}(O2$>MvV%Xv@F)HT-L%M`!|L=)e)%VbA5$0G` zwp^MicSz%qNsXJ@y2X>2>iaSgEMyaXBhWC47Lk1*z|lqLQ28o$zL*5BEfc53cfk)OKV;=HjHciGut?11n1C;s?b~_9t<=JSIj5`D z+Je{F#HLeXWGg?ifTHbKCaG=Y<*@lAepG;14=m599aWnQ%{7ZXQ>&CWxpuii)5gV= zpOFLf@cSo)=Q=&GeI29w=c0SfUuD_~RD**z#{I4aKCJr&rFlD2ZuX2+^mrJ5GQ=*f zm?QjEw=g4h5GOimJ(Sd6qkolR=7|jw(#VeiZ_*84p+~CCx(z;8!#{WjC3lmqMPwQUdMhSHWxEfNd0_xHMdu3tTbt@d!HBEPtuuwl z)TSqQ(|q^7v`H|rvdh93=vY{u7$aHS4HMSi#!hxhBj5Ki%-0VGZv>lkYKe3z>4`7( zQe@+_y`qGs6S7i*IACpfIx3gu*AK=RtccFoc&etfnfGMsGL!m&J?hFD4fj#~Os z_OHiQG-pyTkO#A$<3cFM>65D4)pm9fRNmiJxi2o*^iaLj0L|2T9B19FiRi%q)E{f9 zo&4n4&Lnm%1sgo*hEhUydBhq5E~I)$`IBA|GXTYc9;TA-|DJpOA5rE)gZIc%;uU4f zcAr!QeyA;QuwZKrerIW3d0(Ry%0 zYQ7nvU-C{b>@n#GP0a0xQ5uRzTvUh5ItAE-z2UvgJTYv-p4eQKcN&|pCoRRrksw@8 zoEO-%ATdrbNEo!Fco5PCCv0hbWB;(atK6k(j1!7tt*{vLJQcoTXS_Kc0`Z@o*M8oC z(ug<^wMAQ=NUZIR#T>}fz1Gqa*5l_`hC94XV`@IKzfoY~0AAZIs}{Z8*%ZD1+5uY& zLJup6>&MoDa6U{X#9G912XF>zKF&v*=7UTZ%Va2mW3HxUv{~83?7AxZ6tv4Gyjw_< z`e5Jho%^#kU9_>K!gFkS?0grk(~Z6I^QMn)4N1P;&t3zq>LGK3ABowcg3W9?kdsZ2_fuGDGV-h&#i_Fa4J9>vw4kgaZ zUs?t!nwiU4RrzzW~%14JT(#>WU5$rJda94S8{xT@tDm2n&f z$w-j&g*3isWUdXD3ZU+EVAAl>rNaw`qx5|vKEe^((VX{3QxAIt zy+*hEYfod4_z8E)a+D3u=Vz+@puU+?F!}({5bmJji?$tq=xu6QcM1sUe09}?$NKls z{?EA=W>YQEMT3*LnG;tVv1~HZiR~a~hpNk+x^S3t zo`!IAHPyqo<3ExmxJgew4A~51f-<^6V;@p+XV%_BYZN(24hL>R=$Eu8;+k6QVXo@7 zZ>s$4Syb);!0LiNPxcN=X6O63m?d!l*`v~8sW`OfB#r&zCi3d4iKlci`b988=wlta z5|N!l%-t;asgio$m!=ECC)iQ+c5BN zW=_z^Gq<8gyk7wKZn)6I$L=W8(kR|IB?x-?=CpUW+$-LUvgMj07lr^2R@L}MtrIzG z7B5@sMW%cbKM1QLkV)^g=$yA?#LzJ}Jv6kc>1v;*GX=?L;U62oqiB@zB)?drJe(!p zJs8ZaEi-{oLp7%{FR>X7(5RJ8l#VU%>L(ti4z(u5T{$@riU=p#Je>);2xT}IM+dCy z(mTm_RkJ_7>*b_0p*T1bdo@AvCg8zNbOK}2o3zJfV9LW<31kN$S#~;Lc0|^D$${0;%dBgLBrd+yiJJr8aahy6{}Yt;F)l~ zqG{@T`q($;eQFq6?O^N2Weh;JN8e5D!-7rm>Av=dH!3(A*BtR0_fo;2Y99ErB*z0) zbmrx$M<5@cZVGgQ89Lae1TCcT#ygKdjrh7$(~QQFkAtibi;b{ZQIy>+0g0-5hL!C2 z=zF`uK}-k=YP7Om%$1pgrjA9I(l-RLqN35|UL=}C>fce;MsXyJGlge6fU9&KvUG#~ z{vG6%KGVF|Pb_Tg(r=dDa<{g!Y||GHj58x&>+~$^Q_F%Tn1EfWwb)$hm>#3{@rP5U z#=Fhkd#3i(Bni}QYR&$d?B?02Lly2sfB-jsAsSp9Y8}Lk%&E=W`I340#CN>)WF*^F zBIM|C%O%uP(hY2F>Hss|@UXVN<>FrGf)acEGVQ$=A0>&JUXo}C4!)}#2pKbWBOTN6 zrCsp5zh_B}D$Zg+q5}u#@)p^Jzi-4|R$i+ z-;!m&?82XlUHJ1U{^i-}@0_QCN4u0Tz_=U+sGHEn081Iz^0;4|en^JT>=`!SnO?fS z_KnOWboV260pA6%iS2I~Kx*@R_!9QVXHM8My1!KoLoka}00065AOHXiupgjbaVi`D zz`^2RZ2!ZH0092Ap8(s&{}so_;#45qU&cJcj-mdw|HoW(zv4fhr~eiI@lP0j9sdM7 zo*9Jq%m0nU;w-=7iCCQV@8;qE6~`_IxP`@k%vX;cV+JAsl(3z35jWliD~$m>6!We^o1D!uyld&K)+nrh5vGaaKPBb z5fBm)lVArlQT}+HU>sa99v&{11E65+_W&*x9yO=9Dn5w4*K zP9dR^)}G-+#Pke|Ow2sIeEb4}QqnTAau?;VTvb!ofN5U4rEg$pWNcz;V{2!B*TK=r z%iG7-&p+T^L}XNSOl(|y`h$lVnOTn>KPfCKE_qg3R$fux(Ad=6(%RPE*FP{gH2iX8 zbo$NA?A-jq;u2zG^WE0=&hFkm>iFd2r_;~qFJFJq1;R?+Z`beAMTMmc2NxHNOYnm( z5RM-fz*M++oZ|S@s(J)>JZQKi?i12pPAjPECE}L6iKMgkoFb-&N+EbqKS=w9vOh*x P_+O&zZ-o6nx)%QrGkjqh literal 10846 zcmdsdcUTn7viB^zOU^7A$vNjNk~2t#C5WJiARrk*kf7usIVqVX=OjVNARr()iU^u8=X|$kXQ!sRtGcVFw|-kSt)jvX%rFDM#nia~+HizxCiJ!9|N3h0GG0}DBK7ZdOsP_> zUzPPawWY!7BJLPYhzp=cme~&lJ1_Sed`nB2{DFcfz5s^JeNuEsoIU)E9?39DEq<=t z&;Z3!>7Ke+W(y@B?UsU!-}ZJ8X~B#^s&-zkC9%%S zEqrT#=sBv^+!{RUJiudw`2ujQhyN(=_BiP`72(C=PRZR5(J#9N%Yf-lRtq z?+Fg0oCo(^BH4j`7QB})G}5CWI?Ao|Uy?#W&uNTqf=Fn1*73=n_k_~s^a!HHK1AW~ z2VT=g(0hoW^LPX|TmTAx>8{yB52YQ!V@0-tfU(F-FI%y^(DV&%*d%6Ee=Q}&rK-S4 zpuzyCN6Lsk!1lR&NJaa$r9|3B)+31p9n_W6?IGcVD;d-9MKA{E(=qlf`M*>*J1xww zRerrAqkCx|Ey3m;yar-a za7z`VRL=c``{VIb`mmKudD%{INsi3Q58vRX;Vs`JAJoS`)B-cSPOZHQj)|Rhb-czx zb|b3k(?wUGbi6jDYZZxmK`-``)t>2N!Kf(@ea23a{9zCu=l8wPVDj6JO8q>0J7*|= z>1b#PS{Ws8eM$RuWCC;DQ#JbbCQZM>(J{r&F&P{y#I|5~r$^wF4`cW-?c*SWt-v9t zx%>-YLG}W$znK324^dE|V8}lq3P?EDkD9NErQ)}XM={KvMp8(>4+xOWARz+9UIhSA z79L1n!2&?^xZL{+D*#|&V8ibU766Dt%%|Tnz};u6%D|;g0G!5I1pv%r(EvbbpZNL` zUjP6UIXM1X2Ke165^9irTy~04%Lo8honDFm?(|9=AfiD+4i7#60;52n5D)}>g@ynK zi8&BdB-+pcL?Y6GFkZeI8DeJHHaW{2t$%>ck;8eRg>~vl$EQ^Pp!7^L>{2kX>stSc zo7gHNY)$4^)lY)eLG)}l2>Sv^U#v~OcSZoG7@@iVs$}u-tA|F%(96QgEz8p2IQASj z8U0E*XxOyST+`k^^*B_+lAN5NKG>pG?JyksXhh7Zq@Re-Zt1B4bNiHyPHsnGND{;- zXZo1i|HwQ%`H{3cca3w#fX2SS!y6Ond)sS?B%b9ZH-C+^2Q{v`xO%~vUD>0wV-hsP zXPA`fvva=JjC~nyJLVV?Kv{629d)`*2s z>K0+J1cV%KZcHUw-5;&PM`VQ-6ErrsRco+dN@LmBnu7Z}neMc^`VUQ$z0XV&!ur^= z4g8kuus%3Fng{@y(Z3NNi{iri{OK(#sUaS`e`y7;szPg>-KZa$U;9Vv%x*`^_@l|2 zVCGYW)*uuDy}l~j92rbi_PFMn&90_UT>AU7BF{M$2lo$j6Wh<2Y)R7tD{9@7uBU%? zPPj&B9Q#zSn5vs-=D>*-D>+`ka{UQwg|J zy~eKJo-@Kthn>xqpfq25N9jOj>UsUmgzNeD5IW*q%4d8~B3oOxq;2N*_G??CQuLOL zLd21cH{4@GXi_asX{1-6R4C>#RgulaFoqGE7-6(#-^QQi-q^JBnc}M_@rLB7X@~I# zop`1AbKA#Bak&mPyU-Blit&RXkuw2;ajU>o8wXp38y>9Dnom&^rp(TC+CK^%273sB zac)XCk{hG4ua2h-t+|XSvyDC9O90%pJ~{pRicNk2-0XV9`~HN!N+?(C0=WNzn$9{a zzktAu_)eFZcooHrftL!%*g#4r6L(eOrPuXxmze$}nGjT7m|nqd6jjVgtJk>~%evkm zkIz3PSjL5|98~|=47|}o$~)n=VfJw8R_d$e2SXC2Qk#D!W)cyI<2JIqa!{qdqED5> zz@F+>qZ%z6B%e#v_$0GApG%Am%O|k(4SN8q1IaYbh-9z}8{Sg2+7Iq)KhTmG8krJV z6cvL|P~egk6dyT9KM#=z5J7v6=4Mg7@(et#Hp^V-y&|8JqOTa-lE(jr1K53J#yhDe zKv;QupUlOIaicC#%Ea**>}GLGkr8~kx#9w7Ypjs%Zn*zC#;vGGJjnpj+^B>C{$RKy zV{z~0zdKM+{s}#P`&FbH2GCHU5R|{i9_NLZ5x`~DB{m?-B`{o;D-RA_yYJtwAIbgg zxPLo+ZnzI00k`=j%dwMXk^=p=Fp4PX!|7>bJa+XNI47y?BlAOz6pL;`DwU|RIN(lXi%%zOfJ zF2p4K0kPRti~oR#A0objZ{QP676(l&sU{`sW)&x9^8;KHZe>$G+}q2E>*AAkQb`{B zYHn$d>S)xOjuDN6wX=ALxzmw3Yvaw}k*#wZhw4)Ij#ZEUR?#yk_X)WngAT=$&z@gB z%gHkh8D0bt!Ihkbd%|ZF)Rel+u9eM?b7--pV>zTZ@T@6Uv?-X!%0-0B7NvAQDF?w8 zRYPlqPHNxl6zi^StLA$Wp%`f^C$mh&#aVTDi+*#;jEU>6;L6d>F&2rRH86exlZds| z%x)g8qSkqe$<6AUit9f!Q_`UCx2A$aw9s71QWu#F^xA2w7*BQ?3o;6SSmxOMGZ{as z^V{+joK08l6r(;1z1JY=;#`DlZ-pnRs zaD|soZjAZM1@NE^;9P&pvZ%YW-rA|MH-PaS8L}Q?~Z(mR40Z2OTBijM=%AIu4UJ z5L}b|JpSxhOX>|@`I%1yW6;m)E`W!xCx6{HC;IcGo=RaGN02*Oy;)R>ZL8X`QqmF? zSK$}c>*F51t5-Y*hgGNBeGl-ak^EOY$>eVK$q8KB$nS{6v+K!Tx_=A}@-muH>^su3*F;tE9*t}rbs zQ<`WtD5Y1a|JCi*?R~3;{+UHBL_Ua6Y)+t z0dpsqvP=9Po`}vv;tG+~yws1F_c~MP413-fv|Jz{J8$%{8&)T?SAH# zAsh>pD+Irkp+e_HRV!V2zAq>Hq3r^QeB)zW^gM1;b+_5g_%?q0NtAU51Ea07Z||m^ zILWxPLiXwNy-p0~fO2wjn774LfIM5m-8j}1`XLhonI@7WEdLNM*4hDrV#XN&V&iq* zeJ|JCFR_+rW;0*kJe(v;QGIN6JG}o*iLnZo^=5WTbRu*Z83htghweTcPxa9Ri@n*> zz$LG~;W#d<_`+)cIHZ>f!|}_rU;pkd{=dpD{g<%-@^Aa>*^{UnW52yF*{7sB8Y}bP z-WkQ7?~JFz3jox#qSCzykqVx z|ClUu$*$E9y@Cu3)DI?m_e46nHQ+~AGLYHO`;Na-xE}W2d-UZ>CTz4R7%#30ooVAr zf+qO_(8P;dPuJ=U2>x`1Fn9wrh>qa3_3vH+1MeNLP=?M>%R7au^Zk1F*n#wA%mHFv z(UA-O6j_^qNNhxfAj1wY5|jW46a|b5LIaQ)E)i)MF>fF~2`wEdJp&UTqwoVa0U@0~ph5_o zh+hDDjmY#tdH%3;XmFd(rIT;J`p?E_r4_E%|}2_msbi9tsmv z!Y-qsJcASUr1@Hsn$+P2jkmDbHpR;wx_L}22O=VOJWt65oh|v3 zd`^q^oPo_@f-?@dMF}(C53w*g{ahP9x)Ctou<4OLLb#X{p4GLCb0_+&Pnjz~hV4nm zv25xH0~3Zvs|WScB=UULM=2={kL(j}-b|_aWiX~49qh=^rJ7Kf7}nreL8ZO$rKq&| z(LT3hE61B&o~ZR!76QcShu7G@*!R@FHb3t^YP_DF`_rnE9IB?BM)+*_J0=Di)l7C} zeJhx+`yw_|o#z~UCkL1x-cEgUwjkzO{c26bmO)uIKl<@^zT%nnGo4lI&+lHHw&%}- z`F}Pyb+m*lv4|<4tGC?5w9qF^VJ?X}B}{@9-*0aIHTv`CJzN^*VK7QE`S}J@<-x@Nf`EMqFIe0(^3{+2G<2rE$*ut#FL``c=Gdz z;(E|Fl{KIV9jlFYAgg?Nd@`x-v&jA?NP#^5(4+lmXdoxEOC< zx+d2Bw+=svsJ0NoA#hXZ1u$NI#CW^3{7?;%;dSJ7gI;oEn$OV{N*UTsEy7_p{7!3p z%VDpNuhGQ@)bQ~%Yr_rpvXbvWsj~*S)S5hOx<11Tq$<4Y& zk`k!?5)o0~90VI?w-t)HEp;DpFW^hYqt@y|la0KV)v*1~W(eFWGwAAJsYi&J)RzkogaD|#}4E?GfC zT8f4p&6Kr2r8&^Qa6-cb+PgP?0}p>`m_2_g)%3G>aEhLiV_H|f9tHE zc)tqSUD$GU-IC2$Z)ODjcBn)7=@6*B5+e7ax}PeQ&Q0J9=Sh&2!=RsGWro;fYZFQl zPi886bGU`QaJxX+$NcLjsyOetZc@g*`bj{l)DaYYhL?E94P}NgiwK1s63)cAVq2qI z7_mT^H9zoBH0MUq8-f1sJGd;Ky*VdBzCsdig^Hy6r@ptjwsOGdUA?{|;6tJFLf7i; zJH2ea+=KV!o5L{f;^}xo)8>&GEae{;Kw!kvM?)HG5<%IH1#8wQhV#+BA_c3=KV@?Y zUw2z5*-NBB4Wo*M@!wQ6Qq4-ZP+-m%eJN*H=qdW8$g4X@>;VrKZIXoHJWrdv{eSlO ztyTY28egB9f1(NPwgN2`2fnKG8w

H(J8&1Oa4L|1Ezg*%= zNo=W>+&qPPta+Ygp3ul06=yI$NP9I@6Ub>})h~+LX76vhES_DJP^M>Ka~sZ{;)M6+ zwnx3ZGXAnUw=G!|4*{cQ!TQYilUUD(3kqEwbX_E~qtQS0lEA5qy{$`0dn+miJPS)BR?mlTC3;JIKp(c<$OD zc?r+rM1_$C(K2aB3+fNow|8)dK2xif3nT7YJA3x`RFShcLS8hz^*+Rl?|(*)hc4^5 z(#Z8il_6fzyK-bC0BsuKQLeSwTX{$(k2T^dxS1VR-#T8dki!!rsW&Oz@Rx;8s^6 z;R4-4cKXN0&C&6IjGmHn$wo3-Xp zklTJgwd1+9_jlSX{pwR+B%q5S0sSh82!cYeF7f;_hX_H2iF8mRdOliYjQ9c{M$Dky zrfczh5tUKz{$-$8-QIbP>O{AIy=T1poi-f0W36pp6Z8+N+SQ}mn2HLPoi_Z{@^T-v zF>CH>^f>fmDX@-~FY5N^=HxFHtOt%w#T2rH(j_Jw`41gzfb_?m#TBr|#8mFYqJVt9 za=$C(^|{Ni+*q2jYnH_DE;#RJ#}Kai!?Y(dMq5WLC_kkdLI`7>CWS=RxY_&Xz*-Va zH;J9qLesM?QswVUPZ#Jc#VJF)v4Z4RtDB@AWCptwj3(eP>GWB{3a6Z3Q_?-{*|>SD zo7#VjzpD&Fd3m+DnOuVl_CqNv476awZ%C6?`>3^seu7o&L=mp{;H=q`z@$9$Im3pFKDM>6iJhxGkS|YlT&pf zO0wbFUp*|!SB5=J#rfgWC`lmFxx>)hMaL?ox9Z$;Di)4kJ`{?x+uT`FcX>ZYM$GW> zXUA{_Cw#W5sDLRdFJ>_;HI>vb@l6PCuXbeDs8&gZ_RjQXLWMQGURpO(Mw4aZyB9*y zrkxv{t>x7yxVf|+G$fTsLr-BNHT*>+xWuKS^g*QP3rSk6wz!NL(@Qzewc>3Vx&C%DS^1BN7fjeSJ!l&l4zQWNJ~u+)r%88u$wjCqALY+SDHuzm>1W zl(YCr5+7xZxu=-pAfC(hS?$8yHir0P zBvERxL!4W*x0NhUKVUr=;;lc8e&^3}d+Oy-)R)M%Nh8}e*-R#*W#2?KBI}*x{bg*` z0jM9Re1US+RN|xuVo{HP(}k-?uCGmUKH??;&zWsr)&zn;Sr&DRpf=q-t=oCqWv+LJ z#!CXS^l4VuKk((ZKyDRrwcyemA4DFL^1Jd>Q=w$rE@u@O|0|)8dMSKkMq}G1avf|5 zSu`;d<+g#90P6sZq1^*8 zKces~sF_bx1(_Uc)7S{Bu9d>{Xf7U}@}OI~^5O-MWZr5n@D)#if4O>GES|i>!yWTW z@tg1(N5iBGU^HXPbaF039k$2*MXd8o^@x*l&T|wR+0b>{)`Q0v994^!JXk zJ<5{14|`&3Z>nSKD5u03u)v~9s&Dv$E{6##Axgvl_I6)-&-8~9UNLbmqgJ2Y1pSwv z_h?m!A}5S`(MV;%3{P(;;&EA{m#N>6bG^F|_xZh#HOw@B8Io6Q*=kDX{Br!Ds^}&$ z0dH%Yn{&^w66tha{8P4m=n%Q|p^(Dd5bWJFd5miW8Cn!=M6-1_btoq_hAl=SvsrRw zoB^#QmxJtchx{DA^c4OeY~Jv?nY}9?K_!$W*5LpzDgexn+^SUX{x!%+$Y*K#89ZM>|=k; zp6}B^MJe)#o&IEW;RMN+h?~TJTZ~*wMSiSoa6-7SWzoVE>(bIcCgSYbP)%I`C0ddQ z)C)dlqUSbbsChF89}&JDN}QX@f^E<#Rj9p~>Lr-afOkvuDSMWzoSCa%(o;f3he_)? z#mTW%H$>nGb&>TAZTVY5)qK-#P=47^qa0{}SM>T%a$#qWC0qM%S=l&GY|wtaTE$Av z&r6zKbQ?$2CiJg^FGjJTpBr{lM=5pV(y70wfANd4$S65?SobKMNY{Df15C})#!jx0 zZiLs$&BC!yv6Cj}{eaqS0;SOSPrxs;66LXP7;&g=X}4@}j^Kv5tA6)X_ud`%32`7K z)vQ({c`T;vgfNvMWjG~F96{pY7&fB%R0dcOkw$k7iH7pUL%OuItzXXJbr04HBj=W$ z@0j&AyqlJ!`FBfA5d04|z93T*82{-tB|skf-J~?K|6!VaQew|l%nt7MOzuA1uRDKc znU?=MGtE2}w{+*ts^m=UCE`n5riLK^7zG0Z;|lPRBm@e&N(~dyF~Eo!c}1jU0&DPT z`Q#Mc1FG9e1q6k4EUn%0{zUS(fPE2P1h>J{^@YN*)EwpD47qa~qgv9+1?mXEJ@LFN|OpT$=o`$eI|xQERAL%6>}4lX`n|QrX7a zBtJsQl7MxVJ2~Zv`N8OY`#i0vaYqLy=R+>zl(!#)h$jy0hAWf}nT$EY@bV+F)XFVI z7T28k`pHK4&^XQXIAs0UFf4IGQ^}o>t~2ga=e#K?|j^K9`fFCSYsRQOWoa*b$ohR zP@}slT7`TTnyeOCeucM6+b8G5IA)S>y3F|KC>V+`&n14^0b+x3R(I)GTWiMb$rkMG zCTWA>Ud1J8N`>0JATnvqk(@r(X^S$!JG$Ar@7Wel4L`gxYcVNqViy|}I%ltyY6P)Kp2%<7Ish@_sw=v*qd~%qnde@ zI&F0(ZPw0vVVme<2DvipIjp<@th=A6FQ#bPr5I9mhKzSvic;v zhLPMY;6u!=g-HZM*}2~BPMYl^(#G2Sx{$A3hG%g!q>pcZQi`n8Zct$(gr?_A)fh?# zwi{4W%(&aly*<^gqK$P_RJx}Un;xqvpB(?-8LTmY)3B|j!RbjOd&kHFg{=Ih6Gc>Cjs^Uasv z^S>>(OyMm$EF*E9hNGDC-?FEdteS&$pGuK8%ld(>+h z6-g6-Ai(A3tqEis!fXDeF5+wYQl8|R_CwO7*X`Sp?I}RW?OsS;36iF~rfZNi)!+26 zUen0o0J=!}Qr{Y~jR`V=CWU0uvH}1M1qxh_We3T>ES#5i{OyVkTpl{eCTz&_D{{E6 zkXz5DkgCv;t&EYp=hy)7fDkFga4C6tT$ao4i|ec3|K%+-{pYQKmr)Ax-4;3qCKl4C)m}w0NIwRKLLm@jYae7i03m=9((%cl5@}nY(L2HT z{bRDw8DuNlh;@c{7zHey128a2NXf`4n3!2u+1LezghfQf#O34_6qS@!RCV?A4GfLo z#`o@9J+OXgW9#DT=I-&t)9d+*z@Xre(6HFJ_=LoyiuIcypbawYyL$VYPd zRQ}m60_3tqfk40zv`f1{C?1y$2p~{8K2$;(Z8QrfB6@y*beL>RR%IIogMiKsv8D4c eCJCe90@LoLX;+s0&kPIrf3oZ^!~S8{^nU;ePP7sL From 4d1f7e051dbce01a7c8a08f44f20e67d001333bd Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Thu, 12 Jun 2025 11:32:24 +0200 Subject: [PATCH 018/115] Support composite op with non-sRGB pipeline colourspace (#4412) --- src/pipeline.cc | 11 ++++++---- .../fixtures/expected/composite-red-scrgb.png | Bin 0 -> 1709 bytes test/unit/composite.js | 20 ++++++++++++++++++ 3 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 test/fixtures/expected/composite-red-scrgb.png diff --git a/src/pipeline.cc b/src/pipeline.cc index 7acbd967a..679c83298 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -669,7 +669,6 @@ class PipelineWorker : public Napi::AsyncWorker { sharp::ImageType compositeImageType = sharp::ImageType::UNKNOWN; composite->input->access = access; std::tie(compositeImage, compositeImageType) = sharp::OpenInput(composite->input); - compositeImage = sharp::EnsureColourspace(compositeImage, baton->colourspacePipeline); if (composite->input->autoOrient) { // Respect EXIF Orientation @@ -734,8 +733,7 @@ class PipelineWorker : public Napi::AsyncWorker { // gravity was used for extract_area, set it back to its default value of 0 composite->gravity = 0; } - // Ensure image to composite is sRGB with unpremultiplied alpha - compositeImage = compositeImage.colourspace(VIPS_INTERPRETATION_sRGB); + // Ensure image to composite is with unpremultiplied alpha compositeImage = sharp::EnsureAlpha(compositeImage, 1); if (composite->premultiplied) compositeImage = compositeImage.unpremultiply(); // Calculate position @@ -760,7 +758,12 @@ class PipelineWorker : public Napi::AsyncWorker { xs.push_back(left); ys.push_back(top); } - image = VImage::composite(images, modes, VImage::option()->set("x", xs)->set("y", ys)); + image = VImage::composite(images, modes, VImage::option() + ->set("compositing_space", baton->colourspacePipeline == VIPS_INTERPRETATION_LAST + ? VIPS_INTERPRETATION_sRGB + : baton->colourspacePipeline) + ->set("x", xs) + ->set("y", ys)); image = sharp::RemoveGifPalette(image); } diff --git a/test/fixtures/expected/composite-red-scrgb.png b/test/fixtures/expected/composite-red-scrgb.png new file mode 100644 index 0000000000000000000000000000000000000000..fd2bdf940b2f4e3d494c086a6c89413a780d751e GIT binary patch literal 1709 zcmV;e22%NnP)1FrIgEP*?>8ia~7xD)Lj*I(QFvEOc8exFN>ESG%*^l@sb#C|H-50?I7xe zF-$c6Z~{rcdC%vZ_nhaP7X%Ldmxli>z(*G^a_aPHeskpt|22S5E?;Ie8f8mM3#+QC zSY2Ammi6m7YBux5V340*xNyfXw*~lWW`-w^9b;El7u{|*J(ZPg%+2NQq$CCa`T#Zn zYzH`~X&lbV;z_TU?@dnf=eOU!EzsWre0%jOpMUBp_Vx9#wzihl9uFJLW_GS!%RWux z5WpUQtpIEFdOEYRXiZF{1)$?5R46Wvjczyh?%m5*pLvEq%+CHT%sjvkZ@j^m&Ya=k z;2;|s8dz6X$L7jPcCKH~P<%Wi01p5>1aJ!As{oGx9M&}YQ&Z_P7}&aUCEEb@0}KN6 zSgowCu2yHsnc;9)1twX&1>oY@vutf`RUg*Z*DLGK&gP>49|0Hzcu=orZ*DF_77LGL zWN=o~_~Gwa_!{6R0B`&O%&TcCb8~0SnaAT%LEZxJ?)mfd`F!l`>|}d;JDZxC=(E{4 zv2rC3tXacANeOq>*DJs|Yx8(Gws|vW)6@CIU3c+Qy`IxaNgU10WK&t$pT4cBsbNJ$ z1xrgydHm?nTLC_M5+c4241r27~iixt;ydxun}}x6eB+EG(qM;oyQ@uzUAz zYKJxAB#5h^BkE89(hdFn{p{`SRaey9+`Opm*s+7<6vPaFkt4NSj~&YqqgX#k-LPRFfg1!)Qm3n6YH9}c`ef?$HsmQj%!}m3vN8agdQI~HVxo2eU@#oK z8T}~Nt#i<9E@4Va3xOeOS~tVteTxIU^}-7@c}+2ZCJ>K;xB{;7uVP*}FV-FXpebZh zYBmQUL&|P)X7nB!jpdAw4-$wFXl7z!B_+T`0Yr=n>I!1%_kjrm3B-92`@xKX z4C2Wcz^2e94h#&;LpYsI-gjT?&FGIXEv=F%DTM@@2zZpOUTx=h*RCxNAmh{WfJGG= z`oOG)EaC|eCqONv#r_Y1TY9$4x1~Tx0U8V=1mylZn4N89YU&1Rnu|akfiR1UYZjk| zbGEH+8!-Z9rYaMYN0W)?LHI!&1JMl@1&ijzNler(EiFo5ioiB*+O&lRgMoVeb^?c0 z20A)IO9K#riHpQhelog^yw`UxaVC~})rNksu)AR@n63Te)#EGQ={P^aZ3?2&7=rhvka?<5-G47!_;vo=6VgS~FRVk!E$iR|8laTPB zauy%&qS07Eoi0q^VWy=OGa7wt!OdvFm27%)lH0d$SG!+UFpD@0A_}4lwE1l+a)FTP zDFDgI(r)e4v?^*^JAodqUR}-0PfsqomMyvyelb1Gj*bqN)s)3DAP}9PwadytAfO;b z1qI-qdkU#(Qt>Wjci&yd52h|HZzud~XN--F#Uxrj?*Q$cb~TIyLR8RdwbEoVF)b~F ziHT+w6x8y|*JhTqAuo9?pE>s|bHX{QHN9l9Cc`+_+IqM5&{to_j~{ zg0E+0)bNqzM6O04L12dFP!wdK=vF%jnk|H+cH^akW1Rgs7loU}9ooSudnz zKh55sno>n5T_PLxa?klkkJIn3U#Gkg|H&Eu`Rn*M9(LA<@u9a`00000NkvXXu0mjf D5=S!z literal 0 HcmV?d00001 diff --git a/test/unit/composite.js b/test/unit/composite.js index 865ac5981..d748d8f76 100644 --- a/test/unit/composite.js +++ b/test/unit/composite.js @@ -122,6 +122,26 @@ describe('composite', () => { }); }); + it('scrgb pipeline', () => { + const filename = 'composite-red-scrgb.png'; + const actual = fixtures.path(`output.${filename}`); + const expected = fixtures.expected(filename); + return sharp({ + create: { + width: 32, height: 32, channels: 4, background: red + } + }) + .pipelineColourspace('scrgb') + .composite([{ + input: fixtures.inputPngWithTransparency16bit, + blend: 'color-burn' + }]) + .toFile(actual) + .then(() => { + fixtures.assertMaxColourDistance(actual, expected); + }); + }); + it('multiple', async () => { const filename = 'composite-multiple.png'; const actual = fixtures.path(`output.${filename}`); From 99be893dd4908f72eb8d824a9a8184ae1416cb32 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Thu, 12 Jun 2025 11:27:26 +0100 Subject: [PATCH 019/115] Upgrade to libvips v8.17.0 CI: Use more recent, non-deprecated Windows runners Bump devDeps --- .github/workflows/ci.yml | 12 +++++------ .github/workflows/npm.yml | 12 +++++------ docs/src/content/docs/changelog.md | 10 ++++++++- npm/darwin-arm64/package.json | 2 +- npm/darwin-x64/package.json | 2 +- npm/linux-arm/package.json | 2 +- npm/linux-arm64/package.json | 2 +- npm/linux-ppc64/package.json | 2 +- npm/linux-s390x/package.json | 2 +- npm/linux-x64/package.json | 2 +- npm/linuxmusl-arm64/package.json | 2 +- npm/linuxmusl-x64/package.json | 2 +- package.json | 34 +++++++++++++++--------------- src/common.h | 6 +++--- src/sharp.cc | 6 ++++-- test/unit/libvips.js | 2 +- 16 files changed, 55 insertions(+), 45 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 53b5e12db..a445d3fe0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -78,34 +78,34 @@ jobs: nodejs_version: "^22.9.0" nodejs_version_major: 22 platform: darwin-arm64 - - os: windows-2019 + - os: windows-2022 nodejs_arch: x86 nodejs_version: "18.18.2" # pinned to avoid 18.19.0 and npm 10 nodejs_version_major: 18 platform: win32-ia32 prebuild: true - - os: windows-2019 + - os: windows-2022 nodejs_arch: x86 nodejs_version: "^20.3.0" nodejs_version_major: 20 platform: win32-ia32 - - os: windows-2019 + - os: windows-2022 nodejs_arch: x86 nodejs_version: "^22.9.0" nodejs_version_major: 22 platform: win32-ia32 - - os: windows-2019 + - os: windows-2022 nodejs_arch: x64 nodejs_version: "^18.17.0" nodejs_version_major: 18 platform: win32-x64 prebuild: true - - os: windows-2019 + - os: windows-2022 nodejs_arch: x64 nodejs_version: "^20.3.0" nodejs_version_major: 20 platform: win32-x64 - - os: windows-2019 + - os: windows-2022 nodejs_arch: x64 nodejs_version: "^22.9.0" nodejs_version_major: 22 diff --git a/.github/workflows/npm.yml b/.github/workflows/npm.yml index f74916713..25286b454 100644 --- a/.github/workflows/npm.yml +++ b/.github/workflows/npm.yml @@ -70,27 +70,27 @@ jobs: runtime: bun - name: win32-x64-node-npm - runs-on: windows-2019 + runs-on: windows-2022 runtime: node package-manager: npm - name: win32-x64-node-pnpm - runs-on: windows-2019 + runs-on: windows-2022 runtime: node package-manager: pnpm - name: win32-x64-node-yarn - runs-on: windows-2019 + runs-on: windows-2022 runtime: node package-manager: yarn - name: win32-x64-node-yarn-pnp - runs-on: windows-2019 + runs-on: windows-2022 runtime: node package-manager: yarn-pnp - name: win32-x64-node-yarn-v1 - runs-on: windows-2019 + runs-on: windows-2022 runtime: node package-manager: yarn-v1 - name: win32-x64-deno - runs-on: windows-2019 + runs-on: windows-2022 runtime: deno steps: diff --git a/docs/src/content/docs/changelog.md b/docs/src/content/docs/changelog.md index b9cbc7b6e..191a0a72a 100644 --- a/docs/src/content/docs/changelog.md +++ b/docs/src/content/docs/changelog.md @@ -4,7 +4,15 @@ title: Changelog ## v0.34 - *hat* -Requires libvips v8.16.1 +Requires libvips v8.17.0 + +### v0.34.3 - TBD + +* Upgrade to libvips v8.17.0 for upstream bug fixes. + +* Support composite operation with non-sRGB pipeline colourspace. + [#4412](https://github.com/lovell/sharp/pull/4412) + [@kleisauke](https://github.com/kleisauke) ### v0.34.2 - 20th May 2025 diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index 0132543e6..e6bc6a353 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.1.0" + "@img/sharp-libvips-darwin-arm64": "1.2.0-rc.1" }, "files": [ "lib" diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index 0161956a4..307e48075 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.1.0" + "@img/sharp-libvips-darwin-x64": "1.2.0-rc.1" }, "files": [ "lib" diff --git a/npm/linux-arm/package.json b/npm/linux-arm/package.json index f03525108..ff69b01e2 100644 --- a/npm/linux-arm/package.json +++ b/npm/linux-arm/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.1.0" + "@img/sharp-libvips-linux-arm": "1.2.0-rc.1" }, "files": [ "lib" diff --git a/npm/linux-arm64/package.json b/npm/linux-arm64/package.json index 9142b138b..a11592b69 100644 --- a/npm/linux-arm64/package.json +++ b/npm/linux-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.1.0" + "@img/sharp-libvips-linux-arm64": "1.2.0-rc.1" }, "files": [ "lib" diff --git a/npm/linux-ppc64/package.json b/npm/linux-ppc64/package.json index 72fd443c9..73b682ded 100644 --- a/npm/linux-ppc64/package.json +++ b/npm/linux-ppc64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.1.0" + "@img/sharp-libvips-linux-ppc64": "1.2.0-rc.1" }, "files": [ "lib" diff --git a/npm/linux-s390x/package.json b/npm/linux-s390x/package.json index d4a889371..5f0f4a7f5 100644 --- a/npm/linux-s390x/package.json +++ b/npm/linux-s390x/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.1.0" + "@img/sharp-libvips-linux-s390x": "1.2.0-rc.1" }, "files": [ "lib" diff --git a/npm/linux-x64/package.json b/npm/linux-x64/package.json index 768a0f2fa..df68dbfda 100644 --- a/npm/linux-x64/package.json +++ b/npm/linux-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.1.0" + "@img/sharp-libvips-linux-x64": "1.2.0-rc.1" }, "files": [ "lib" diff --git a/npm/linuxmusl-arm64/package.json b/npm/linuxmusl-arm64/package.json index 55ca0cf76..2b9997f05 100644 --- a/npm/linuxmusl-arm64/package.json +++ b/npm/linuxmusl-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.1.0" + "@img/sharp-libvips-linuxmusl-arm64": "1.2.0-rc.1" }, "files": [ "lib" diff --git a/npm/linuxmusl-x64/package.json b/npm/linuxmusl-x64/package.json index 9f591441a..68be43ec6 100644 --- a/npm/linuxmusl-x64/package.json +++ b/npm/linuxmusl-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.1.0" + "@img/sharp-libvips-linuxmusl-x64": "1.2.0-rc.1" }, "files": [ "lib" diff --git a/package.json b/package.json index 51a7069a4..c3f6abf0f 100644 --- a/package.json +++ b/package.json @@ -144,15 +144,15 @@ "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.2", "@img/sharp-darwin-x64": "0.34.2", - "@img/sharp-libvips-darwin-arm64": "1.1.0", - "@img/sharp-libvips-darwin-x64": "1.1.0", - "@img/sharp-libvips-linux-arm": "1.1.0", - "@img/sharp-libvips-linux-arm64": "1.1.0", - "@img/sharp-libvips-linux-ppc64": "1.1.0", - "@img/sharp-libvips-linux-s390x": "1.1.0", - "@img/sharp-libvips-linux-x64": "1.1.0", - "@img/sharp-libvips-linuxmusl-arm64": "1.1.0", - "@img/sharp-libvips-linuxmusl-x64": "1.1.0", + "@img/sharp-libvips-darwin-arm64": "1.2.0-rc.1", + "@img/sharp-libvips-darwin-x64": "1.2.0-rc.1", + "@img/sharp-libvips-linux-arm": "1.2.0-rc.1", + "@img/sharp-libvips-linux-arm64": "1.2.0-rc.1", + "@img/sharp-libvips-linux-ppc64": "1.2.0-rc.1", + "@img/sharp-libvips-linux-s390x": "1.2.0-rc.1", + "@img/sharp-libvips-linux-x64": "1.2.0-rc.1", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.0-rc.1", + "@img/sharp-libvips-linuxmusl-x64": "1.2.0-rc.1", "@img/sharp-linux-arm": "0.34.2", "@img/sharp-linux-arm64": "0.34.2", "@img/sharp-linux-s390x": "0.34.2", @@ -166,11 +166,11 @@ }, "devDependencies": { "@emnapi/runtime": "^1.4.3", - "@img/sharp-libvips-dev": "1.1.0", - "@img/sharp-libvips-dev-wasm32": "1.1.0", - "@img/sharp-libvips-win32-arm64": "1.1.0", - "@img/sharp-libvips-win32-ia32": "1.1.0", - "@img/sharp-libvips-win32-x64": "1.1.0", + "@img/sharp-libvips-dev": "1.2.0-rc.1", + "@img/sharp-libvips-dev-wasm32": "1.2.0-rc.1", + "@img/sharp-libvips-win32-arm64": "1.2.0-rc.1", + "@img/sharp-libvips-win32-ia32": "1.2.0-rc.1", + "@img/sharp-libvips-win32-x64": "1.2.0-rc.1", "@types/node": "*", "cc": "^3.0.1", "emnapi": "^1.4.3", @@ -179,12 +179,12 @@ "icc": "^3.0.0", "jsdoc-to-markdown": "^9.1.1", "license-checker": "^25.0.1", - "mocha": "^11.4.0", + "mocha": "^11.6.0", "node-addon-api": "^8.3.1", "nyc": "^17.1.0", "prebuild": "^13.0.1", "semistandard": "^17.0.0", - "tar-fs": "^3.0.8", + "tar-fs": "^3.0.9", "tsd": "^0.32.0" }, "license": "Apache-2.0", @@ -192,7 +192,7 @@ "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "config": { - "libvips": ">=8.16.1" + "libvips": ">=8.17.0" }, "funding": { "url": "https://opencollective.com/libvips" diff --git a/src/common.h b/src/common.h index 1a61e47d6..3031c629e 100644 --- a/src/common.h +++ b/src/common.h @@ -15,9 +15,9 @@ // Verify platform and compiler compatibility #if (VIPS_MAJOR_VERSION < 8) || \ - (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 16) || \ - (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 16 && VIPS_MICRO_VERSION < 1) -#error "libvips version 8.16.1+ is required - please see https://sharp.pixelplumbing.com/install" + (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 17) || \ + (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 17 && VIPS_MICRO_VERSION < 0) +#error "libvips version 8.17.0+ is required - please see https://sharp.pixelplumbing.com/install" #endif #if defined(__has_include) diff --git a/src/sharp.cc b/src/sharp.cc index ed54c501a..f41ad14f7 100644 --- a/src/sharp.cc +++ b/src/sharp.cc @@ -18,8 +18,10 @@ Napi::Object init(Napi::Env env, Napi::Object exports) { vips_init("sharp"); }); - g_log_set_handler("VIPS", static_cast(G_LOG_LEVEL_WARNING), - static_cast(sharp::VipsWarningCallback), nullptr); + for (auto domain : { "VIPS", "vips2tiff" }) { + g_log_set_handler(domain, static_cast(G_LOG_LEVEL_WARNING), + static_cast(sharp::VipsWarningCallback), nullptr); + } // Methods available to JavaScript exports.Set("metadata", Napi::Function::New(env, metadata)); diff --git a/test/unit/libvips.js b/test/unit/libvips.js index 5578ff42a..d3c06079c 100644 --- a/test/unit/libvips.js +++ b/test/unit/libvips.js @@ -179,7 +179,7 @@ describe('libvips binaries', function () { process.env.npm_config_arch = 's390x'; process.env.npm_config_libc = ''; const locatorHash = libvips.yarnLocator(); - assert.strictEqual(locatorHash, '9b2ea457de'); + assert.strictEqual(locatorHash, '3ee8908a2b'); delete process.env.npm_config_platform; delete process.env.npm_config_arch; delete process.env.npm_config_libc; From 01f6cbbaeeca05beff770a54f5d7c00c7efb4541 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Thu, 12 Jun 2025 14:48:15 +0100 Subject: [PATCH 020/115] Upgrade to sharp-libvips v1.2.0-rc.2 --- .github/workflows/ci.yml | 2 +- npm/darwin-arm64/package.json | 2 +- npm/darwin-x64/package.json | 2 +- npm/linux-arm/package.json | 2 +- npm/linux-arm64/package.json | 2 +- npm/linux-ppc64/package.json | 2 +- npm/linux-s390x/package.json | 2 +- npm/linux-x64/package.json | 2 +- npm/linuxmusl-arm64/package.json | 2 +- npm/linuxmusl-x64/package.json | 2 +- package.json | 28 ++++++++++++++-------------- test/unit/libvips.js | 2 +- 12 files changed, 25 insertions(+), 25 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a445d3fe0..e8050f87f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -219,7 +219,7 @@ jobs: contents: write name: wasm32 - prebuild runs-on: ubuntu-24.04 - container: "emscripten/emsdk:4.0.6" + container: "emscripten/emsdk:4.0.10" steps: - name: Checkout uses: actions/checkout@v4 diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index e6bc6a353..17dbc64bd 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.0-rc.1" + "@img/sharp-libvips-darwin-arm64": "1.2.0-rc.2" }, "files": [ "lib" diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index 307e48075..3ab94ac03 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.0-rc.1" + "@img/sharp-libvips-darwin-x64": "1.2.0-rc.2" }, "files": [ "lib" diff --git a/npm/linux-arm/package.json b/npm/linux-arm/package.json index ff69b01e2..83fc2f394 100644 --- a/npm/linux-arm/package.json +++ b/npm/linux-arm/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.0-rc.1" + "@img/sharp-libvips-linux-arm": "1.2.0-rc.2" }, "files": [ "lib" diff --git a/npm/linux-arm64/package.json b/npm/linux-arm64/package.json index a11592b69..9cb57d087 100644 --- a/npm/linux-arm64/package.json +++ b/npm/linux-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.0-rc.1" + "@img/sharp-libvips-linux-arm64": "1.2.0-rc.2" }, "files": [ "lib" diff --git a/npm/linux-ppc64/package.json b/npm/linux-ppc64/package.json index 73b682ded..868d14759 100644 --- a/npm/linux-ppc64/package.json +++ b/npm/linux-ppc64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.2.0-rc.1" + "@img/sharp-libvips-linux-ppc64": "1.2.0-rc.2" }, "files": [ "lib" diff --git a/npm/linux-s390x/package.json b/npm/linux-s390x/package.json index 5f0f4a7f5..7f920b546 100644 --- a/npm/linux-s390x/package.json +++ b/npm/linux-s390x/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.2.0-rc.1" + "@img/sharp-libvips-linux-s390x": "1.2.0-rc.2" }, "files": [ "lib" diff --git a/npm/linux-x64/package.json b/npm/linux-x64/package.json index df68dbfda..372cdd641 100644 --- a/npm/linux-x64/package.json +++ b/npm/linux-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.0-rc.1" + "@img/sharp-libvips-linux-x64": "1.2.0-rc.2" }, "files": [ "lib" diff --git a/npm/linuxmusl-arm64/package.json b/npm/linuxmusl-arm64/package.json index 2b9997f05..3fc921adf 100644 --- a/npm/linuxmusl-arm64/package.json +++ b/npm/linuxmusl-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.0-rc.1" + "@img/sharp-libvips-linuxmusl-arm64": "1.2.0-rc.2" }, "files": [ "lib" diff --git a/npm/linuxmusl-x64/package.json b/npm/linuxmusl-x64/package.json index 68be43ec6..089e4cf37 100644 --- a/npm/linuxmusl-x64/package.json +++ b/npm/linuxmusl-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.0-rc.1" + "@img/sharp-libvips-linuxmusl-x64": "1.2.0-rc.2" }, "files": [ "lib" diff --git a/package.json b/package.json index c3f6abf0f..93100990c 100644 --- a/package.json +++ b/package.json @@ -144,15 +144,15 @@ "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.2", "@img/sharp-darwin-x64": "0.34.2", - "@img/sharp-libvips-darwin-arm64": "1.2.0-rc.1", - "@img/sharp-libvips-darwin-x64": "1.2.0-rc.1", - "@img/sharp-libvips-linux-arm": "1.2.0-rc.1", - "@img/sharp-libvips-linux-arm64": "1.2.0-rc.1", - "@img/sharp-libvips-linux-ppc64": "1.2.0-rc.1", - "@img/sharp-libvips-linux-s390x": "1.2.0-rc.1", - "@img/sharp-libvips-linux-x64": "1.2.0-rc.1", - "@img/sharp-libvips-linuxmusl-arm64": "1.2.0-rc.1", - "@img/sharp-libvips-linuxmusl-x64": "1.2.0-rc.1", + "@img/sharp-libvips-darwin-arm64": "1.2.0-rc.2", + "@img/sharp-libvips-darwin-x64": "1.2.0-rc.2", + "@img/sharp-libvips-linux-arm": "1.2.0-rc.2", + "@img/sharp-libvips-linux-arm64": "1.2.0-rc.2", + "@img/sharp-libvips-linux-ppc64": "1.2.0-rc.2", + "@img/sharp-libvips-linux-s390x": "1.2.0-rc.2", + "@img/sharp-libvips-linux-x64": "1.2.0-rc.2", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.0-rc.2", + "@img/sharp-libvips-linuxmusl-x64": "1.2.0-rc.2", "@img/sharp-linux-arm": "0.34.2", "@img/sharp-linux-arm64": "0.34.2", "@img/sharp-linux-s390x": "0.34.2", @@ -166,11 +166,11 @@ }, "devDependencies": { "@emnapi/runtime": "^1.4.3", - "@img/sharp-libvips-dev": "1.2.0-rc.1", - "@img/sharp-libvips-dev-wasm32": "1.2.0-rc.1", - "@img/sharp-libvips-win32-arm64": "1.2.0-rc.1", - "@img/sharp-libvips-win32-ia32": "1.2.0-rc.1", - "@img/sharp-libvips-win32-x64": "1.2.0-rc.1", + "@img/sharp-libvips-dev": "1.2.0-rc.2", + "@img/sharp-libvips-dev-wasm32": "1.2.0-rc.2", + "@img/sharp-libvips-win32-arm64": "1.2.0-rc.2", + "@img/sharp-libvips-win32-ia32": "1.2.0-rc.2", + "@img/sharp-libvips-win32-x64": "1.2.0-rc.2", "@types/node": "*", "cc": "^3.0.1", "emnapi": "^1.4.3", diff --git a/test/unit/libvips.js b/test/unit/libvips.js index d3c06079c..434be9e15 100644 --- a/test/unit/libvips.js +++ b/test/unit/libvips.js @@ -179,7 +179,7 @@ describe('libvips binaries', function () { process.env.npm_config_arch = 's390x'; process.env.npm_config_libc = ''; const locatorHash = libvips.yarnLocator(); - assert.strictEqual(locatorHash, '3ee8908a2b'); + assert.strictEqual(locatorHash, 'e23686d7dd'); delete process.env.npm_config_platform; delete process.env.npm_config_arch; delete process.env.npm_config_libc; From 751f9992c4d1e6bba33ff2a90caae427197a25e5 Mon Sep 17 00:00:00 2001 From: "Michael B. Klein" Date: Tue, 12 Nov 2024 11:32:41 -0600 Subject: [PATCH 021/115] Expose JPEG 2000 oneshot decoder option #4262 Requires libvips compiled with support for JP2 images Co-authored-by: Kleis Auke Wolthuizen --- docs/src/content/docs/api-constructor.md | 1 + docs/src/content/docs/changelog.md | 4 +++ lib/constructor.js | 1 + lib/index.d.ts | 2 ++ lib/input.js | 14 ++++++++-- src/common.cc | 10 +++++++ src/common.h | 4 ++- test/fixtures/index.js | 1 + test/fixtures/relax_tileparts.jp2 | Bin 0 -> 10218 bytes test/types/sharp.test-d.ts | 3 ++ test/unit/jp2.js | 34 +++++++++++++++++++++-- 11 files changed, 67 insertions(+), 7 deletions(-) create mode 100644 test/fixtures/relax_tileparts.jp2 diff --git a/docs/src/content/docs/api-constructor.md b/docs/src/content/docs/api-constructor.md index 8010b58ba..b5b7a9c85 100644 --- a/docs/src/content/docs/api-constructor.md +++ b/docs/src/content/docs/api-constructor.md @@ -47,6 +47,7 @@ where the overall height is the `pageHeight` multiplied by the number of `pages` | [options.subifd] | number | -1 | subIFD (Sub Image File Directory) to extract for OME-TIFF, defaults to main image. | | [options.level] | number | 0 | level to extract from a multi-level input (OpenSlide), zero based. | | [options.pdfBackground] | string \| Object | | Background colour to use when PDF is partially transparent. Parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick. | +| [options.jp2Oneshot] | boolean | false | Set to `true` to decode tiled JPEG 2000 images in a single operation, improving compatibility. | | [options.animated] | boolean | false | Set to `true` to read all frames/pages of an animated image (GIF, WebP, TIFF), equivalent of setting `pages` to `-1`. | | [options.raw] | Object | | describes raw pixel input image data. See `raw()` for pixel ordering. | | [options.raw.width] | number | | integral number of pixels wide. | diff --git a/docs/src/content/docs/changelog.md b/docs/src/content/docs/changelog.md index 191a0a72a..f84859d80 100644 --- a/docs/src/content/docs/changelog.md +++ b/docs/src/content/docs/changelog.md @@ -10,6 +10,10 @@ Requires libvips v8.17.0 * Upgrade to libvips v8.17.0 for upstream bug fixes. +* Expose JPEG 2000 `oneshot` decoder option. + [#4262](https://github.com/lovell/sharp/pull/4262) + [@mbklein](https://github.com/mbklein) + * Support composite operation with non-sRGB pipeline colourspace. [#4412](https://github.com/lovell/sharp/pull/4412) [@kleisauke](https://github.com/kleisauke) diff --git a/lib/constructor.js b/lib/constructor.js index d94900683..c70bbf1e4 100644 --- a/lib/constructor.js +++ b/lib/constructor.js @@ -156,6 +156,7 @@ const debuglog = util.debuglog('sharp'); * @param {number} [options.subifd=-1] - subIFD (Sub Image File Directory) to extract for OME-TIFF, defaults to main image. * @param {number} [options.level=0] - level to extract from a multi-level input (OpenSlide), zero based. * @param {string|Object} [options.pdfBackground] - Background colour to use when PDF is partially transparent. Parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick. + * @param {boolean} [options.jp2Oneshot=false] - Set to `true` to decode tiled JPEG 2000 images in a single operation, improving compatibility. * @param {boolean} [options.animated=false] - Set to `true` to read all frames/pages of an animated image (GIF, WebP, TIFF), equivalent of setting `pages` to `-1`. * @param {Object} [options.raw] - describes raw pixel input image data. See `raw()` for pixel ordering. * @param {number} [options.raw.width] - integral number of pixels wide. diff --git a/lib/index.d.ts b/lib/index.d.ts index a8f1d98df..9ed7190dd 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1009,6 +1009,8 @@ declare namespace sharp { level?: number | undefined; /** Background colour to use when PDF is partially transparent. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick. */ pdfBackground?: Colour | Color | undefined; + /** Set to `true` to load JPEG 2000 images using [oneshot mode](https://github.com/libvips/libvips/issues/4205) */ + jp2Oneshot?: boolean | undefined; /** Set to `true` to read all frames/pages of an animated image (equivalent of setting `pages` to `-1`). (optional, default false) */ animated?: boolean | undefined; /** Describes raw pixel input image data. See raw() for pixel ordering. */ diff --git a/lib/input.js b/lib/input.js index d9d29f3a7..59de9a6c3 100644 --- a/lib/input.js +++ b/lib/input.js @@ -27,9 +27,9 @@ const align = { * @private */ function _inputOptionsFromObject (obj) { - const { raw, density, limitInputPixels, ignoreIcc, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd, pdfBackground, autoOrient } = obj; - return [raw, density, limitInputPixels, ignoreIcc, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd, pdfBackground, autoOrient].some(is.defined) - ? { raw, density, limitInputPixels, ignoreIcc, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd, pdfBackground, autoOrient } + const { raw, density, limitInputPixels, ignoreIcc, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd, pdfBackground, autoOrient, jp2Oneshot } = obj; + return [raw, density, limitInputPixels, ignoreIcc, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd, pdfBackground, autoOrient, jp2Oneshot].some(is.defined) + ? { raw, density, limitInputPixels, ignoreIcc, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd, pdfBackground, autoOrient, jp2Oneshot } : undefined; } @@ -250,6 +250,14 @@ function _createInputDescriptor (input, inputOptions, containerOptions) { if (is.defined(inputOptions.pdfBackground)) { inputDescriptor.pdfBackground = this._getBackgroundColourOption(inputOptions.pdfBackground); } + // JP2 oneshot + if (is.defined(inputOptions.jp2Oneshot)) { + if (is.bool(inputOptions.jp2Oneshot)) { + inputDescriptor.jp2Oneshot = inputOptions.jp2Oneshot; + } else { + throw is.invalidParameterError('jp2Oneshot', 'boolean', inputOptions.jp2Oneshot); + } + } // Create new image if (is.defined(inputOptions.create)) { if ( diff --git a/src/common.cc b/src/common.cc index abbfe705e..57ae4aef5 100644 --- a/src/common.cc +++ b/src/common.cc @@ -113,6 +113,10 @@ namespace sharp { if (HasAttr(input, "pdfBackground")) { descriptor->pdfBackground = AttrAsVectorOfDouble(input, "pdfBackground"); } + // Use JPEG 2000 oneshot mode? + if (HasAttr(input, "jp2Oneshot")) { + descriptor->jp2Oneshot = AttrAsBool(input, "jp2Oneshot"); + } // Create new image if (HasAttr(input, "createChannels")) { descriptor->createChannels = AttrAsUint32(input, "createChannels"); @@ -434,6 +438,9 @@ namespace sharp { if (imageType == ImageType::PDF) { option->set("background", descriptor->pdfBackground); } + if (imageType == ImageType::JP2) { + option->set("oneshot", descriptor->jp2Oneshot); + } image = VImage::new_from_buffer(descriptor->buffer, descriptor->bufferLength, nullptr, option); if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) { image = SetDensity(image, descriptor->density); @@ -541,6 +548,9 @@ namespace sharp { if (imageType == ImageType::PDF) { option->set("background", descriptor->pdfBackground); } + if (imageType == ImageType::JP2) { + option->set("oneshot", descriptor->jp2Oneshot); + } image = VImage::new_from_file(descriptor->file.data(), option); if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) { image = SetDensity(image, descriptor->density); diff --git a/src/common.h b/src/common.h index 3031c629e..b926972bf 100644 --- a/src/common.h +++ b/src/common.h @@ -78,6 +78,7 @@ namespace sharp { VipsAlign joinHalign; VipsAlign joinValign; std::vector pdfBackground; + bool jp2Oneshot; InputDescriptor(): autoOrient(false), @@ -120,7 +121,8 @@ namespace sharp { joinBackground{ 0.0, 0.0, 0.0, 255.0 }, joinHalign(VIPS_ALIGN_LOW), joinValign(VIPS_ALIGN_LOW), - pdfBackground{ 255.0, 255.0, 255.0, 255.0 } {} + pdfBackground{ 255.0, 255.0, 255.0, 255.0 }, + jp2Oneshot(false) {} }; // Convenience methods to access the attributes of a Napi::Object diff --git a/test/fixtures/index.js b/test/fixtures/index.js index f5b686ad7..b69d64656 100644 --- a/test/fixtures/index.js +++ b/test/fixtures/index.js @@ -117,6 +117,7 @@ module.exports = { inputTiffFogra: getPath('fogra-0-100-100-0.tif'), // https://github.com/lovell/sharp/issues/4045 inputJp2: getPath('relax.jp2'), // https://www.fnordware.com/j2k/relax.jp2 + inputJp2TileParts: getPath('relax_tileparts.jp2'), // kdu_expand -i relax.jp2 -o relax-tmp.tif ; kdu_compress -i relax-tmp.tif -o relax_tileparts.jp2 -jp2_space sRGB Clayers=8 -rate 1.0,0.04 Stiles='{128,128}' ORGtparts=L ; rm relax-tmp.tif inputGif: getPath('Crash_test.gif'), // http://upload.wikimedia.org/wikipedia/commons/e/e3/Crash_test.gif inputGifGreyPlusAlpha: getPath('grey-plus-alpha.gif'), // http://i.imgur.com/gZ5jlmE.gif inputGifAnimated: getPath('rotating-squares.gif'), // CC0 https://loading.io/spinner/blocks/-rotating-squares-preloader-gif diff --git a/test/fixtures/relax_tileparts.jp2 b/test/fixtures/relax_tileparts.jp2 new file mode 100644 index 0000000000000000000000000000000000000000..62621c6890a56b6541ea625962e72beb8f18ad6d GIT binary patch literal 10218 zcmaiY1wd5W7WUBH-9v|TNW&oAARW>mUD6VV2I)o+=}_qw5r#%UKqLeKX+cCra_E2H zzWeUG|9}7Y&VkwIto^OE_KLmE-Wvo0;X3Pp!FbrQ*dP#y)WIjv)7euHjCcn9tK~to zj)+%sCr3MPL<<9fkRTuw3=E`O5P_|StM}a#i179u0k*x-zR?Bo-M%4!cMP}BcNc*8 zz5V~=Lcu^n`s45BAqW>i!$d+uMFoLw%t6dd{`7u75O=2s$OGiQ_E-aP+v%VnZbhRh z#BF_J2O9g8U~zkoP`#iU9fArr*=)du!{f~Y`Q2r}F%Kzv` zbc5KD5aS=GB>ZSasxbBcH-qICHpWlHgz?XqTT@u?Fc2b>5z~JL-P&^}XdIVtDeRvy zw>B}~2?8_Z{xjs(tUEEoP$CPPf5spnAa>+GLQ@(I!nNfGwEm9#D?%TMW zw!dFr0RT$CR84`sxb9 zN)LK`y&%NkA#5$;B>%UJ+Z5%wm2m`ia_)7t1TVipzLflA6l4V|~7yv3UEA&+z z|CD_<+FO5`-wH)gVQH%%jFxH>;^Mv*04QY>(_tt)-!i7bxL+NpM@uP%@Um`)Sgdpb zMtkSOu-@-126~=uEPA~=rF#4yq5@e2Zl9SO!RBt>bPYA0E(0FadA_b9h{OG+UWkY5z+oTC{A|*tenD~dOkr|`W~W$ z_w<2q>BijBH{i-qWpk_;0fJ%;2**JcBoYMxO3VqRSB!dz%+JkeIKo6E44taVvkTVQ z*a;*baGfF&6ft9jP&w?k{?v7+=r)ube~gr|Z-o#;tU}<={y*D0+-)!wZ*g!islzI$ z?mYmLBE+cV0)Q?g2<}9E{|o>Onu_Tp3GEn}%n&3gg@%`}_kI8O^t=;t8@z}+A&~RE z_}rdVfTFElY5<{_lI(^h;Y4%QlOI-OqEy77PV46Y0PtE0u;{FTH=`D7quxXmPeV(K zb5I^S9@Swl0IW+?dqUg>eYJLw@f6D+q7S;+mCT}yG#!1NT9|Kw#4$}1yqusMw*Q+M zhyj4|&~DQQ205JSy<82JlR<*CvOZ|_j01QgGc8AgV*xADqK|bz7;!$r{&kZMEcTW`(ALdFl@0KYjl;vfGpiyB!$}j0N=a07c43 zgqWRgNgo$^T49H8_e`}1TVV(rFj=g(cQR+1nkH@7di5T7^t`MQMd(e4d4*p@9dqE` zOnv^14ed8w137AIq)tnXDBkW&cU%@DIq}L4Do|*iru1|9AzbP5`oBG?D*mA4> z5(z+I7gz;-*8x_2WH3iWTM9Nf&Wl!76d2x~vRD)`fzUM$qOLfqqtjewV`uem*j|p7 z1&%b_k8BXV)Qx!LUbYD<=nkBIRg|bX&Io2-DyuA>R-=ankSLVA{aZx{h! z7;5T*b~o;SC$GaFK63FJpQ?|@NR@KCD0c={yK zZxIM#!Hl@KDl78%h+OK949ivJ=0H;$gh_(6ay?>kA7NYLM0bDR3(w_5t!v{ry= znAMI{;E@(aWCL%Ls?Bw5Mh^@VM4=P^3A$ZGi9H+n7QW0r1Tz0kuBe#g+WA=GB>GE@ zYVw-&VVeZW38z_txTc8lq*$igxflSP?T6zQNx6#<(w81ZEF^|L8ag>#U}y^@mi~DB zTu75#o~wXZuA)Fcmfz@|Y1K3BZ5ds3Wu-3utpytJZF#fI0ESIHvBpN(*W3{-}d^XpmsJ)Ai9G1?t~(aOKvTBmOhCcQ1K~t( znc!BZJ7Y!H=&hV;_bH%99iJ`aWc$lS;%GJ1h#x-N42tSdrv`vS?V$e1=ou8fF}F@V zrC@qzbaM@I(a*@#o5-oiPjXCByCaR zNO|+t$E;75K{3W9d|eGHH-F|-xIFGnp`u*!S56>;g_MVWo5;wZy{})rjv%>RwqO`U zMC3>dC*rG^wZ$||@d%VCTauJGnb#Th)T0iR)*Z3?lIwpR|a66 zeatEKqf+;0vi0x$&bZD5{W-qR?jbH2A)U}w@D7NDRe+m*?Weu7=WA?eHo6t=*333Q zN!pP$`@AIJo4R1~$@*&`b1ye>n0?i(@MH z2~c2=Vk*MxxnwrjL9IpEI%7;I&MKM1c*64&|7g|n`d-e1RqAr(0i&)TI^H|MWOheB zP|RJ9OnBh9wzmB@!c;AJ*FI!^4HHL)Njsd$-25@=Q8@9pbZXe-MkVGIZZ@Jezmvf; z4^2>l>eqko`5oaR=*F0O{;^mhE`oF#8i}DY=Oqk{Vn|%UpycAnOYi7V%(KINh|-rg zmyzh&o03nB>T=mmF`1{*$+Z5_Mk&FDGw_nh0%yyvS7*Y$vVjXCM4Q6EKQc~akgZUN zS_vHti<*&#fDjZVIZDe5J?n?+X){FQO1n|IQL1CCyo@>2dbGyc%!N@)w z5aRD0YpnRI&;TuLWJ1!cb&Ygdvb7@*plIFjsSaS3n8pejlbq7sdvl!5Eb>MAgsDbOpJuk* z+9{()>>8*EbyaAJ8|7ygLQ~jjnnlZlk6v>7rnp|B7KG=U_Qq*d&WAt!Wx-cP8TMvK z6@B;TqU~~*7F&tXD1~whFQDGQOqK&t04K6 z$cjP$!GPzQ+)&EEyDb-Do)a~H8_6nKA35y-KWU2&Fu)qB036DXxPJl#LM24GL#}g{ z2lvL+i54BDcP^Z5YHNk;Y2LIviYN`5hS&35d8gM=w=;Orv{S`*_6(PjhY5h5^a|o& zmtzU;)}Elavc9qS-s{DwD_Ao{_?eHWp{0*-zV3c~P2>|aspLFs=rvs*1;P$$S~sg* zuHP#$iz*Z8MPb@wNQ4npduO$*HXQrina))D!iS2{*ixFW9i z_86uvOgsK^C}K&4L8D1s{`WXTy!?ph$`qoseh> zm-x+5)%q5I%B|WFcBs}?A=WYGbOb=RhY10qZf~8;A+nRm_~W8<^WRfmQ@P#N<76A^ zv~Pr?gqGN?+2-F=H5hyB@Be=PE$!>>Gxf$KYvhmD`2#;DO(&ZcHS(>DFL8qt`1A;} z?gM&>m`BEFFf3XB6~v;^7xPysbrC&$#}k}2q|1DiX&L|ahhwWkDz@daGV(n-C5?hi zv?&fV)s%07Y3i-iyAu#|jTgVzT!u8UjJ`R5yXlNh=LRZ01e+i1+iogVr>)1W_ckbfhbM!Fz4Bgx?4`k2#Woj9@OAa35~UgUh2DBT7pDMKimxC& zISb?V3z)LM)Z_Ea03Ro0P0|!(3BQ%c0|IJL=Ik#hMC&RR-Cu~>BVHV<(N#Om|K)1L zry1$&*41#Z`n@AaBzI@T5x*{hI_wci56J4c6Gos?G^{CjwZ;$I$H#gv`4W3ID5psa^YA~#gj>`X9SfXg;L6rWrP{HDDGTk>fX?v%Aae2-6dU~Xv^Z06mqp2jAb z{dl|2{BZJ<#&uhLaB0ntPKNL|-Y@rwH)6Z~FfH@l9(`O#e@HSeS_~UDXn0Q&r30?~A+i~iMS}}v0 zT4guI+GAI_K8LMMTs`6GZ3^RkfGxf6oJm&g+X-PL5d~!uE_}eQiL`c(&UH#WR+tOr zls0-o@T4N6e!FkUNz}I;-$l@uCXyDPZ zsx!x2%{^NW4a*3+)Ko{~b*$GQRLfWae+3?~lR%=oD_XsyNBnaor0p^>CaP+_0&-Am zFh4+XK_?HjhI)F^;nL}ZQ6VQWsMf*9*~>wzN$E*HPL;aLp7PdN%ZicAGNLJ#d{E1I zUW=^Hn@9!#NBbP#fzzGbIj1)@bIuZUhYfvNOm*&<{nYr(LiVXPg(C0{6C4_PLKEp{ zzw-=`KRGwXYqev%{M89F{Y4~8;I#+(;G{>3^#J|KiXRK zb3V7jKQcXeA|mo0>z(7Tc>LMPH4Sp7G(iK?>+L~9e%^J0uznp_u0-;i4VBW3e zUl$S}7DB~dYeR@8tS7AyF4jpIwYtY>Z{}BYq!k}^Kd;iGPYHGphY;=&C#s;Dl{1SQ zDyd7Y67eoN0YY_&3GaFlGbmucb6<0sX*1Qz?1KLn0$Ai?Oy)sEvmA-*q4=Uz8TF75R+VU(UV1}8B5)U_gG4UP0KCkX8 z=xa?p9=rvrElUzfJf1w+%#$PQuT3mW>W2A+ad@c!p%PNl`=zTbR^r;9cyTQK~lUjPQT6Q zt5C0$QAgd}wrRnj#($xEK9&+&3Yjl)XsmDIeBTzVviSpQ9^qr@gJKh&mde=^fW>ph zN*U#vU56EmMf2;IDz;yvR6jRi?M&A!XVkfMpV3HMa{%_BazSfga2@ujm1446oZ5x` zE0TJzFPNRDpQ?;M>--9MHYcgFEa7aAwq@#!ecpvsnRP0Gn)}KHM)D!fOU|y;XQqx@ z`N(%b>5`(6EOUhe0ui=K0+`m}@8q5B+6(C3$Lg_bT4XZF0UZgwFw{LV{>I)(cp`-q=Gjk>S ztUjCM&B4-|fNmt=6Gz@j@A=0V8@NR;-qB(_%DETy0lmatj@G+hWs+u07F3so%F%*m z+?!6F4$)*LCcF5^!cx;rKHT^da-RY>FDoVVKwFn9Pj6lO+QTOgv_~%6t?29Yv9I)@ z%?-txjp8@1C3*b(U1cfBAi*=g{p%K#Z4)BF;}_GMHXj05?S13ysp7kRB=;G8&1vd} z!FwhnO9wm;N3%UfrBDM6MU@_Tza^O#XdL_OQ|9b{{S}#)nf#MZLBZ>>9jB6loR}@8 zboxP7Jc|HGqazC#G_iBH5+DE{ziV<#Ocp8W+qbh?Xx;m#u+`& zlY7EVeEdc6p6c_;ts~BMav&OSRC8KH>E*hHH?Eib$9y$&mjhyIgFPq89b*)MKaQ0U zOK{|aKPm%AiNE(F3~Y;7e}hlvIw<7T5AG8|U@{nM=*QuE!G~}UoF2rXW2^($w~qmi zPOYWjaVT899~fgq`p_(@XU$!;KkShIeTkrp?-)IO+p4((I&g{ZlMS=+q{ePlviRV^%<6Yj zdCGvM8S&@)Py5sr1j7U5$kr(rl_YZ#8bZP1m^vHZ23A=Q9e%MWI@B>7_!Q;}UJ1UQ z6VvZG@qxZXuci7Js2xQ^$>98ef3FUM)0wmX+FopWcw|Z@6~}D12iAhodx=kKo@gws z4W)^UCOvx}`h;)20+lV8&lO{_9=OL#k&B&Ak$%-!vT(qWYJe3bgg<5+H+zg1@SfHk zq7Pp86hDdBo#-ismT!JP#uC(#u*IkRhKvCDV;B-A=!!iC6qtdSjhZj5R-e4mG z^EACth?pIC_jhtZsHZNgDVa2W1o9lbn#+`8nW>(=rY$T$B5u6C5NpyVVsG-Q?syc# zCU|qc>N2WiIBp~|xXD1hf$r7T64UHCd)Y#w^&nYZRa*2*vF_ba@lu;i29^{I(nRYi!ur_Kj@o$=Ufkwx0nU9sa)NN<1xX{|!%+~802h!`hS>dI1A z(~yk=Hynjk?-o;}&FxM`^wSW%>1vL$g_4ilGYUML?E7|$S2cAS{p{Am=ge1lDMbwU zVtZ8f`{QH2?xD=7WCez15S_p)#Re;VxvKjblA#c!V^ zu7g9#TsQ{T+9pw>o)i{SH8u4d_uC86g=qr5hO$Rg6rNFeLvlKz5On1 z@>Ii?gQ&{f2^DYG-W==EdSxDl*2a?*)n=;``r=2;wsX2e;1=BK78&|&T+>7Tn6vPf z5mi8KaYI@e^dhW?k6KY>z*1Dzeaa!l)Vg0?_&bx{0$x*b{&?rZ#>BGj6|Re%Z1Erd zB1E4v>aif5Ds+5EX$tu~$UcV49Fh;OFzUjD67hA@FFH$?*wiL(HN~$U%&8qli}+CZW+# zqH03EQ`f)d4q_vVoO?TWVBqyjE2v7u4B|JY4+&;YFo?;aScqGV_;~2x<1#Wiqcsad zrPxs>Aq03mo(r-^mOyf1N#Wx0P`!f+?b_C+hQYV2@aheyPXK-f(kCcmx~t-#^h*Mh z9`ovRT$yAl%f!zzc~zrGQ63|Na_!R}8m1&JG0($dC z`RNYKCa08Mjsl)aye95)Xiy&T9c zT+=4uX3nB&kOT5I%I7a4}X=bD-zDLgygNfb{te@kO zLFLL!rQ8;JNX_91_?V*#|tt>JavLZ zyW~k!n($X#eRGU(DI>VY6ze>P-=l?r;I$?Ae&kvUgYvdpTm#}dai%ZGF> z`1E{H(TP##!B0TW4<@<@WUz8YndAeF99A*>Dp9Qcc*C191jlG=3~8TKyGn4?ox0^D zpN0i@l*Yzq7?)}2?y-}H?5J1g3{Kj`lxFn?zw6o{s#%kYZTzKmCY8)xLg~~bH)1f+ zVURj7Hisp$B>DN;?Kxh8xH#*)*7aNSw_2N8?ka_#dj3sc!N2x5h+RL*}@2X6cH!cz)^4TkUU%lqZptU+h!Pi5xWYP#SWGAG996s4)J1{xJ35hjX4Uc zstse3(tHiCef}Br8I}80FG`maKBdm0*Zb<`w-4wEj@5Qmj#DY=$t6$5>Nt*u@g-2e z-%x1E0XM3iA$ngastoD|);TjA{4;9ejy9%E>FQb6Fztg(3_V~6TI=NZ;Y=MT<(=H6 z=DV*hz0yY1XPft8x);#+d|Ld9RB1e2GyG{#i(cqDe+kv&BvYP7JF0sVR6UP}?po3C z2G3(cLF>afH73C+?gls{s->IRXR^<+jOfx#h>5Q-D?JyrA)#*}D6bGA(pwXL!_12P zs5XyvQ;IdlqeYqHP@6;PKnzd{vCCJ;RMfdJPkWgejSI7tFB#ew(mhF-^Geg@P^r~$>5H9vg@UsSI>v6> zGbiA$lQW+qy?N>Can8_ZQa@z=TGz!OI0^tf-AJb^Vz1Orn(qgu#-{rzL zZjRKk*}XD`4{#8>?x`{ttG=(gmT|$T%A>l(){Sk@6ZVN4){Rd9fih1a38-m1Om4gr zc`bh@*|yD|{AjOqm220z07Q0nKDB1~)B5ugMb4{d44Ug&^T^kE2_9Uc;n-RJ{13%> zZ1C44yM7MLZ_<~54>G8R?(sXo8>_?SVQ%MeOj3lXmY=CQ&-tsJB4#5}s6S%y707aQ{# zj+SvUc{#%v7Nntxho9A8 zD?F9ct9_Kh($R)Ed%O>s_Sn==qvsl_nk{iZH;N{lz^^kHEyPk?=0y&%XIB53m7=D5 zT35_)ZdrxlBZc!KpzvScB*eiFa^=6)bJuPeFPJZ_A(5FGbRS_>kslY1EaMnZ*E0?_ z^Rv{(^9wJLp~2Q2lsC*HA`%2P<+26r1Fs%lBE!Xi&BUQ~f28%cZP}v<;09+M<+Ia5 zgU7^fDSQ7yNBfu^hZ9>ly6}07R4T0}GSB#k@;AEz8On!R4I zi4W?fL&t`)LaGJpf+d89wa3(RZs9cg;s$5|x2r^0X4I=|F?Xg1EQTwJ#}bQX8< zaH*U9?JG`P3h%lxc+}&&tsrT9y!x{+l*~O+GYVmwG=-eNFq+MCFq@w~N4A)Vzq}Bp3e^@p;a!v7v5ChUaw%`Rj-CTu{&xyOQT_fxOE7CDu&lNi0szQOb>uiAW* zv{jrVBqGB-8QdqZM`g1%9F#}X&}&soY>)C|VwJNoSwgkly-gHJg(oGzk7lK>HMBUB zC^*E8LM<)$PFr@Mp;1&h*Y1xM4?_5aclyI4XZ!@SGAh18yVeg22~R68%_1D~r_y|1 zhL;TbsgIm97_t`lm6PF?1mf-1g6GA?J>%O*g1(Z}NPDA*&o!rU+=zU7{-er8DJ_WA zPcaFZqf$APm{Pkyj<)oZn);){GMuPJ_ploeEW??RoG&BAt#2bhIX4l+lf(= { }); }); - it('Invalid JP2 chromaSubsampling value throws error', function () { - assert.throws(function () { - sharp().jpeg({ chromaSubsampling: '4:2:2' }); + it('can use the jp2Oneshot option to handle multi-part tiled JPEG 2000 file', async () => { + const outputJpg = fixtures.path('output.jpg'); + await assert.rejects( + () => sharp(fixtures.inputJp2TileParts).toFile(outputJpg) + ); + await assert.doesNotReject(async () => { + await sharp(fixtures.inputJp2TileParts, { jp2Oneshot: true }).toFile(outputJpg); + const { format, width, height } = await sharp(outputJpg).metadata(); + assert.strictEqual(format, 'jpeg'); + assert.strictEqual(width, 320); + assert.strictEqual(height, 240); }); }); + + it('Invalid JP2 chromaSubsampling value throws error', () => { + assert.throws( + () => sharp().jp2({ chromaSubsampling: '4:2:2' }), + /Expected one of 4:2:0, 4:4:4 but received 4:2:2 of type string/ + ); + }); } + + it('valid JP2 oneshot value does not throw error', () => { + assert.doesNotThrow( + () => sharp(fixtures.inputJp2TileParts, { jp2Oneshot: true }) + ); + }); + + it('invalid JP2 oneshot value throws error', () => { + assert.throws( + () => sharp(fixtures.inputJp2TileParts, { jp2Oneshot: 'fail' }), + /Expected boolean for jp2Oneshot but received fail of type string/ + ); + }); }); From 327a6d20836c82ed2787027e716c04bbb81ae9aa Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Fri, 13 Jun 2025 11:48:32 +0200 Subject: [PATCH 022/115] Docs: update link to concurrency API (#4414) --- docs/src/content/docs/install.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/content/docs/install.md b/docs/src/content/docs/install.md index 69d1c1064..41c18714e 100644 --- a/docs/src/content/docs/install.md +++ b/docs/src/content/docs/install.md @@ -175,7 +175,7 @@ The default memory allocator on most glibc-based Linux systems processes that involve lots of small memory allocations. For this reason, by default, sharp will limit the use of thread-based -[concurrency](api-utility#concurrency) when the glibc allocator is +[concurrency](/api-utility#concurrency) when the glibc allocator is detected at runtime. To help avoid fragmentation and improve performance on these systems, From 5374b036f31c7536c78af2452315a624e2f40143 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Fri, 13 Jun 2025 12:59:52 +0100 Subject: [PATCH 023/115] CI: Switch ARM64 from CircleCI to GitHub Actions --- .circleci/config.yml | 105 --------------------------------------- .cirrus.yml | 2 +- .github/workflows/ci.yml | 37 +++++++++++++- 3 files changed, 37 insertions(+), 107 deletions(-) delete mode 100644 .circleci/config.yml diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index a29034945..000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,105 +0,0 @@ -version: 2.1 - -workflows: - build: - jobs: - - linux-arm64-glibc-node-18: - filters: - tags: - only: /^v.*/ - - linux-arm64-musl-node-18: - filters: - tags: - only: /^v.*/ - - linux-arm64-glibc-node-20: - filters: - tags: - only: /^v.*/ - - linux-arm64-musl-node-20: - filters: - tags: - only: /^v.*/ - -jobs: - linux-arm64-glibc-node-18: - resource_class: arm.medium - machine: - image: ubuntu-2204:current - steps: - - checkout - - run: | - sudo docker run -dit --name sharp --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp arm64v8/debian:bullseye - sudo docker exec sharp sh -c "apt-get update && apt-get install -y build-essential git python3 curl fonts-noto-core" - sudo docker exec sharp sh -c "mkdir -p /etc/apt/keyrings" - sudo docker exec sharp sh -c "curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg" - sudo docker exec sharp sh -c "echo 'deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_18.x nodistro main' | tee /etc/apt/sources.list.d/nodesource.list" - sudo docker exec sharp sh -c "apt-get update && apt-get install -y nodejs" - - run: sudo docker exec sharp sh -c "npm install --build-from-source" - - run: sudo docker exec sharp sh -c "npm test" - - run: | - sudo docker exec sharp sh -c "npm run package-from-local-build" - sudo docker exec sharp sh -c "npm pkg set \"optionalDependencies.@img/sharp-linux-arm64=file:./npm/linux-arm64\"" - sudo docker exec sharp sh -c "npm run clean" - sudo docker exec sharp sh -c "npm install --ignore-scripts" - sudo docker exec sharp sh -c "npm test" - - run: "[[ -n $CIRCLE_TAG ]] && sudo docker exec --env prebuild_upload sharp sh -c \"cd src && ln -s ../package.json && npx prebuild --upload=$prebuild_upload\" || true" - linux-arm64-glibc-node-20: - resource_class: arm.medium - machine: - image: ubuntu-2204:current - steps: - - checkout - - run: | - sudo docker run -dit --name sharp --workdir /mnt/sharp arm64v8/debian:bullseye - sudo docker exec sharp sh -c "apt-get update && apt-get install -y build-essential git python3 curl fonts-noto-core" - sudo docker exec sharp sh -c "mkdir -p /etc/apt/keyrings" - sudo docker exec sharp sh -c "curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg" - sudo docker exec sharp sh -c "echo 'deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main' | tee /etc/apt/sources.list.d/nodesource.list" - sudo docker exec sharp sh -c "apt-get update && apt-get install -y nodejs" - sudo docker exec sharp sh -c "mkdir -p /mnt/sharp" - sudo docker cp . sharp:/mnt/sharp/. - - run: sudo docker exec sharp sh -c "npm install --build-from-source" - - run: sudo docker exec sharp sh -c "npm test" - - run: | - sudo docker exec sharp sh -c "npm run package-from-local-build" - sudo docker exec sharp sh -c "npm pkg set \"optionalDependencies.@img/sharp-linux-arm64=file:./npm/linux-arm64\"" - sudo docker exec sharp sh -c "npm run clean" - sudo docker exec sharp sh -c "npm install --ignore-scripts" - sudo docker exec sharp sh -c "npm test" - linux-arm64-musl-node-18: - resource_class: arm.medium - machine: - image: ubuntu-2204:current - steps: - - checkout - - run: | - sudo docker run -dit --name sharp --volume "${PWD}:/mnt/sharp" --workdir /mnt/sharp node:18-alpine3.17 - sudo docker exec sharp sh -c "apk add build-base git python3 font-noto --update-cache" - - run: sudo docker exec sharp sh -c "npm install --build-from-source" - - run: sudo docker exec sharp sh -c "npm test" - - run: | - sudo docker exec sharp sh -c "npm run package-from-local-build" - sudo docker exec sharp sh -c "npm pkg set \"optionalDependencies.@img/sharp-linuxmusl-arm64=file:./npm/linuxmusl-arm64\"" - sudo docker exec sharp sh -c "npm run clean" - sudo docker exec sharp sh -c "npm install --ignore-scripts" - sudo docker exec sharp sh -c "npm test" - - run: "[[ -n $CIRCLE_TAG ]] && sudo docker exec --env prebuild_upload sharp sh -c \"cd src && ln -s ../package.json && npx prebuild --upload=$prebuild_upload\" || true" - linux-arm64-musl-node-20: - resource_class: arm.medium - machine: - image: ubuntu-2204:current - steps: - - checkout - - run: | - sudo docker run -dit --name sharp --workdir /mnt/sharp node:20-alpine3.18 - sudo docker exec sharp sh -c "apk add build-base git python3 font-noto --update-cache" - sudo docker exec sharp sh -c "mkdir -p /mnt/sharp" - sudo docker cp . sharp:/mnt/sharp/. - - run: sudo docker exec sharp sh -c "npm install --build-from-source" - - run: sudo docker exec sharp sh -c "npm test" - - run: | - sudo docker exec sharp sh -c "npm run package-from-local-build" - sudo docker exec sharp sh -c "npm pkg set \"optionalDependencies.@img/sharp-linuxmusl-arm64=file:./npm/linuxmusl-arm64\"" - sudo docker exec sharp sh -c "npm run clean" - sudo docker exec sharp sh -c "npm install --ignore-scripts" - sudo docker exec sharp sh -c "npm test" diff --git a/.cirrus.yml b/.cirrus.yml index a0b1785b0..eb240b5b8 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,5 +1,5 @@ freebsd_instance: - image_family: freebsd-14-0-snap + image_family: freebsd-15-0-snap task: name: FreeBSD diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e8050f87f..d67993b2d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,10 @@ jobs: contents: write name: ${{ matrix.platform }} - Node.js ${{ matrix.nodejs_version_major }} ${{ matrix.prebuild && '- prebuild' }} runs-on: ${{ matrix.os }} - container: ${{ matrix.container }} + container: + image: ${{ matrix.container }} + volumes: + - /:/host strategy: fail-fast: false matrix: @@ -46,6 +49,28 @@ jobs: container: node:22-alpine3.20 nodejs_version_major: 22 platform: linuxmusl-x64 + - os: ubuntu-24.04-arm + container: arm64v8/rockylinux:8 + nodejs_arch: arm64 + nodejs_version: "^18.17.0" + nodejs_version_major: 18 + platform: linux-arm64 + prebuild: true + - os: ubuntu-24.04-arm + container: arm64v8/rockylinux:8 + nodejs_arch: arm64 + nodejs_version: "^20.3.0" + nodejs_version_major: 20 + platform: linux-arm64 + - os: ubuntu-24.04-arm + container: node:18-alpine3.17 + nodejs_version_major: 18 + platform: linuxmusl-arm64 + prebuild: true + - os: ubuntu-24.04-arm + container: node:20-alpine3.18 + nodejs_version_major: 20 + platform: linuxmusl-arm64 - os: macos-13 nodejs_arch: x64 nodejs_version: "^18.17.0" @@ -122,6 +147,16 @@ jobs: nodejs_version_major: 22 platform: win32-arm64 steps: + - name: Allow Linux musl containers on ARM64 runners # https://github.com/actions/runner/issues/801#issuecomment-2394425757 + if: matrix.platform == 'linuxmusl-arm64' + shell: sh + run: | + apk add nodejs + sed -i "s:ID=alpine:ID=NotpineForGHA:" /etc/os-release + cd /host/home/runner/runners/*/externals/ + rm -rf node20/* + mkdir node20/bin + ln -s /usr/bin/node node20/bin/node - name: Dependencies (Rocky Linux glibc) if: contains(matrix.container, 'rockylinux') run: | From cab02463ec3e38f4150070bd9aea1c2dfa75b7be Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Fri, 13 Jun 2025 12:41:45 +0100 Subject: [PATCH 024/115] Remove prebuild dependency Every CI build task tagged with 'package' now populates and publishes the relevant npm/platform directory as an artefact. These are aggregated by a fan-in release task at the end to create a complete npm workspace zipfile. If the commit is tagged, a release is created and the npm workspace attached. --- .github/workflows/ci.yml | 195 ++++++++++++++++++++++--------------- .prebuildrc | 6 -- npm/from-github-release.js | 73 -------------- npm/from-local-build.js | 62 +++++++++--- package.json | 13 +-- src/binding.gyp | 5 + 6 files changed, 173 insertions(+), 181 deletions(-) delete mode 100644 .prebuildrc delete mode 100644 npm/from-github-release.js diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d67993b2d..ec95b072c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,15 +4,12 @@ on: - pull_request permissions: {} jobs: - github-runner: + build-native: permissions: - contents: write - name: ${{ matrix.platform }} - Node.js ${{ matrix.nodejs_version_major }} ${{ matrix.prebuild && '- prebuild' }} + contents: read + name: "build-${{ matrix.platform }} [Node.js ${{ matrix.nodejs_version_major }}] ${{ matrix.package && '[package]' }}" runs-on: ${{ matrix.os }} - container: - image: ${{ matrix.container }} - volumes: - - /:/host + container: ${{ matrix.container }} strategy: fail-fast: false matrix: @@ -23,7 +20,7 @@ jobs: nodejs_version: "^18.17.0" nodejs_version_major: 18 platform: linux-x64 - prebuild: true + package: true - os: ubuntu-24.04 container: rockylinux:8 nodejs_arch: x64 @@ -40,7 +37,7 @@ jobs: container: node:18-alpine3.17 nodejs_version_major: 18 platform: linuxmusl-x64 - prebuild: true + package: true - os: ubuntu-24.04 container: node:20-alpine3.18 nodejs_version_major: 20 @@ -55,28 +52,19 @@ jobs: nodejs_version: "^18.17.0" nodejs_version_major: 18 platform: linux-arm64 - prebuild: true + package: true - os: ubuntu-24.04-arm container: arm64v8/rockylinux:8 nodejs_arch: arm64 nodejs_version: "^20.3.0" nodejs_version_major: 20 platform: linux-arm64 - - os: ubuntu-24.04-arm - container: node:18-alpine3.17 - nodejs_version_major: 18 - platform: linuxmusl-arm64 - prebuild: true - - os: ubuntu-24.04-arm - container: node:20-alpine3.18 - nodejs_version_major: 20 - platform: linuxmusl-arm64 - os: macos-13 nodejs_arch: x64 nodejs_version: "^18.17.0" nodejs_version_major: 18 platform: darwin-x64 - prebuild: true + package: true - os: macos-13 nodejs_arch: x64 nodejs_version: "^20.3.0" @@ -92,7 +80,7 @@ jobs: nodejs_version: "^18.17.0" nodejs_version_major: 18 platform: darwin-arm64 - prebuild: true + package: true - os: macos-14 nodejs_arch: arm64 nodejs_version: "^20.3.0" @@ -108,7 +96,7 @@ jobs: nodejs_version: "18.18.2" # pinned to avoid 18.19.0 and npm 10 nodejs_version_major: 18 platform: win32-ia32 - prebuild: true + package: true - os: windows-2022 nodejs_arch: x86 nodejs_version: "^20.3.0" @@ -124,7 +112,7 @@ jobs: nodejs_version: "^18.17.0" nodejs_version_major: 18 platform: win32-x64 - prebuild: true + package: true - os: windows-2022 nodejs_arch: x64 nodejs_version: "^20.3.0" @@ -140,28 +128,18 @@ jobs: nodejs_version: "^20.3.0" nodejs_version_major: 20 platform: win32-arm64 - prebuild: true + package: true - os: windows-11-arm nodejs_arch: arm64 nodejs_version: "^22.9.0" nodejs_version_major: 22 platform: win32-arm64 steps: - - name: Allow Linux musl containers on ARM64 runners # https://github.com/actions/runner/issues/801#issuecomment-2394425757 - if: matrix.platform == 'linuxmusl-arm64' - shell: sh - run: | - apk add nodejs - sed -i "s:ID=alpine:ID=NotpineForGHA:" /etc/os-release - cd /host/home/runner/runners/*/externals/ - rm -rf node20/* - mkdir node20/bin - ln -s /usr/bin/node node20/bin/node - name: Dependencies (Rocky Linux glibc) if: contains(matrix.container, 'rockylinux') run: | - dnf install -y gcc-toolset-11-gcc-c++ make git python3.12 fontconfig google-noto-sans-fonts - echo "/opt/rh/gcc-toolset-11/root/usr/bin" >> $GITHUB_PATH + dnf install -y gcc-toolset-14-gcc-c++ make git python3.12 fontconfig google-noto-sans-fonts + echo "/opt/rh/gcc-toolset-14/root/usr/bin" >> $GITHUB_PATH - name: Dependencies (Linux musl) if: contains(matrix.container, 'alpine') run: apk add build-base git python3 font-noto --update-cache @@ -176,31 +154,70 @@ jobs: with: node-version: ${{ matrix.nodejs_version }} architecture: ${{ matrix.nodejs_arch }} - - name: Checkout - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - name: Install run: npm install --build-from-source - name: Test run: npm test - - name: Test packaging - run: | - npm run package-from-local-build - npm pkg set "optionalDependencies.@img/sharp-${{ matrix.platform }}=file:./npm/${{ matrix.platform }}" - npm run clean - npm install --ignore-scripts - npm test - - name: Prebuild - if: matrix.prebuild && startsWith(github.ref, 'refs/tags/') - env: - prebuild_upload: ${{ secrets.GITHUB_TOKEN }} + - name: Populate npm package + if: matrix.package + run: npm run package-from-local-build + - uses: actions/upload-artifact@v4 + if: matrix.package + with: + name: ${{ matrix.platform }} + path: npm/${{ matrix.platform }} + retention-days: 1 + if-no-files-found: error + build-linuxmusl-arm-64: + permissions: + contents: read + name: "build-linuxmusl-arm64 [Node.js ${{ matrix.nodejs_version_major }}] ${{ matrix.package && '[package]' }}" + runs-on: ubuntu-24.04-arm + container: + image: ${{ matrix.container }} + volumes: + - /:/host + strategy: + fail-fast: false + matrix: + include: + - container: node:18-alpine3.17 + nodejs_version_major: 18 + package: true + - container: node:20-alpine3.18 + nodejs_version_major: 20 + steps: + - name: Allow Linux musl containers on ARM64 runners # https://github.com/actions/runner/issues/801#issuecomment-2394425757 + shell: sh run: | - node -e "require('fs').cpSync('package.json', 'src/package.json')" - cd src - npx prebuild - github-runner-qemu: + apk add nodejs + sed -i "s:ID=alpine:ID=NotpineForGHA:" /etc/os-release + cd /host/home/runner/runners/*/externals/ + rm -rf node20/* + mkdir node20/bin + ln -s /usr/bin/node node20/bin/node + - name: Dependencies + run: apk add build-base git python3 font-noto --update-cache + - uses: actions/checkout@v4 + - name: Install + run: npm install --build-from-source + - name: Test + run: npm test + - name: Populate npm package + if: matrix.package + run: npm run package-from-local-build + - uses: actions/upload-artifact@v4 + if: matrix.package + with: + name: linuxmusl-arm64 + path: npm/linuxmusl-arm64 + retention-days: 1 + if-no-files-found: error + build-qemu: permissions: - contents: write - name: ${{ matrix.platform }} - Node.js ${{ matrix.nodejs_version_major }} - prebuild + contents: read + name: "build-${{ matrix.platform }} [Node.js ${{ matrix.nodejs_version_major }}] [package]" runs-on: ubuntu-24.04 strategy: fail-fast: false @@ -233,8 +250,6 @@ jobs: with: arch: ${{ matrix.run_on_arch }} distro: ${{ matrix.distro }} - env: | - prebuild_upload: "${{ startsWith(github.ref, 'refs/tags/') && secrets.GITHUB_TOKEN || '' }}" run: | apt-get update apt-get install -y curl g++ git libatomic1 make python3 xz-utils @@ -244,20 +259,20 @@ jobs: npm install --build-from-source npx mocha --no-config --spec=test/unit/io.js --timeout=30000 npm run package-from-local-build - npm pkg set "optionalDependencies.@img/sharp-${{ matrix.platform }}=file:./npm/${{ matrix.platform }}" - npm run clean - npm install --ignore-scripts - npx mocha --no-config --spec=test/unit/io.js --timeout=30000 - [[ -n $prebuild_upload ]] && cd src && ln -s ../package.json && npx prebuild || true - github-runner-emscripten: + - uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.platform }} + path: npm/${{ matrix.platform }} + retention-days: 1 + if-no-files-found: error + build-emscripten: permissions: - contents: write - name: wasm32 - prebuild + contents: read + name: "build-wasm32 [package]" runs-on: ubuntu-24.04 container: "emscripten/emsdk:4.0.10" steps: - - name: Checkout - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - name: Dependencies run: apt-get update && apt-get install -y pkg-config - name: Dependencies (Node.js) @@ -275,17 +290,35 @@ jobs: test "$EMSCRIPTEN_VERSION_LIBVIPS" = "$EMSCRIPTEN_VERSION_SHARP" - name: Test run: emmake npm test - - name: Test packaging - run: | - emmake npm run package-from-local-build - npm pkg set "optionalDependencies.@img/sharp-wasm32=file:./npm/wasm32" - npm run clean - rm -rf node_modules/@img/sharp-linux-x64 - npm install --cpu=wasm32 - npm test - - name: Prebuild - if: startsWith(github.ref, 'refs/tags/') - env: - npm_config_nodedir: emscripten - prebuild_upload: ${{ secrets.GITHUB_TOKEN }} - run: cd src && ln -s ../package.json && emmake npx prebuild --platform=emscripten --arch=wasm32 --strip=0 + - name: Populate npm package + run: emmake npm run package-from-local-build + - uses: actions/upload-artifact@v4 + with: + name: wasm32 + path: npm/wasm32 + retention-days: 1 + if-no-files-found: error + release: + permissions: + contents: write + runs-on: ubuntu-24.04 + needs: + - build-native + - build-linuxmusl-arm-64 + - build-qemu + - build-emscripten + steps: + - uses: actions/checkout@v4 + - uses: actions/download-artifact@v4 + with: + path: npm + - name: Create npm workspace tarball + run: tar -vcaf npm-workspace.tar.xz --directory npm --exclude=from-local-build.js . + - name: Create GitHub release for tag + if: startsWith(github.ref, 'refs/tags/v') + uses: ncipollo/release-action@v1 + with: + artifacts: npm-workspace.tar.xz + artifactContentType: application/x-xz + prerelease: ${{ contains(github.ref, '-rc') }} + makeLatest: ${{ !contains(github.ref, '-rc') }} diff --git a/.prebuildrc b/.prebuildrc deleted file mode 100644 index 0a4ccd2ef..000000000 --- a/.prebuildrc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "runtime": "napi", - "include-regex": "(sharp-.+\\.node|libvips-.+\\.dll)", - "prerelease": true, - "strip": true -} diff --git a/npm/from-github-release.js b/npm/from-github-release.js deleted file mode 100644 index 84f9fb9b3..000000000 --- a/npm/from-github-release.js +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 - -'use strict'; - -// Populate contents of all packages with the current GitHub release - -const { readFile, writeFile, appendFile, copyFile, rm } = require('node:fs/promises'); -const path = require('node:path'); -const { Readable } = require('node:stream'); -const { pipeline } = require('node:stream/promises'); -const { createGunzip } = require('node:zlib'); -const { extract } = require('tar-fs'); - -const { workspaces } = require('./package.json'); -const { version } = require('../package.json'); - -const mapTarballEntry = (header) => { - header.name = path.basename(header.name); - return header; -}; - -const licensing = ` -## Licensing - -Copyright 2013 Lovell Fuller and others. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at -[https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0) - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -`; - -workspaces.map(async platform => { - const prebuildPlatform = platform === 'wasm32' ? 'emscripten-wasm32' : platform; - const url = `https://github.com/lovell/sharp/releases/download/v${version}/sharp-v${version}-napi-v9-${prebuildPlatform}.tar.gz`; - const dir = path.join(__dirname, platform); - const response = await fetch(url); - if (!response.ok) { - console.log(`Skipping ${platform}: ${response.statusText}`); - return; - } - // Extract prebuild tarball - const lib = path.join(dir, 'lib'); - await rm(lib, { force: true, recursive: true }); - await pipeline( - Readable.fromWeb(response.body), - createGunzip(), - extract(lib, { map: mapTarballEntry }) - ); - // Generate README - const { name, description } = require(`./${platform}/package.json`); - await writeFile(path.join(dir, 'README.md'), `# \`${name}\`\n\n${description}.\n${licensing}`); - // Copy Apache-2.0 LICENSE - await copyFile(path.join(__dirname, '..', 'LICENSE'), path.join(dir, 'LICENSE')); - // Copy files for packages without an explicit sharp-libvips dependency (Windows, wasm) - if (platform.startsWith('win') || platform.startsWith('wasm')) { - const libvipsPlatform = platform === 'wasm32' ? 'dev-wasm32' : platform; - const sharpLibvipsDir = path.join(require(`@img/sharp-libvips-${libvipsPlatform}/lib`), '..'); - // Copy versions.json - await copyFile(path.join(sharpLibvipsDir, 'versions.json'), path.join(dir, 'versions.json')); - // Append third party licensing to README - const readme = await readFile(path.join(sharpLibvipsDir, 'README.md'), { encoding: 'utf-8' }); - const thirdParty = readme.substring(readme.indexOf('\nThis software contains')); - appendFile(path.join(dir, 'README.md'), thirdParty); - } -}); diff --git a/npm/from-local-build.js b/npm/from-local-build.js index ad7593ece..2fee2db9c 100644 --- a/npm/from-local-build.js +++ b/npm/from-local-build.js @@ -3,24 +3,62 @@ 'use strict'; -// Populate contents of a single npm/sharpen-sharp- package -// with the local/CI build directory for local/CI prebuild testing +// Populate the npm package for the current platform with the local build -const fs = require('node:fs'); -const path = require('node:path'); +const { copyFileSync, cpSync, readFileSync, writeFileSync, appendFileSync } = require('node:fs'); +const { basename, join } = require('node:path'); const { buildPlatformArch } = require('../lib/libvips'); + +const licensing = ` +## Licensing + +Copyright 2013 Lovell Fuller and others. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at +[https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0) + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +`; + const platform = buildPlatformArch(); -const dest = path.join(__dirname, platform); +const destDir = join(__dirname, platform); +console.log(`Populating npm package for platform: ${platform}`); -// Use same config as prebuild to copy binary files -const release = path.join(__dirname, '..', 'src', 'build', 'Release'); -const prebuildrc = JSON.parse(fs.readFileSync(path.join(__dirname, '..', '.prebuildrc'), 'utf8')); -const include = new RegExp(prebuildrc['include-regex'], 'i'); -fs.cpSync(release, path.join(dest, 'lib'), { +// Copy binaries +const releaseDir = join(__dirname, '..', 'src', 'build', 'Release'); +const libDir = join(destDir, 'lib'); +cpSync(releaseDir, libDir, { recursive: true, filter: (file) => { - const name = path.basename(file); - return name === 'Release' || include.test(name); + const name = basename(file); + return name === 'Release' || + (name.startsWith('sharp-') && name.includes('.node')) || + (name.startsWith('libvips-') && name.endsWith('.dll')); } }); + +// Generate README +const { name, description } = require(`./${platform}/package.json`); +writeFileSync(join(destDir, 'README.md'), `# \`${name}\`\n\n${description}.\n${licensing}`); + +// Copy Apache-2.0 LICENSE +copyFileSync(join(__dirname, '..', 'LICENSE'), join(destDir, 'LICENSE')); + +// Copy files for packages without an explicit sharp-libvips dependency (Windows, wasm) +if (platform.startsWith('win') || platform.startsWith('wasm')) { + const libvipsPlatform = platform === 'wasm32' ? 'dev-wasm32' : platform; + const sharpLibvipsDir = join(require(`@img/sharp-libvips-${libvipsPlatform}/lib`), '..'); + // Copy versions.json + copyFileSync(join(sharpLibvipsDir, 'versions.json'), join(destDir, 'versions.json')); + // Append third party licensing to README + const readme = readFileSync(join(sharpLibvipsDir, 'README.md'), { encoding: 'utf-8' }); + const thirdParty = readme.substring(readme.indexOf('\nThis software contains')); + appendFileSync(join(destDir, 'README.md'), thirdParty); +} diff --git a/package.json b/package.json index 93100990c..0536050b1 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,7 @@ "Don Denton " ], "scripts": { - "install": "node install/check", + "install": "node install/check.js", "clean": "rm -rf src/build/ .nyc_output/ coverage/ test/fixtures/output.*", "test": "npm run test-lint && npm run test-unit && npm run test-licensing && npm run test-types", "test-lint": "semistandard && cpplint", @@ -100,8 +100,7 @@ "test-licensing": "license-checker --production --summary --onlyAllow=\"Apache-2.0;BSD;ISC;LGPL-3.0-or-later;MIT\"", "test-leak": "./test/leak/leak.sh", "test-types": "tsd", - "package-from-local-build": "node npm/from-local-build", - "package-from-github-release": "node npm/from-github-release", + "package-from-local-build": "node npm/from-local-build.js", "docs-build": "node docs/build.mjs", "docs-serve": "cd docs && npm start", "docs-publish": "cd docs && npm run build && npx firebase-tools deploy --project pixelplumbing --only hosting:pixelplumbing-sharp" @@ -155,6 +154,7 @@ "@img/sharp-libvips-linuxmusl-x64": "1.2.0-rc.2", "@img/sharp-linux-arm": "0.34.2", "@img/sharp-linux-arm64": "0.34.2", + "@img/sharp-linux-ppc64": "0.34.2", "@img/sharp-linux-s390x": "0.34.2", "@img/sharp-linux-x64": "0.34.2", "@img/sharp-linuxmusl-arm64": "0.34.2", @@ -181,8 +181,8 @@ "license-checker": "^25.0.1", "mocha": "^11.6.0", "node-addon-api": "^8.3.1", + "node-gyp": "^11.2.0", "nyc": "^17.1.0", - "prebuild": "^13.0.1", "semistandard": "^17.0.0", "tar-fs": "^3.0.9", "tsd": "^0.32.0" @@ -197,11 +197,6 @@ "funding": { "url": "https://opencollective.com/libvips" }, - "binary": { - "napi_versions": [ - 9 - ] - }, "semistandard": { "env": [ "mocha" diff --git a/src/binding.gyp b/src/binding.gyp index 0fbf515ea..ae38a29f3 100644 --- a/src/binding.gyp +++ b/src/binding.gyp @@ -163,6 +163,8 @@ }, 'xcode_settings': { 'OTHER_LDFLAGS': [ + '-Wl,-s', + '-Wl,-dead_strip', # Ensure runtime linking is relative to sharp.node '-Wl,-rpath,\'@loader_path/../../sharp-libvips-<(platform_and_arch)/lib\'', '-Wl,-rpath,\'@loader_path/../../../sharp-libvips-<(platform_and_arch)/<(sharp_libvips_version)/lib\'', @@ -176,6 +178,9 @@ 'defines': [ '_GLIBCXX_USE_CXX11_ABI=1' ], + 'cflags_cc': [ + ' Date: Sat, 14 Jun 2025 21:49:24 +0100 Subject: [PATCH 025/115] Prerelease v0.34.3-rc.0 --- npm/darwin-arm64/package.json | 2 +- npm/darwin-x64/package.json | 2 +- npm/linux-arm/package.json | 2 +- npm/linux-arm64/package.json | 2 +- npm/linux-ppc64/package.json | 2 +- npm/linux-s390x/package.json | 2 +- npm/linux-x64/package.json | 2 +- npm/linuxmusl-arm64/package.json | 2 +- npm/linuxmusl-x64/package.json | 2 +- npm/package.json | 2 +- npm/wasm32/package.json | 2 +- npm/win32-arm64/package.json | 2 +- npm/win32-ia32/package.json | 2 +- npm/win32-x64/package.json | 2 +- package.json | 28 ++++++++++++++-------------- 15 files changed, 28 insertions(+), 28 deletions(-) diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index 17dbc64bd..58f4617b6 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-arm64", - "version": "0.34.2", + "version": "0.34.3-rc.0", "description": "Prebuilt sharp for use with macOS 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index 3ab94ac03..4c7af9191 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-x64", - "version": "0.34.2", + "version": "0.34.3-rc.0", "description": "Prebuilt sharp for use with macOS x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm/package.json b/npm/linux-arm/package.json index 83fc2f394..4fe4d7dca 100644 --- a/npm/linux-arm/package.json +++ b/npm/linux-arm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm", - "version": "0.34.2", + "version": "0.34.3-rc.0", "description": "Prebuilt sharp for use with Linux (glibc) ARM (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm64/package.json b/npm/linux-arm64/package.json index 9cb57d087..8ffc90d87 100644 --- a/npm/linux-arm64/package.json +++ b/npm/linux-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm64", - "version": "0.34.2", + "version": "0.34.3-rc.0", "description": "Prebuilt sharp for use with Linux (glibc) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-ppc64/package.json b/npm/linux-ppc64/package.json index 868d14759..0e2e66538 100644 --- a/npm/linux-ppc64/package.json +++ b/npm/linux-ppc64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-ppc64", - "version": "0.34.2", + "version": "0.34.3-rc.0", "description": "Prebuilt sharp for use with Linux (glibc) ppc64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-s390x/package.json b/npm/linux-s390x/package.json index 7f920b546..6ff791d92 100644 --- a/npm/linux-s390x/package.json +++ b/npm/linux-s390x/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-s390x", - "version": "0.34.2", + "version": "0.34.3-rc.0", "description": "Prebuilt sharp for use with Linux (glibc) s390x", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-x64/package.json b/npm/linux-x64/package.json index 372cdd641..120855e8e 100644 --- a/npm/linux-x64/package.json +++ b/npm/linux-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-x64", - "version": "0.34.2", + "version": "0.34.3-rc.0", "description": "Prebuilt sharp for use with Linux (glibc) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-arm64/package.json b/npm/linuxmusl-arm64/package.json index 3fc921adf..05ef9bfd4 100644 --- a/npm/linuxmusl-arm64/package.json +++ b/npm/linuxmusl-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-arm64", - "version": "0.34.2", + "version": "0.34.3-rc.0", "description": "Prebuilt sharp for use with Linux (musl) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-x64/package.json b/npm/linuxmusl-x64/package.json index 089e4cf37..9425ed3fc 100644 --- a/npm/linuxmusl-x64/package.json +++ b/npm/linuxmusl-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-x64", - "version": "0.34.2", + "version": "0.34.3-rc.0", "description": "Prebuilt sharp for use with Linux (musl) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/package.json b/npm/package.json index fde3bf4ed..de00c0dd6 100644 --- a/npm/package.json +++ b/npm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp", - "version": "0.34.2", + "version": "0.34.3-rc.0", "private": "true", "workspaces": [ "darwin-arm64", diff --git a/npm/wasm32/package.json b/npm/wasm32/package.json index 9ad9d08f5..0e02c5b96 100644 --- a/npm/wasm32/package.json +++ b/npm/wasm32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-wasm32", - "version": "0.34.2", + "version": "0.34.3-rc.0", "description": "Prebuilt sharp for use with wasm32", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-arm64/package.json b/npm/win32-arm64/package.json index cc46b899d..35a5da2cb 100644 --- a/npm/win32-arm64/package.json +++ b/npm/win32-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-arm64", - "version": "0.34.2", + "version": "0.34.3-rc.0", "description": "Prebuilt sharp for use with Windows 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-ia32/package.json b/npm/win32-ia32/package.json index 2fa8c41a1..52c7beb77 100644 --- a/npm/win32-ia32/package.json +++ b/npm/win32-ia32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-ia32", - "version": "0.34.2", + "version": "0.34.3-rc.0", "description": "Prebuilt sharp for use with Windows x86 (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-x64/package.json b/npm/win32-x64/package.json index 99f54be02..5f0f67b35 100644 --- a/npm/win32-x64/package.json +++ b/npm/win32-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-x64", - "version": "0.34.2", + "version": "0.34.3-rc.0", "description": "Prebuilt sharp for use with Windows x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/package.json b/package.json index 0536050b1..13816bce0 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "sharp", "description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images", - "version": "0.34.2", + "version": "0.34.3-rc.0", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", "contributors": [ @@ -141,8 +141,8 @@ "semver": "^7.7.2" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.2", - "@img/sharp-darwin-x64": "0.34.2", + "@img/sharp-darwin-arm64": "0.34.3-rc.0", + "@img/sharp-darwin-x64": "0.34.3-rc.0", "@img/sharp-libvips-darwin-arm64": "1.2.0-rc.2", "@img/sharp-libvips-darwin-x64": "1.2.0-rc.2", "@img/sharp-libvips-linux-arm": "1.2.0-rc.2", @@ -152,17 +152,17 @@ "@img/sharp-libvips-linux-x64": "1.2.0-rc.2", "@img/sharp-libvips-linuxmusl-arm64": "1.2.0-rc.2", "@img/sharp-libvips-linuxmusl-x64": "1.2.0-rc.2", - "@img/sharp-linux-arm": "0.34.2", - "@img/sharp-linux-arm64": "0.34.2", - "@img/sharp-linux-ppc64": "0.34.2", - "@img/sharp-linux-s390x": "0.34.2", - "@img/sharp-linux-x64": "0.34.2", - "@img/sharp-linuxmusl-arm64": "0.34.2", - "@img/sharp-linuxmusl-x64": "0.34.2", - "@img/sharp-wasm32": "0.34.2", - "@img/sharp-win32-arm64": "0.34.2", - "@img/sharp-win32-ia32": "0.34.2", - "@img/sharp-win32-x64": "0.34.2" + "@img/sharp-linux-arm": "0.34.3-rc.0", + "@img/sharp-linux-arm64": "0.34.3-rc.0", + "@img/sharp-linux-ppc64": "0.34.3-rc.0", + "@img/sharp-linux-s390x": "0.34.3-rc.0", + "@img/sharp-linux-x64": "0.34.3-rc.0", + "@img/sharp-linuxmusl-arm64": "0.34.3-rc.0", + "@img/sharp-linuxmusl-x64": "0.34.3-rc.0", + "@img/sharp-wasm32": "0.34.3-rc.0", + "@img/sharp-win32-arm64": "0.34.3-rc.0", + "@img/sharp-win32-ia32": "0.34.3-rc.0", + "@img/sharp-win32-x64": "0.34.3-rc.0" }, "devDependencies": { "@emnapi/runtime": "^1.4.3", From 9392b8702bb6895c3951180f7125d7eff80885fb Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Sun, 15 Jun 2025 12:53:10 +0100 Subject: [PATCH 026/115] Add Magic Kernel Sharp (no relation) to resizing kernels --- docs/src/content/docs/api-resize.md | 2 ++ docs/src/content/docs/changelog.md | 2 ++ lib/index.d.ts | 2 ++ lib/resize.js | 2 ++ test/types/sharp.test-d.ts | 2 ++ 5 files changed, 10 insertions(+) diff --git a/docs/src/content/docs/api-resize.md b/docs/src/content/docs/api-resize.md index da7ac53bf..6452c3455 100644 --- a/docs/src/content/docs/api-resize.md +++ b/docs/src/content/docs/api-resize.md @@ -38,6 +38,8 @@ Possible downsizing kernels are: - `mitchell`: Use a [Mitchell-Netravali spline](https://www.cs.utexas.edu/~fussell/courses/cs384g-fall2013/lectures/mitchell/Mitchell.pdf). - `lanczos2`: Use a [Lanczos kernel](https://en.wikipedia.org/wiki/Lanczos_resampling#Lanczos_kernel) with `a=2`. - `lanczos3`: Use a Lanczos kernel with `a=3` (the default). +- `mks2013`: Use a [Magic Kernel Sharp](https://johncostella.com/magic/mks.pdf) 2013 kernel, as adopted by Facebook. +- `mks2021`: Use a Magic Kernel Sharp 2021 kernel, with more accurate (reduced) sharpening than the 2013 version. When upsampling, these kernels map to `nearest`, `linear` and `cubic` interpolators. Downsampling kernels without a matching upsampling interpolator map to `cubic`. diff --git a/docs/src/content/docs/changelog.md b/docs/src/content/docs/changelog.md index f84859d80..88c822935 100644 --- a/docs/src/content/docs/changelog.md +++ b/docs/src/content/docs/changelog.md @@ -10,6 +10,8 @@ Requires libvips v8.17.0 * Upgrade to libvips v8.17.0 for upstream bug fixes. +* Add "Magic Kernel Sharp" (no relation) to resizing kernels. + * Expose JPEG 2000 `oneshot` decoder option. [#4262](https://github.com/lovell/sharp/pull/4262) [@mbklein](https://github.com/mbklein) diff --git a/lib/index.d.ts b/lib/index.d.ts index 9ed7190dd..2d93ac84a 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1729,6 +1729,8 @@ declare namespace sharp { mitchell: 'mitchell'; lanczos2: 'lanczos2'; lanczos3: 'lanczos3'; + mks2013: 'mks2013'; + mks2021: 'mks2021'; } interface PresetEnum { diff --git a/lib/resize.js b/lib/resize.js index 66cfd8719..665e0c879 100644 --- a/lib/resize.js +++ b/lib/resize.js @@ -150,6 +150,8 @@ function isResizeExpected (options) { * - `mitchell`: Use a [Mitchell-Netravali spline](https://www.cs.utexas.edu/~fussell/courses/cs384g-fall2013/lectures/mitchell/Mitchell.pdf). * - `lanczos2`: Use a [Lanczos kernel](https://en.wikipedia.org/wiki/Lanczos_resampling#Lanczos_kernel) with `a=2`. * - `lanczos3`: Use a Lanczos kernel with `a=3` (the default). + * - `mks2013`: Use a [Magic Kernel Sharp](https://johncostella.com/magic/mks.pdf) 2013 kernel, as adopted by Facebook. + * - `mks2021`: Use a Magic Kernel Sharp 2021 kernel, with more accurate (reduced) sharpening than the 2013 version. * * When upsampling, these kernels map to `nearest`, `linear` and `cubic` interpolators. * Downsampling kernels without a matching upsampling interpolator map to `cubic`. diff --git a/test/types/sharp.test-d.ts b/test/types/sharp.test-d.ts index 88e5b45bb..be8ce88d3 100644 --- a/test/types/sharp.test-d.ts +++ b/test/types/sharp.test-d.ts @@ -188,6 +188,8 @@ sharp(input) // of the image data in inputBuffer }); +sharp(input).resize({ kernel: 'mks2013' }); + transformer = sharp() .resize(200, 200, { fit: 'cover', From 8c53d499f7029133d940fcf58f0be76bb1394395 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Sun, 15 Jun 2025 15:39:01 +0100 Subject: [PATCH 027/115] Expose keepDuplicateFrames GIF output parameter --- docs/src/content/docs/api-output.md | 1 + docs/src/content/docs/changelog.md | 2 ++ lib/constructor.js | 1 + lib/index.d.ts | 6 ++++-- lib/output.js | 8 ++++++++ src/pipeline.cc | 5 +++++ src/pipeline.h | 2 ++ test/types/sharp.test-d.ts | 2 ++ test/unit/gif.js | 25 +++++++++++++++++++++++++ 9 files changed, 50 insertions(+), 2 deletions(-) diff --git a/docs/src/content/docs/api-output.md b/docs/src/content/docs/api-output.md index 9cca1d554..40cc74cfd 100644 --- a/docs/src/content/docs/api-output.md +++ b/docs/src/content/docs/api-output.md @@ -496,6 +496,7 @@ The palette of the input image will be re-used if possible. | [options.dither] | number | 1.0 | level of Floyd-Steinberg error diffusion, between 0 (least) and 1 (most) | | [options.interFrameMaxError] | number | 0 | maximum inter-frame error for transparency, between 0 (lossless) and 32 | | [options.interPaletteMaxError] | number | 3 | maximum inter-palette error for palette reuse, between 0 and 256 | +| [options.keepDuplicateFrames] | boolean | false | keep duplicate frames in the output instead of combining them | | [options.loop] | number | 0 | number of animation iterations, use 0 for infinite animation | | [options.delay] | number \| Array.<number> | | delay(s) between animation frames (in milliseconds) | | [options.force] | boolean | true | force GIF output, otherwise attempt to use input format | diff --git a/docs/src/content/docs/changelog.md b/docs/src/content/docs/changelog.md index 88c822935..b3c068b74 100644 --- a/docs/src/content/docs/changelog.md +++ b/docs/src/content/docs/changelog.md @@ -12,6 +12,8 @@ Requires libvips v8.17.0 * Add "Magic Kernel Sharp" (no relation) to resizing kernels. +* Expose `keepDuplicateFrames` GIF output parameter. + * Expose JPEG 2000 `oneshot` decoder option. [#4262](https://github.com/lovell/sharp/pull/4262) [@mbklein](https://github.com/mbklein) diff --git a/lib/constructor.js b/lib/constructor.js index c70bbf1e4..2cf4c3b3f 100644 --- a/lib/constructor.js +++ b/lib/constructor.js @@ -338,6 +338,7 @@ const Sharp = function (input, options) { gifDither: 1, gifInterFrameMaxError: 0, gifInterPaletteMaxError: 3, + gifKeepDuplicateFrames: false, gifReuse: true, gifProgressive: false, tiffQuality: 80, diff --git a/lib/index.d.ts b/lib/index.d.ts index 2d93ac84a..2a3554265 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1392,9 +1392,11 @@ declare namespace sharp { /** Level of Floyd-Steinberg error diffusion, between 0 (least) and 1 (most) (optional, default 1.0) */ dither?: number | undefined; /** Maximum inter-frame error for transparency, between 0 (lossless) and 32 (optional, default 0) */ - interFrameMaxError?: number; + interFrameMaxError?: number | undefined; /** Maximum inter-palette error for palette reuse, between 0 and 256 (optional, default 3) */ - interPaletteMaxError?: number; + interPaletteMaxError?: number | undefined; + /** Keep duplicate frames in the output instead of combining them (optional, default false) */ + keepDuplicateFrames?: boolean | undefined; } interface TiffOptions extends OutputOptions { diff --git a/lib/output.js b/lib/output.js index 08d596ade..a8b32277c 100644 --- a/lib/output.js +++ b/lib/output.js @@ -729,6 +729,7 @@ function webp (options) { * @param {number} [options.dither=1.0] - level of Floyd-Steinberg error diffusion, between 0 (least) and 1 (most) * @param {number} [options.interFrameMaxError=0] - maximum inter-frame error for transparency, between 0 (lossless) and 32 * @param {number} [options.interPaletteMaxError=3] - maximum inter-palette error for palette reuse, between 0 and 256 + * @param {boolean} [options.keepDuplicateFrames=false] - keep duplicate frames in the output instead of combining them * @param {number} [options.loop=0] - number of animation iterations, use 0 for infinite animation * @param {number|number[]} [options.delay] - delay(s) between animation frames (in milliseconds) * @param {boolean} [options.force=true] - force GIF output, otherwise attempt to use input format @@ -779,6 +780,13 @@ function gif (options) { throw is.invalidParameterError('interPaletteMaxError', 'number between 0.0 and 256.0', options.interPaletteMaxError); } } + if (is.defined(options.keepDuplicateFrames)) { + if (is.bool(options.keepDuplicateFrames)) { + this._setBooleanOption('gifKeepDuplicateFrames', options.keepDuplicateFrames); + } else { + throw is.invalidParameterError('keepDuplicateFrames', 'boolean', options.keepDuplicateFrames); + } + } } trySetAnimationOptions(options, this.options); return this._updateFormatOut('gif', options); diff --git a/src/pipeline.cc b/src/pipeline.cc index 679c83298..e353cc728 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -1006,6 +1006,7 @@ class PipelineWorker : public Napi::AsyncWorker { ->set("interlace", baton->gifProgressive) ->set("interframe_maxerror", baton->gifInterFrameMaxError) ->set("interpalette_maxerror", baton->gifInterPaletteMaxError) + ->set("keep_duplicate_frames", baton->gifKeepDuplicateFrames) ->set("dither", baton->gifDither))); baton->bufferOut = static_cast(area->data); baton->bufferOutLength = area->length; @@ -1209,6 +1210,9 @@ class PipelineWorker : public Napi::AsyncWorker { ->set("effort", baton->gifEffort) ->set("reuse", baton->gifReuse) ->set("interlace", baton->gifProgressive) + ->set("interframe_maxerror", baton->gifInterFrameMaxError) + ->set("interpalette_maxerror", baton->gifInterPaletteMaxError) + ->set("keep_duplicate_frames", baton->gifKeepDuplicateFrames) ->set("dither", baton->gifDither)); baton->formatOut = "gif"; } else if (baton->formatOut == "tiff" || (mightMatchInput && isTiff) || @@ -1761,6 +1765,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) { baton->gifDither = sharp::AttrAsDouble(options, "gifDither"); baton->gifInterFrameMaxError = sharp::AttrAsDouble(options, "gifInterFrameMaxError"); baton->gifInterPaletteMaxError = sharp::AttrAsDouble(options, "gifInterPaletteMaxError"); + baton->gifKeepDuplicateFrames = sharp::AttrAsBool(options, "gifKeepDuplicateFrames"); baton->gifReuse = sharp::AttrAsBool(options, "gifReuse"); baton->gifProgressive = sharp::AttrAsBool(options, "gifProgressive"); baton->tiffQuality = sharp::AttrAsUint32(options, "tiffQuality"); diff --git a/src/pipeline.h b/src/pipeline.h index 66a45f43e..63c9f7c21 100644 --- a/src/pipeline.h +++ b/src/pipeline.h @@ -169,6 +169,7 @@ struct PipelineBaton { double gifDither; double gifInterFrameMaxError; double gifInterPaletteMaxError; + bool gifKeepDuplicateFrames; bool gifReuse; bool gifProgressive; int tiffQuality; @@ -342,6 +343,7 @@ struct PipelineBaton { gifDither(1.0), gifInterFrameMaxError(0.0), gifInterPaletteMaxError(3.0), + gifKeepDuplicateFrames(false), gifReuse(true), gifProgressive(false), tiffQuality(80), diff --git a/test/types/sharp.test-d.ts b/test/types/sharp.test-d.ts index be8ce88d3..eb1b3bb7b 100644 --- a/test/types/sharp.test-d.ts +++ b/test/types/sharp.test-d.ts @@ -375,6 +375,8 @@ sharp(input) .gif({ reuse: false }) .gif({ progressive: true }) .gif({ progressive: false }) + .gif({ keepDuplicateFrames: true }) + .gif({ keepDuplicateFrames: false }) .toBuffer({ resolveWithObject: true }) .then(({ data, info }) => { console.log(data); diff --git a/test/unit/gif.js b/test/unit/gif.js index 93e4d46b4..61a3e199f 100644 --- a/test/unit/gif.js +++ b/test/unit/gif.js @@ -187,6 +187,17 @@ describe('GIF input', () => { ); }); + it('invalid keepDuplicateFrames throws', () => { + assert.throws( + () => sharp().gif({ keepDuplicateFrames: -1 }), + /Expected boolean for keepDuplicateFrames but received -1 of type number/ + ); + assert.throws( + () => sharp().gif({ keepDuplicateFrames: 'fail' }), + /Expected boolean for keepDuplicateFrames but received fail of type string/ + ); + }); + it('should work with streams when only animated is set', function (done) { fs.createReadStream(fixtures.inputGifAnimated) .pipe(sharp({ animated: true })) @@ -225,6 +236,20 @@ describe('GIF input', () => { assert.strict(before.length > after.length); }); + it('should keep duplicate frames via keepDuplicateFrames', async () => { + const create = { width: 8, height: 8, channels: 4, background: 'blue' }; + const input = sharp([{ create }, { create }], { join: { animated: true } }); + + const before = await input.gif({ keepDuplicateFrames: false }).toBuffer(); + const after = await input.gif({ keepDuplicateFrames: true }).toBuffer(); + assert.strict(before.length < after.length); + + const beforeMeta = await sharp(before).metadata(); + const afterMeta = await sharp(after).metadata(); + assert.strictEqual(beforeMeta.pages, 1); + assert.strictEqual(afterMeta.pages, 2); + }); + it('non-animated input defaults to no-loop', async () => { for (const input of [fixtures.inputGif, fixtures.inputPng]) { const data = await sharp(input) From f92540f1348e6952562aef1d78ef997e13a222e7 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Mon, 16 Jun 2025 07:51:36 +0100 Subject: [PATCH 028/115] Nest format-specific constructor params (deprecate at top-level) - `subifd` -> `tiff.subifd` - `level` -> `openSlide.level` - `pdfBackground` -> `pdf.background` --- docs/src/content/docs/api-constructor.md | 12 ++- docs/src/content/docs/changelog.md | 2 + lib/constructor.js | 13 ++- lib/index.d.ts | 38 ++++++-- lib/input.js | 39 +++++--- test/types/sharp.test-d.ts | 19 ++-- test/unit/io.js | 115 +++++++++++++++-------- test/unit/jp2.js | 6 +- 8 files changed, 169 insertions(+), 75 deletions(-) diff --git a/docs/src/content/docs/api-constructor.md b/docs/src/content/docs/api-constructor.md index b5b7a9c85..7c7e8e9c9 100644 --- a/docs/src/content/docs/api-constructor.md +++ b/docs/src/content/docs/api-constructor.md @@ -44,10 +44,6 @@ where the overall height is the `pageHeight` multiplied by the number of `pages` | [options.ignoreIcc] | number | false | should the embedded ICC profile, if any, be ignored. | | [options.pages] | number | 1 | Number of pages to extract for multi-page input (GIF, WebP, TIFF), use -1 for all pages. | | [options.page] | number | 0 | Page number to start extracting from for multi-page input (GIF, WebP, TIFF), zero based. | -| [options.subifd] | number | -1 | subIFD (Sub Image File Directory) to extract for OME-TIFF, defaults to main image. | -| [options.level] | number | 0 | level to extract from a multi-level input (OpenSlide), zero based. | -| [options.pdfBackground] | string \| Object | | Background colour to use when PDF is partially transparent. Parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick. | -| [options.jp2Oneshot] | boolean | false | Set to `true` to decode tiled JPEG 2000 images in a single operation, improving compatibility. | | [options.animated] | boolean | false | Set to `true` to read all frames/pages of an animated image (GIF, WebP, TIFF), equivalent of setting `pages` to `-1`. | | [options.raw] | Object | | describes raw pixel input image data. See `raw()` for pixel ordering. | | [options.raw.width] | number | | integral number of pixels wide. | @@ -82,6 +78,14 @@ where the overall height is the `pageHeight` multiplied by the number of `pages` | [options.join.background] | string \| Object | | parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha. | | [options.join.halign] | string | "'left'" | horizontal alignment style for images joined horizontally (`'left'`, `'centre'`, `'center'`, `'right'`). | | [options.join.valign] | string | "'top'" | vertical alignment style for images joined vertically (`'top'`, `'centre'`, `'center'`, `'bottom'`). | +| [options.tiff] | Object | | Describes TIFF specific options. | +| [options.tiff.subifd] | number | -1 | Sub Image File Directory to extract for OME-TIFF, defaults to main image. | +| [options.pdf] | Object | | Describes PDF specific options. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick. | +| [options.pdf.background] | string \| Object | | Background colour to use when PDF is partially transparent. Parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha. | +| [options.openSlide] | Object | | Describes OpenSlide specific options. Requires the use of a globally-installed libvips compiled with support for OpenSlide. | +| [options.openSlide.level] | number | 0 | Level to extract from a multi-level input, zero based. | +| [options.jp2] | Object | | Describes JPEG 2000 specific options. Requires the use of a globally-installed libvips compiled with support for OpenJPEG. | +| [options.jp2.oneshot] | boolean | false | Set to `true` to decode tiled JPEG 2000 images in a single operation, improving compatibility. | **Example** ```js diff --git a/docs/src/content/docs/changelog.md b/docs/src/content/docs/changelog.md index b3c068b74..125f774fd 100644 --- a/docs/src/content/docs/changelog.md +++ b/docs/src/content/docs/changelog.md @@ -12,6 +12,8 @@ Requires libvips v8.17.0 * Add "Magic Kernel Sharp" (no relation) to resizing kernels. +* Deprecate top-level, format-specific constructor parameters, e.g. `subifd` becomes `tiff.subifd`. + * Expose `keepDuplicateFrames` GIF output parameter. * Expose JPEG 2000 `oneshot` decoder option. diff --git a/lib/constructor.js b/lib/constructor.js index 2cf4c3b3f..5d86c422c 100644 --- a/lib/constructor.js +++ b/lib/constructor.js @@ -153,10 +153,6 @@ const debuglog = util.debuglog('sharp'); * @param {number} [options.ignoreIcc=false] - should the embedded ICC profile, if any, be ignored. * @param {number} [options.pages=1] - Number of pages to extract for multi-page input (GIF, WebP, TIFF), use -1 for all pages. * @param {number} [options.page=0] - Page number to start extracting from for multi-page input (GIF, WebP, TIFF), zero based. - * @param {number} [options.subifd=-1] - subIFD (Sub Image File Directory) to extract for OME-TIFF, defaults to main image. - * @param {number} [options.level=0] - level to extract from a multi-level input (OpenSlide), zero based. - * @param {string|Object} [options.pdfBackground] - Background colour to use when PDF is partially transparent. Parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick. - * @param {boolean} [options.jp2Oneshot=false] - Set to `true` to decode tiled JPEG 2000 images in a single operation, improving compatibility. * @param {boolean} [options.animated=false] - Set to `true` to read all frames/pages of an animated image (GIF, WebP, TIFF), equivalent of setting `pages` to `-1`. * @param {Object} [options.raw] - describes raw pixel input image data. See `raw()` for pixel ordering. * @param {number} [options.raw.width] - integral number of pixels wide. @@ -192,7 +188,14 @@ const debuglog = util.debuglog('sharp'); * @param {string|Object} [options.join.background] - parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha. * @param {string} [options.join.halign='left'] - horizontal alignment style for images joined horizontally (`'left'`, `'centre'`, `'center'`, `'right'`). * @param {string} [options.join.valign='top'] - vertical alignment style for images joined vertically (`'top'`, `'centre'`, `'center'`, `'bottom'`). - * + * @param {Object} [options.tiff] - Describes TIFF specific options. + * @param {number} [options.tiff.subifd=-1] - Sub Image File Directory to extract for OME-TIFF, defaults to main image. + * @param {Object} [options.pdf] - Describes PDF specific options. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick. + * @param {string|Object} [options.pdf.background] - Background colour to use when PDF is partially transparent. Parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha. + * @param {Object} [options.openSlide] - Describes OpenSlide specific options. Requires the use of a globally-installed libvips compiled with support for OpenSlide. + * @param {number} [options.openSlide.level=0] - Level to extract from a multi-level input, zero based. + * @param {Object} [options.jp2] - Describes JPEG 2000 specific options. Requires the use of a globally-installed libvips compiled with support for OpenJPEG. + * @param {boolean} [options.jp2.oneshot=false] - Set to `true` to decode tiled JPEG 2000 images in a single operation, improving compatibility. * @returns {Sharp} * @throws {Error} Invalid parameters */ diff --git a/lib/index.d.ts b/lib/index.d.ts index 2a3554265..1ac6fc247 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1003,14 +1003,20 @@ declare namespace sharp { pages?: number | undefined; /** Page number to start extracting from for multi-page input (GIF, TIFF, PDF), zero based. (optional, default 0) */ page?: number | undefined; - /** subIFD (Sub Image File Directory) to extract for OME-TIFF, defaults to main image. (optional, default -1) */ + /** TIFF specific input options */ + tiff?: TiffInputOptions | undefined; + /** PDF specific input options */ + pdf?: PdfInputOptions | undefined; + /** OpenSlide specific input options */ + openSlide?: OpenSlideInputOptions | undefined; + /** JPEG 2000 specific input options */ + jp2?: Jp2InputOptions | undefined; + /** Deprecated: use tiff.subifd instead */ subifd?: number | undefined; - /** Level to extract from a multi-level input (OpenSlide), zero based. (optional, default 0) */ - level?: number | undefined; - /** Background colour to use when PDF is partially transparent. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick. */ + /** Deprecated: use pdf.background instead */ pdfBackground?: Colour | Color | undefined; - /** Set to `true` to load JPEG 2000 images using [oneshot mode](https://github.com/libvips/libvips/issues/4205) */ - jp2Oneshot?: boolean | undefined; + /** Deprecated: use openSlide.level instead */ + level?: number | undefined; /** Set to `true` to read all frames/pages of an animated image (equivalent of setting `pages` to `-1`). (optional, default false) */ animated?: boolean | undefined; /** Describes raw pixel input image data. See raw() for pixel ordering. */ @@ -1116,6 +1122,26 @@ declare namespace sharp { valign?: VerticalAlignment | undefined; } + interface TiffInputOptions { + /** Sub Image File Directory to extract, defaults to main image. Use -1 for all subifds. */ + subifd?: number | undefined; + } + + interface PdfInputOptions { + /** Background colour to use when PDF is partially transparent. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick. */ + background?: Colour | Color | undefined; + } + + interface OpenSlideInputOptions { + /** Level to extract from a multi-level input, zero based. (optional, default 0) */ + level?: number | undefined; + } + + interface Jp2InputOptions { + /** Set to `true` to load JPEG 2000 images using [oneshot mode](https://github.com/libvips/libvips/issues/4205) */ + oneshot?: boolean | undefined; + } + interface ExifDir { [k: string]: string; } diff --git a/lib/input.js b/lib/input.js index 59de9a6c3..d15715558 100644 --- a/lib/input.js +++ b/lib/input.js @@ -230,32 +230,49 @@ function _createInputDescriptor (input, inputOptions, containerOptions) { throw is.invalidParameterError('page', 'integer between 0 and 100000', inputOptions.page); } } - // Multi-level input (OpenSlide) - if (is.defined(inputOptions.level)) { + // OpenSlide specific options + if (is.object(inputOptions.openSlide) && is.defined(inputOptions.openSlide.level)) { + if (is.integer(inputOptions.openSlide.level) && is.inRange(inputOptions.openSlide.level, 0, 256)) { + inputDescriptor.level = inputOptions.openSlide.level; + } else { + throw is.invalidParameterError('openSlide.level', 'integer between 0 and 256', inputOptions.openSlide.level); + } + } else if (is.defined(inputOptions.level)) { + // Deprecated if (is.integer(inputOptions.level) && is.inRange(inputOptions.level, 0, 256)) { inputDescriptor.level = inputOptions.level; } else { throw is.invalidParameterError('level', 'integer between 0 and 256', inputOptions.level); } } - // Sub Image File Directory (TIFF) - if (is.defined(inputOptions.subifd)) { + // TIFF specific options + if (is.object(inputOptions.tiff) && is.defined(inputOptions.tiff.subifd)) { + if (is.integer(inputOptions.tiff.subifd) && is.inRange(inputOptions.tiff.subifd, -1, 100000)) { + inputDescriptor.subifd = inputOptions.tiff.subifd; + } else { + throw is.invalidParameterError('tiff.subifd', 'integer between -1 and 100000', inputOptions.tiff.subifd); + } + } else if (is.defined(inputOptions.subifd)) { + // Deprecated if (is.integer(inputOptions.subifd) && is.inRange(inputOptions.subifd, -1, 100000)) { inputDescriptor.subifd = inputOptions.subifd; } else { throw is.invalidParameterError('subifd', 'integer between -1 and 100000', inputOptions.subifd); } } - // PDF background colour - if (is.defined(inputOptions.pdfBackground)) { + // PDF specific options + if (is.object(inputOptions.pdf) && is.defined(inputOptions.pdf.background)) { + inputDescriptor.pdfBackground = this._getBackgroundColourOption(inputOptions.pdf.background); + } else if (is.defined(inputOptions.pdfBackground)) { + // Deprecated inputDescriptor.pdfBackground = this._getBackgroundColourOption(inputOptions.pdfBackground); } - // JP2 oneshot - if (is.defined(inputOptions.jp2Oneshot)) { - if (is.bool(inputOptions.jp2Oneshot)) { - inputDescriptor.jp2Oneshot = inputOptions.jp2Oneshot; + // JPEG 2000 specific options + if (is.object(inputOptions.jp2) && is.defined(inputOptions.jp2.oneshot)) { + if (is.bool(inputOptions.jp2.oneshot)) { + inputDescriptor.jp2Oneshot = inputOptions.jp2.oneshot; } else { - throw is.invalidParameterError('jp2Oneshot', 'boolean', inputOptions.jp2Oneshot); + throw is.invalidParameterError('jp2.oneshot', 'boolean', inputOptions.jp2.oneshot); } } // Create new image diff --git a/test/types/sharp.test-d.ts b/test/types/sharp.test-d.ts index eb1b3bb7b..8575f1e69 100644 --- a/test/types/sharp.test-d.ts +++ b/test/types/sharp.test-d.ts @@ -435,9 +435,6 @@ sharp('input.jpg').clahe({ width: 10, height: 10, maxSlope: 5 }).toFile('outfile // Support `unlimited` input option sharp('input.png', { unlimited: true }).resize(320, 240).toFile('outfile.png'); -// Support `subifd` input option for tiffs -sharp('input.tiff', { subifd: 3 }).resize(320, 240).toFile('outfile.png'); - // Support creating with noise sharp({ create: { @@ -720,13 +717,19 @@ sharp(input).composite([ } ]) +// Support format-specific input options const colour: sharp.Colour = '#fff'; const color: sharp.Color = '#fff'; -sharp({ pdfBackground: colour }); -sharp({ pdfBackground: color }); - -sharp({ jp2Oneshot: true }); -sharp({ jp2Oneshot: false }); +sharp({ pdf: { background: colour } }); +sharp({ pdf: { background: color } }); +sharp({ pdfBackground: colour }); // Deprecated +sharp({ pdfBackground: color }); // Deprecated +sharp({ tiff: { subifd: 3 } }); +sharp({ subifd: 3 }); // Deprecated +sharp({ openSlide: { level: 0 } }); +sharp({ level: 0 }); // Deprecated +sharp({ jp2: { oneshot: true } }); +sharp({ jp2: { oneshot: false } }); sharp({ autoOrient: true }); sharp({ autoOrient: false }); diff --git a/test/unit/io.js b/test/unit/io.js index 038bfe1f8..a2ee4eb55 100644 --- a/test/unit/io.js +++ b/test/unit/io.js @@ -867,52 +867,91 @@ describe('Input/output', function () { sharp({ pages: '1' }); }, /Expected integer between -1 and 100000 for pages but received 1 of type string/); }); - it('Valid level property', function () { + it('Valid openSlide.level property', function () { + sharp({ openSlide: { level: 1 } }); sharp({ level: 1 }); }); - it('Invalid level property (string) throws', function () { - assert.throws(function () { - sharp({ level: '1' }); - }, /Expected integer between 0 and 256 for level but received 1 of type string/); - }); - it('Invalid level property (negative) throws', function () { - assert.throws(function () { - sharp({ level: -1 }); - }, /Expected integer between 0 and 256 for level but received -1 of type number/); - }); - it('Valid subifd property', function () { + it('Invalid openSlide.level property (string) throws', function () { + assert.throws( + () => sharp({ openSlide: { level: '1' } }), + /Expected integer between 0 and 256 for openSlide.level but received 1 of type string/ + ); + assert.throws( + () => sharp({ level: '1' }), + /Expected integer between 0 and 256 for level but received 1 of type string/ + ); + }); + it('Invalid openSlide.level property (negative) throws', function () { + assert.throws( + () => sharp({ openSlide: { level: -1 } }), + /Expected integer between 0 and 256 for openSlide\.level but received -1 of type number/ + ); + assert.throws( + () => sharp({ level: -1 }), + /Expected integer between 0 and 256 for level but received -1 of type number/ + ); + }); + it('Valid tiff.subifd property', function () { + sharp({ tiff: { subifd: 1 } }); sharp({ subifd: 1 }); }); - it('Invalid subifd property (string) throws', function () { - assert.throws(function () { - sharp({ subifd: '1' }); - }, /Expected integer between -1 and 100000 for subifd but received 1 of type string/); - }); - it('Invalid subifd property (float) throws', function () { - assert.throws(function () { - sharp({ subifd: 1.2 }); - }, /Expected integer between -1 and 100000 for subifd but received 1.2 of type number/); - }); - it('Valid pdfBackground property (string)', function () { + it('Invalid tiff.subifd property (string) throws', function () { + assert.throws( + () => sharp({ tiff: { subifd: '1' } }), + /Expected integer between -1 and 100000 for tiff\.subifd but received 1 of type string/ + ); + assert.throws( + () => sharp({ subifd: '1' }), + /Expected integer between -1 and 100000 for subifd but received 1 of type string/ + ); + }); + it('Invalid tiff.subifd property (float) throws', function () { + assert.throws( + () => sharp({ tiff: { subifd: 1.2 } }), + /Expected integer between -1 and 100000 for tiff\.subifd but received 1.2 of type number/ + ); + assert.throws( + () => sharp({ subifd: 1.2 }), + /Expected integer between -1 and 100000 for subifd but received 1.2 of type number/ + ); + }); + it('Valid pdf.background property (string)', function () { + sharp({ pdf: { background: '#00ff00' } }); sharp({ pdfBackground: '#00ff00' }); }); - it('Valid pdfBackground property (object)', function () { + it('Valid pdf.background property (object)', function () { + sharp({ pdf: { background: { r: 0, g: 255, b: 0 } } }); sharp({ pdfBackground: { r: 0, g: 255, b: 0 } }); }); - it('Invalid pdfBackground property (string) throws', function () { - assert.throws(function () { - sharp({ pdfBackground: '00ff00' }); - }, /Unable to parse color from string/); - }); - it('Invalid pdfBackground property (number) throws', function () { - assert.throws(function () { - sharp({ pdfBackground: 255 }); - }, /Expected object or string for background/); - }); - it('Invalid pdfBackground property (object)', function () { - assert.throws(function () { - sharp({ pdfBackground: { red: 0, green: 255, blue: 0 } }); - }, /Unable to parse color from object/); + it('Invalid pdf.background property (string) throws', function () { + assert.throws( + () => sharp({ pdf: { background: '00ff00' } }), + /Unable to parse color from string/ + ); + assert.throws( + () => sharp({ pdfBackground: '00ff00' }), + /Unable to parse color from string/ + ); + }); + it('Invalid pdf.background property (number) throws', function () { + assert.throws( + () => sharp({ pdf: { background: 255 } }), + /Expected object or string for background/ + ); + assert.throws( + () => sharp({ pdf: { background: 255 } }), + /Expected object or string for background/ + ); + }); + it('Invalid pdf.background property (object)', function () { + assert.throws( + () => sharp({ pdf: { background: { red: 0, green: 255, blue: 0 } } }), + /Unable to parse color from object/ + ); + assert.throws( + () => sharp({ pdfBackground: { red: 0, green: 255, blue: 0 } }), + /Unable to parse color from object/ + ); }); }); diff --git a/test/unit/jp2.js b/test/unit/jp2.js index ff04fe727..3fd2f4a65 100644 --- a/test/unit/jp2.js +++ b/test/unit/jp2.js @@ -117,14 +117,14 @@ describe('JP2 output', () => { it('valid JP2 oneshot value does not throw error', () => { assert.doesNotThrow( - () => sharp(fixtures.inputJp2TileParts, { jp2Oneshot: true }) + () => sharp({ jp2: { oneshot: true } }) ); }); it('invalid JP2 oneshot value throws error', () => { assert.throws( - () => sharp(fixtures.inputJp2TileParts, { jp2Oneshot: 'fail' }), - /Expected boolean for jp2Oneshot but received fail of type string/ + () => sharp({ jp2: { oneshot: 'fail' } }), + /Expected boolean for jp2.oneshot but received fail of type string/ ); }); }); From c4b1d80c350d0282c23ac5b8943594b27359ac07 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Mon, 16 Jun 2025 11:11:02 +0100 Subject: [PATCH 029/115] Expose stylesheet and highBitdepth SVG input params --- docs/src/content/docs/api-constructor.md | 3 ++ docs/src/content/docs/changelog.md | 2 ++ lib/constructor.js | 3 ++ lib/index.d.ts | 9 ++++++ lib/input.js | 36 ++++++++++++++++++++++-- src/common.cc | 11 ++++++++ src/common.h | 3 ++ test/types/sharp.test-d.ts | 3 ++ test/unit/svg.js | 35 +++++++++++++++++++++++ 9 files changed, 102 insertions(+), 3 deletions(-) diff --git a/docs/src/content/docs/api-constructor.md b/docs/src/content/docs/api-constructor.md index 7c7e8e9c9..139e08f45 100644 --- a/docs/src/content/docs/api-constructor.md +++ b/docs/src/content/docs/api-constructor.md @@ -80,6 +80,9 @@ where the overall height is the `pageHeight` multiplied by the number of `pages` | [options.join.valign] | string | "'top'" | vertical alignment style for images joined vertically (`'top'`, `'centre'`, `'center'`, `'bottom'`). | | [options.tiff] | Object | | Describes TIFF specific options. | | [options.tiff.subifd] | number | -1 | Sub Image File Directory to extract for OME-TIFF, defaults to main image. | +| [options.svg] | Object | | Describes SVG specific options. | +| [options.svg.stylesheet] | string | | Custom CSS for SVG input, applied with a User Origin during the CSS cascade. | +| [options.svg.highBitdepth] | boolean | false | Set to `true` to render SVG input at 32-bits per channel (128-bit) instead of 8-bits per channel (32-bit) RGBA. | | [options.pdf] | Object | | Describes PDF specific options. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick. | | [options.pdf.background] | string \| Object | | Background colour to use when PDF is partially transparent. Parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha. | | [options.openSlide] | Object | | Describes OpenSlide specific options. Requires the use of a globally-installed libvips compiled with support for OpenSlide. | diff --git a/docs/src/content/docs/changelog.md b/docs/src/content/docs/changelog.md index 125f774fd..d39669d76 100644 --- a/docs/src/content/docs/changelog.md +++ b/docs/src/content/docs/changelog.md @@ -14,6 +14,8 @@ Requires libvips v8.17.0 * Deprecate top-level, format-specific constructor parameters, e.g. `subifd` becomes `tiff.subifd`. +* Expose `stylesheet` and `highBitdepth` SVG input parameters. + * Expose `keepDuplicateFrames` GIF output parameter. * Expose JPEG 2000 `oneshot` decoder option. diff --git a/lib/constructor.js b/lib/constructor.js index 5d86c422c..daac3b5f9 100644 --- a/lib/constructor.js +++ b/lib/constructor.js @@ -190,6 +190,9 @@ const debuglog = util.debuglog('sharp'); * @param {string} [options.join.valign='top'] - vertical alignment style for images joined vertically (`'top'`, `'centre'`, `'center'`, `'bottom'`). * @param {Object} [options.tiff] - Describes TIFF specific options. * @param {number} [options.tiff.subifd=-1] - Sub Image File Directory to extract for OME-TIFF, defaults to main image. + * @param {Object} [options.svg] - Describes SVG specific options. + * @param {string} [options.svg.stylesheet] - Custom CSS for SVG input, applied with a User Origin during the CSS cascade. + * @param {boolean} [options.svg.highBitdepth=false] - Set to `true` to render SVG input at 32-bits per channel (128-bit) instead of 8-bits per channel (32-bit) RGBA. * @param {Object} [options.pdf] - Describes PDF specific options. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick. * @param {string|Object} [options.pdf.background] - Background colour to use when PDF is partially transparent. Parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha. * @param {Object} [options.openSlide] - Describes OpenSlide specific options. Requires the use of a globally-installed libvips compiled with support for OpenSlide. diff --git a/lib/index.d.ts b/lib/index.d.ts index 1ac6fc247..4b39148e8 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1005,6 +1005,8 @@ declare namespace sharp { page?: number | undefined; /** TIFF specific input options */ tiff?: TiffInputOptions | undefined; + /** SVG specific input options */ + svg?: SvgInputOptions | undefined; /** PDF specific input options */ pdf?: PdfInputOptions | undefined; /** OpenSlide specific input options */ @@ -1127,6 +1129,13 @@ declare namespace sharp { subifd?: number | undefined; } + interface SvgInputOptions { + /** Custom CSS for SVG input, applied with a User Origin during the CSS cascade. */ + stylesheet?: string | undefined; + /** Set to `true` to render SVG input at 32-bits per channel (128-bit) instead of 8-bits per channel (32-bit) RGBA. */ + highBitdepth?: boolean | undefined; + } + interface PdfInputOptions { /** Background colour to use when PDF is partially transparent. Requires the use of a globally-installed libvips compiled with support for PDFium, Poppler, ImageMagick or GraphicsMagick. */ background?: Colour | Color | undefined; diff --git a/lib/input.js b/lib/input.js index d15715558..26aa2f540 100644 --- a/lib/input.js +++ b/lib/input.js @@ -22,14 +22,27 @@ const align = { high: 'high' }; +const inputStreamParameters = [ + // Limits and error handling + 'failOn', 'limitInputPixels', 'unlimited', + // Format-generic + 'animated', 'autoOrient', 'density', 'ignoreIcc', 'page', 'pages', 'sequentialRead', + // Format-specific + 'jp2', 'openSlide', 'pdf', 'raw', 'svg', 'tiff', + // Deprecated + 'failOnError', 'level', 'pdfBackground', 'subifd' +]; + /** * Extract input options, if any, from an object. * @private */ function _inputOptionsFromObject (obj) { - const { raw, density, limitInputPixels, ignoreIcc, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd, pdfBackground, autoOrient, jp2Oneshot } = obj; - return [raw, density, limitInputPixels, ignoreIcc, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd, pdfBackground, autoOrient, jp2Oneshot].some(is.defined) - ? { raw, density, limitInputPixels, ignoreIcc, unlimited, sequentialRead, failOn, failOnError, animated, page, pages, subifd, pdfBackground, autoOrient, jp2Oneshot } + const params = inputStreamParameters + .filter(p => is.defined(obj[p])) + .map(p => ([p, obj[p]])); + return params.length + ? Object.fromEntries(params) : undefined; } @@ -260,6 +273,23 @@ function _createInputDescriptor (input, inputOptions, containerOptions) { throw is.invalidParameterError('subifd', 'integer between -1 and 100000', inputOptions.subifd); } } + // SVG specific options + if (is.object(inputOptions.svg)) { + if (is.defined(inputOptions.svg.stylesheet)) { + if (is.string(inputOptions.svg.stylesheet)) { + inputDescriptor.svgStylesheet = inputOptions.svg.stylesheet; + } else { + throw is.invalidParameterError('svg.stylesheet', 'string', inputOptions.svg.stylesheet); + } + } + if (is.defined(inputOptions.svg.highBitdepth)) { + if (is.bool(inputOptions.svg.highBitdepth)) { + inputDescriptor.svgHighBitdepth = inputOptions.svg.highBitdepth; + } else { + throw is.invalidParameterError('svg.highBitdepth', 'boolean', inputOptions.svg.highBitdepth); + } + } + } // PDF specific options if (is.object(inputOptions.pdf) && is.defined(inputOptions.pdf.background)) { inputDescriptor.pdfBackground = this._getBackgroundColourOption(inputOptions.pdf.background); diff --git a/src/common.cc b/src/common.cc index 57ae4aef5..324370685 100644 --- a/src/common.cc +++ b/src/common.cc @@ -101,6 +101,13 @@ namespace sharp { if (HasAttr(input, "page")) { descriptor->page = AttrAsUint32(input, "page"); } + // SVG + if (HasAttr(input, "svgStylesheet")) { + descriptor->svgStylesheet = AttrAsStr(input, "svgStylesheet"); + } + if (HasAttr(input, "svgHighBitdepth")) { + descriptor->svgHighBitdepth = AttrAsBool(input, "svgHighBitdepth"); + } // Multi-level input (OpenSlide) if (HasAttr(input, "level")) { descriptor->level = AttrAsUint32(input, "level"); @@ -429,6 +436,10 @@ namespace sharp { option->set("n", descriptor->pages); option->set("page", descriptor->page); } + if (imageType == ImageType::SVG) { + option->set("stylesheet", descriptor->svgStylesheet.data()); + option->set("high_bitdepth", descriptor->svgHighBitdepth); + } if (imageType == ImageType::OPENSLIDE) { option->set("level", descriptor->level); } diff --git a/src/common.h b/src/common.h index b926972bf..0b37dbebc 100644 --- a/src/common.h +++ b/src/common.h @@ -77,6 +77,8 @@ namespace sharp { std::vector joinBackground; VipsAlign joinHalign; VipsAlign joinValign; + std::string svgStylesheet; + bool svgHighBitdepth; std::vector pdfBackground; bool jp2Oneshot; @@ -121,6 +123,7 @@ namespace sharp { joinBackground{ 0.0, 0.0, 0.0, 255.0 }, joinHalign(VIPS_ALIGN_LOW), joinValign(VIPS_ALIGN_LOW), + svgHighBitdepth(false), pdfBackground{ 255.0, 255.0, 255.0, 255.0 }, jp2Oneshot(false) {} }; diff --git a/test/types/sharp.test-d.ts b/test/types/sharp.test-d.ts index 8575f1e69..d00cbd29b 100644 --- a/test/types/sharp.test-d.ts +++ b/test/types/sharp.test-d.ts @@ -730,6 +730,9 @@ sharp({ openSlide: { level: 0 } }); sharp({ level: 0 }); // Deprecated sharp({ jp2: { oneshot: true } }); sharp({ jp2: { oneshot: false } }); +sharp({ svg: { stylesheet: 'test' }}); +sharp({ svg: { highBitdepth: true }}); +sharp({ svg: { highBitdepth: false }}); sharp({ autoOrient: true }); sharp({ autoOrient: false }); diff --git a/test/unit/svg.js b/test/unit/svg.js index 8f147b0a7..6591cf2dc 100644 --- a/test/unit/svg.js +++ b/test/unit/svg.js @@ -139,6 +139,41 @@ describe('SVG input', function () { assert.strictEqual(info.channels, 4); }); + it('Can apply custom CSS', async () => { + const svg = ` + + + `; + const stylesheet = 'circle { fill: red }'; + + const [r, g, b, a] = await sharp(Buffer.from(svg), { svg: { stylesheet } }) + .extract({ left: 5, top: 5, width: 1, height: 1 }) + .raw() + .toBuffer(); + + assert.deepEqual([r, g, b, a], [255, 0, 0, 255]); + }); + + it('Invalid stylesheet input option throws', () => + assert.throws( + () => sharp({ svg: { stylesheet: 123 } }), + /Expected string for svg\.stylesheet but received 123 of type number/ + ) + ); + + it('Valid highBitdepth input option does not throw', () => + assert.doesNotThrow( + () => sharp({ svg: { highBitdepth: true } }) + ) + ); + + it('Invalid highBitdepth input option throws', () => + assert.throws( + () => sharp({ svg: { highBitdepth: 123 } }), + /Expected boolean for svg\.highBitdepth but received 123 of type number/ + ) + ); + it('Fails to render SVG larger than 32767x32767', () => assert.rejects( () => sharp(Buffer.from('')).toBuffer(), From e688c536591df712001933be1ca4d5c685199f87 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Mon, 16 Jun 2025 12:02:09 +0100 Subject: [PATCH 030/115] Docs: expand info about parallelism and concurrency control #4411 --- docs/src/content/docs/api-utility.md | 12 ++----- docs/src/content/docs/performance.md | 48 +++++++++++++++++++++++----- lib/utility.js | 12 ++----- 3 files changed, 46 insertions(+), 26 deletions(-) diff --git a/docs/src/content/docs/api-utility.md b/docs/src/content/docs/api-utility.md index 8a7ef2483..b2ac16861 100644 --- a/docs/src/content/docs/api-utility.md +++ b/docs/src/content/docs/api-utility.md @@ -113,15 +113,9 @@ Some image format libraries spawn additional threads, e.g. libaom manages its own 4 threads when encoding AVIF images, and these are independent of the value set here. -The maximum number of images that sharp can process in parallel -is controlled by libuv's `UV_THREADPOOL_SIZE` environment variable, -which defaults to 4. - -https://nodejs.org/api/cli.html#uv_threadpool_sizesize - -For example, by default, a machine with 8 CPU cores will process -4 images in parallel and use up to 8 threads per image, -so there will be up to 32 concurrent threads. +:::note +Further [control over performance](/performance) is available. +::: **Returns**: number - concurrency diff --git a/docs/src/content/docs/performance.md b/docs/src/content/docs/performance.md index e61cfd6f8..cc75a44c3 100644 --- a/docs/src/content/docs/performance.md +++ b/docs/src/content/docs/performance.md @@ -2,6 +2,38 @@ title: Performance --- +## Parallelism and concurrency + +Node.js uses a libuv-managed thread pool when processing asynchronous calls to native modules such as sharp. + +The maximum number of images that sharp can process in parallel is controlled by libuv's +[`UV_THREADPOOL_SIZE`](https://nodejs.org/api/cli.html#uv_threadpool_sizesize) +environment variable, which defaults to 4. + +When using more than 4 physical CPU cores, set this environment variable +before the Node.js process starts to increase the thread pool size. + +```sh +export UV_THREADPOOL_SIZE="$(lscpu -p | egrep -v "^#" | sort -u -t, -k 2,4 | wc -l)" +``` + +libvips uses a glib-managed thread pool to avoid the overhead of spawning new threads. + +The default number of threads used to concurrently process each image is the same as the number of CPU cores, +except when using glibc-based Linux without jemalloc, where the default is `1` to help reduce memory fragmentation. + +Use [`sharp.concurrency()`](/api-utility/#concurrency) to manage the number of threads per image. + +To reduce memory fragmentation when using the default Linux glibc memory allocator, set the +[`MALLOC_ARENA_MAX`](https://www.gnu.org/software/libc/manual/html_node/Memory-Allocation-Tunables.html) +environment variable before the Node.js process starts to reduce the number of memory pools. + +```sh +export MALLOC_ARENA_MAX="2" +``` + +## Benchmark + A test to benchmark the performance of this module relative to alternatives. Greater libvips performance can be expected with caching enabled (default) @@ -9,28 +41,28 @@ and using 8+ core machines, especially those with larger L1/L2 CPU caches. The I/O limits of the relevant (de)compression library will generally determine maximum throughput. -## Contenders +### Contenders * [jimp](https://www.npmjs.com/package/jimp) v1.6.0 - Image processing in pure JavaScript. * [imagemagick](https://www.npmjs.com/package/imagemagick) v0.1.3 - Supports filesystem only and "*has been unmaintained for a long time*". * [gm](https://www.npmjs.com/package/gm) v1.25.1 - Fully featured wrapper around GraphicsMagick's `gm` command line utility, but "*has been sunset*". * sharp v0.34.0 / libvips v8.16.1 - Caching within libvips disabled to ensure a fair comparison. -## Environment +### Environment -### AMD64 +#### AMD64 * AWS EC2 us-west-2 [c7a.xlarge](https://aws.amazon.com/ec2/instance-types/c7a/) (4x AMD EPYC 9R14) * Ubuntu 24.10 [fad5ba7223f8](https://hub.docker.com/layers/library/ubuntu/24.10/images/sha256-fad5ba7223f8d87179dfa23211d31845d47e07a474ac31ad5258afb606523c0d) * Node.js 22.14.0 -### ARM64 +#### ARM64 * AWS EC2 us-west-2 [c8g.xlarge](https://aws.amazon.com/ec2/instance-types/c8g/) (4x ARM Graviton4) * Ubuntu 24.10 [133f2e05cb69](https://hub.docker.com/layers/library/ubuntu/24.10/images/sha256-133f2e05cb6958c3ce7ec870fd5a864558ba780fb7062315b51a23670bff7e76) * Node.js 22.14.0 -## Task: JPEG +### Task: JPEG Decompress a 2725x2225 JPEG image, resize to 720x588 using Lanczos 3 resampling (where available), @@ -62,7 +94,7 @@ Note: jimp does not support Lanczos 3, bicubic resampling used instead. | sharp | file | file | 48.42 | 22.7 | | sharp | buffer | buffer | 50.16 | 23.6 | -## Task: PNG +### Task: PNG Decompress a 2048x1536 RGBA PNG image, premultiply the alpha channel, @@ -72,7 +104,7 @@ and without adaptive filtering. Note: jimp does not support premultiply/unpremultiply. -### Results: PNG (AMD64) +#### Results: PNG (AMD64) | Module | Input | Output | Ops/sec | Speed-up | | :----------------- | :----- | :----- | ------: | -------: | @@ -82,7 +114,7 @@ Note: jimp does not support premultiply/unpremultiply. | sharp | file | file | 27.93 | 3.2 | | sharp | buffer | buffer | 28.69 | 3.3 | -### Results: PNG (ARM64) +#### Results: PNG (ARM64) | Module | Input | Output | Ops/sec | Speed-up | | :----------------- | :----- | :----- | ------: | -------: | diff --git a/lib/utility.js b/lib/utility.js index 3c7286fb9..4b11892d5 100644 --- a/lib/utility.js +++ b/lib/utility.js @@ -135,15 +135,9 @@ cache(true); * e.g. libaom manages its own 4 threads when encoding AVIF images, * and these are independent of the value set here. * - * The maximum number of images that sharp can process in parallel - * is controlled by libuv's `UV_THREADPOOL_SIZE` environment variable, - * which defaults to 4. - * - * https://nodejs.org/api/cli.html#uv_threadpool_sizesize - * - * For example, by default, a machine with 8 CPU cores will process - * 4 images in parallel and use up to 8 threads per image, - * so there will be up to 32 concurrent threads. + * :::note + * Further {@link /performance|control over performance} is available. + * ::: * * @example * const threads = sharp.concurrency(); // 4 From 76995deefa8617cd1fd6d69cc6461e16a4fad78f Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Mon, 16 Jun 2025 16:45:19 +0200 Subject: [PATCH 031/115] Ensure SVG scale-on-load optimisation uses newly exposed params (#4415) Follow-up to commit c4b1d80. --- src/pipeline.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pipeline.cc b/src/pipeline.cc index e353cc728..32bb919f4 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -276,6 +276,8 @@ class PipelineWorker : public Napi::AsyncWorker { } else if (inputImageType == sharp::ImageType::SVG) { option->set("unlimited", baton->input->unlimited); option->set("dpi", baton->input->density); + option->set("stylesheet", baton->input->svgStylesheet.data()); + option->set("high_bitdepth", baton->input->svgHighBitdepth); if (baton->input->buffer != nullptr) { // Reload SVG buffer From e286e2bff9ac7142cc32c6a476fe5d9e45f3d23b Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Tue, 17 Jun 2025 10:15:40 +0100 Subject: [PATCH 032/115] Build format-specific input options in a single function --- src/common.cc | 101 ++++++++++++++++++++---------------------------- src/common.h | 9 +---- src/pipeline.cc | 25 +----------- 3 files changed, 45 insertions(+), 90 deletions(-) diff --git a/src/common.cc b/src/common.cc index 324370685..be285327f 100644 --- a/src/common.cc +++ b/src/common.cc @@ -394,6 +394,45 @@ namespace sharp { imageType == ImageType::HEIF; } + /* + Format-specific options builder + */ + vips::VOption* GetOptionsForImageType(ImageType imageType, InputDescriptor *descriptor) { + vips::VOption *option = VImage::option() + ->set("access", descriptor->access) + ->set("fail_on", descriptor->failOn); + if (descriptor->unlimited && ImageTypeSupportsUnlimited(imageType)) { + option->set("unlimited", true); + } + if (imageType == ImageType::SVG || imageType == ImageType::PDF) { + option->set("dpi", descriptor->density); + } + if (imageType == ImageType::MAGICK) { + option->set("density", std::to_string(descriptor->density).data()); + } + if (ImageTypeSupportsPage(imageType)) { + option->set("n", descriptor->pages); + option->set("page", descriptor->page); + } + if (imageType == ImageType::SVG) { + option->set("stylesheet", descriptor->svgStylesheet.data()); + option->set("high_bitdepth", descriptor->svgHighBitdepth); + } + if (imageType == ImageType::OPENSLIDE) { + option->set("level", descriptor->level); + } + if (imageType == ImageType::TIFF) { + option->set("subifd", descriptor->subifd); + } + if (imageType == ImageType::PDF) { + option->set("background", descriptor->pdfBackground); + } + if (imageType == ImageType::JP2) { + option->set("oneshot", descriptor->jp2Oneshot); + } + return option; + } + /* Open an image from the given InputDescriptor (filesystem, compressed buffer, raw pixel data) */ @@ -420,38 +459,7 @@ namespace sharp { imageType = DetermineImageType(descriptor->buffer, descriptor->bufferLength); if (imageType != ImageType::UNKNOWN) { try { - vips::VOption *option = VImage::option() - ->set("access", descriptor->access) - ->set("fail_on", descriptor->failOn); - if (descriptor->unlimited && ImageTypeSupportsUnlimited(imageType)) { - option->set("unlimited", true); - } - if (imageType == ImageType::SVG || imageType == ImageType::PDF) { - option->set("dpi", descriptor->density); - } - if (imageType == ImageType::MAGICK) { - option->set("density", std::to_string(descriptor->density).data()); - } - if (ImageTypeSupportsPage(imageType)) { - option->set("n", descriptor->pages); - option->set("page", descriptor->page); - } - if (imageType == ImageType::SVG) { - option->set("stylesheet", descriptor->svgStylesheet.data()); - option->set("high_bitdepth", descriptor->svgHighBitdepth); - } - if (imageType == ImageType::OPENSLIDE) { - option->set("level", descriptor->level); - } - if (imageType == ImageType::TIFF) { - option->set("subifd", descriptor->subifd); - } - if (imageType == ImageType::PDF) { - option->set("background", descriptor->pdfBackground); - } - if (imageType == ImageType::JP2) { - option->set("oneshot", descriptor->jp2Oneshot); - } + vips::VOption *option = GetOptionsForImageType(imageType, descriptor); image = VImage::new_from_buffer(descriptor->buffer, descriptor->bufferLength, nullptr, option); if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) { image = SetDensity(image, descriptor->density); @@ -534,34 +542,7 @@ namespace sharp { } if (imageType != ImageType::UNKNOWN) { try { - vips::VOption *option = VImage::option() - ->set("access", descriptor->access) - ->set("fail_on", descriptor->failOn); - if (descriptor->unlimited && ImageTypeSupportsUnlimited(imageType)) { - option->set("unlimited", true); - } - if (imageType == ImageType::SVG || imageType == ImageType::PDF) { - option->set("dpi", descriptor->density); - } - if (imageType == ImageType::MAGICK) { - option->set("density", std::to_string(descriptor->density).data()); - } - if (ImageTypeSupportsPage(imageType)) { - option->set("n", descriptor->pages); - option->set("page", descriptor->page); - } - if (imageType == ImageType::OPENSLIDE) { - option->set("level", descriptor->level); - } - if (imageType == ImageType::TIFF) { - option->set("subifd", descriptor->subifd); - } - if (imageType == ImageType::PDF) { - option->set("background", descriptor->pdfBackground); - } - if (imageType == ImageType::JP2) { - option->set("oneshot", descriptor->jp2Oneshot); - } + vips::VOption *option = GetOptionsForImageType(imageType, descriptor); image = VImage::new_from_file(descriptor->file.data(), option); if (imageType == ImageType::SVG || imageType == ImageType::PDF || imageType == ImageType::MAGICK) { image = SetDensity(image, descriptor->density); diff --git a/src/common.h b/src/common.h index 0b37dbebc..37955cf7e 100644 --- a/src/common.h +++ b/src/common.h @@ -221,14 +221,9 @@ namespace sharp { ImageType DetermineImageType(char const *file); /* - Does this image type support multiple pages? + Format-specific options builder */ - bool ImageTypeSupportsPage(ImageType imageType); - - /* - Does this image type support removal of safety limits? - */ - bool ImageTypeSupportsUnlimited(ImageType imageType); + vips::VOption* GetOptionsForImageType(ImageType imageType, InputDescriptor *descriptor); /* Open an image from the given InputDescriptor (filesystem, compressed buffer, raw pixel data) diff --git a/src/pipeline.cc b/src/pipeline.cc index 32bb919f4..bddec2bac 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -241,11 +241,7 @@ class PipelineWorker : public Napi::AsyncWorker { // factor for jpegload*, a double scale factor for webpload*, // pdfload* and svgload* if (jpegShrinkOnLoad > 1) { - vips::VOption *option = VImage::option() - ->set("access", access) - ->set("shrink", jpegShrinkOnLoad) - ->set("unlimited", baton->input->unlimited) - ->set("fail_on", baton->input->failOn); + vips::VOption *option = GetOptionsForImageType(inputImageType, baton->input)->set("shrink", jpegShrinkOnLoad); if (baton->input->buffer != nullptr) { // Reload JPEG buffer VipsBlob *blob = vips_blob_new(nullptr, baton->input->buffer, baton->input->bufferLength); @@ -256,14 +252,8 @@ class PipelineWorker : public Napi::AsyncWorker { image = VImage::jpegload(const_cast(baton->input->file.data()), option); } } else if (scale != 1.0) { - vips::VOption *option = VImage::option() - ->set("access", access) - ->set("scale", scale) - ->set("fail_on", baton->input->failOn); + vips::VOption *option = GetOptionsForImageType(inputImageType, baton->input)->set("scale", scale); if (inputImageType == sharp::ImageType::WEBP) { - option->set("n", baton->input->pages); - option->set("page", baton->input->page); - if (baton->input->buffer != nullptr) { // Reload WebP buffer VipsBlob *blob = vips_blob_new(nullptr, baton->input->buffer, baton->input->bufferLength); @@ -274,11 +264,6 @@ class PipelineWorker : public Napi::AsyncWorker { image = VImage::webpload(const_cast(baton->input->file.data()), option); } } else if (inputImageType == sharp::ImageType::SVG) { - option->set("unlimited", baton->input->unlimited); - option->set("dpi", baton->input->density); - option->set("stylesheet", baton->input->svgStylesheet.data()); - option->set("high_bitdepth", baton->input->svgHighBitdepth); - if (baton->input->buffer != nullptr) { // Reload SVG buffer VipsBlob *blob = vips_blob_new(nullptr, baton->input->buffer, baton->input->bufferLength); @@ -293,11 +278,6 @@ class PipelineWorker : public Napi::AsyncWorker { throw vips::VError("Input SVG image will exceed 32767x32767 pixel limit when scaled"); } } else if (inputImageType == sharp::ImageType::PDF) { - option->set("n", baton->input->pages); - option->set("page", baton->input->page); - option->set("dpi", baton->input->density); - option->set("background", baton->input->pdfBackground); - if (baton->input->buffer != nullptr) { // Reload PDF buffer VipsBlob *blob = vips_blob_new(nullptr, baton->input->buffer, baton->input->bufferLength); @@ -307,7 +287,6 @@ class PipelineWorker : public Napi::AsyncWorker { // Reload PDF file image = VImage::pdfload(const_cast(baton->input->file.data()), option); } - sharp::SetDensity(image, baton->input->density); } } else { From 852c7f8663709a5260b6099fe0a8937f275897e0 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Tue, 17 Jun 2025 13:24:55 +0100 Subject: [PATCH 033/115] Clean up internal naming of format-specific input options --- lib/input.js | 10 +++++----- src/common.cc | 51 +++++++++++++++++++++++++++------------------------ src/common.h | 8 ++++---- 3 files changed, 36 insertions(+), 33 deletions(-) diff --git a/lib/input.js b/lib/input.js index 26aa2f540..436bfb753 100644 --- a/lib/input.js +++ b/lib/input.js @@ -30,7 +30,7 @@ const inputStreamParameters = [ // Format-specific 'jp2', 'openSlide', 'pdf', 'raw', 'svg', 'tiff', // Deprecated - 'failOnError', 'level', 'pdfBackground', 'subifd' + 'failOnError', 'openSlideLevel', 'pdfBackground', 'tiffSubifd' ]; /** @@ -246,14 +246,14 @@ function _createInputDescriptor (input, inputOptions, containerOptions) { // OpenSlide specific options if (is.object(inputOptions.openSlide) && is.defined(inputOptions.openSlide.level)) { if (is.integer(inputOptions.openSlide.level) && is.inRange(inputOptions.openSlide.level, 0, 256)) { - inputDescriptor.level = inputOptions.openSlide.level; + inputDescriptor.openSlideLevel = inputOptions.openSlide.level; } else { throw is.invalidParameterError('openSlide.level', 'integer between 0 and 256', inputOptions.openSlide.level); } } else if (is.defined(inputOptions.level)) { // Deprecated if (is.integer(inputOptions.level) && is.inRange(inputOptions.level, 0, 256)) { - inputDescriptor.level = inputOptions.level; + inputDescriptor.openSlideLevel = inputOptions.level; } else { throw is.invalidParameterError('level', 'integer between 0 and 256', inputOptions.level); } @@ -261,14 +261,14 @@ function _createInputDescriptor (input, inputOptions, containerOptions) { // TIFF specific options if (is.object(inputOptions.tiff) && is.defined(inputOptions.tiff.subifd)) { if (is.integer(inputOptions.tiff.subifd) && is.inRange(inputOptions.tiff.subifd, -1, 100000)) { - inputDescriptor.subifd = inputOptions.tiff.subifd; + inputDescriptor.tiffSubifd = inputOptions.tiff.subifd; } else { throw is.invalidParameterError('tiff.subifd', 'integer between -1 and 100000', inputOptions.tiff.subifd); } } else if (is.defined(inputOptions.subifd)) { // Deprecated if (is.integer(inputOptions.subifd) && is.inRange(inputOptions.subifd, -1, 100000)) { - inputDescriptor.subifd = inputOptions.subifd; + inputDescriptor.tiffSubifd = inputOptions.subifd; } else { throw is.invalidParameterError('subifd', 'integer between -1 and 100000', inputOptions.subifd); } diff --git a/src/common.cc b/src/common.cc index be285327f..e465dc2f7 100644 --- a/src/common.cc +++ b/src/common.cc @@ -109,12 +109,12 @@ namespace sharp { descriptor->svgHighBitdepth = AttrAsBool(input, "svgHighBitdepth"); } // Multi-level input (OpenSlide) - if (HasAttr(input, "level")) { - descriptor->level = AttrAsUint32(input, "level"); + if (HasAttr(input, "openSlideLevel")) { + descriptor->openSlideLevel = AttrAsUint32(input, "openSlideLevel"); } // subIFD (OME-TIFF) if (HasAttr(input, "subifd")) { - descriptor->subifd = AttrAsInt32(input, "subifd"); + descriptor->tiffSubifd = AttrAsInt32(input, "tiffSubifd"); } // // PDF background color if (HasAttr(input, "pdfBackground")) { @@ -404,31 +404,34 @@ namespace sharp { if (descriptor->unlimited && ImageTypeSupportsUnlimited(imageType)) { option->set("unlimited", true); } - if (imageType == ImageType::SVG || imageType == ImageType::PDF) { - option->set("dpi", descriptor->density); - } - if (imageType == ImageType::MAGICK) { - option->set("density", std::to_string(descriptor->density).data()); - } if (ImageTypeSupportsPage(imageType)) { option->set("n", descriptor->pages); option->set("page", descriptor->page); } - if (imageType == ImageType::SVG) { - option->set("stylesheet", descriptor->svgStylesheet.data()); - option->set("high_bitdepth", descriptor->svgHighBitdepth); - } - if (imageType == ImageType::OPENSLIDE) { - option->set("level", descriptor->level); - } - if (imageType == ImageType::TIFF) { - option->set("subifd", descriptor->subifd); - } - if (imageType == ImageType::PDF) { - option->set("background", descriptor->pdfBackground); - } - if (imageType == ImageType::JP2) { - option->set("oneshot", descriptor->jp2Oneshot); + switch (imageType) { + case ImageType::SVG: + option->set("dpi", descriptor->density) + ->set("stylesheet", descriptor->svgStylesheet.data()) + ->set("high_bitdepth", descriptor->svgHighBitdepth); + break; + case ImageType::TIFF: + option->set("tiffSubifd", descriptor->tiffSubifd); + break; + case ImageType::PDF: + option->set("dpi", descriptor->density) + ->set("background", descriptor->pdfBackground); + break; + case ImageType::OPENSLIDE: + option->set("openSlideLevel", descriptor->openSlideLevel); + break; + case ImageType::JP2: + option->set("oneshot", descriptor->jp2Oneshot); + break; + case ImageType::MAGICK: + option->set("density", std::to_string(descriptor->density).data()); + break; + default: + break; } return option; } diff --git a/src/common.h b/src/common.h index 37955cf7e..e199942d1 100644 --- a/src/common.h +++ b/src/common.h @@ -50,8 +50,6 @@ namespace sharp { bool rawPremultiplied; int pages; int page; - int level; - int subifd; int createChannels; int createWidth; int createHeight; @@ -79,6 +77,8 @@ namespace sharp { VipsAlign joinValign; std::string svgStylesheet; bool svgHighBitdepth; + int tiffSubifd; + int openSlideLevel; std::vector pdfBackground; bool jp2Oneshot; @@ -100,8 +100,6 @@ namespace sharp { rawPremultiplied(false), pages(1), page(0), - level(0), - subifd(-1), createChannels(0), createWidth(0), createHeight(0), @@ -124,6 +122,8 @@ namespace sharp { joinHalign(VIPS_ALIGN_LOW), joinValign(VIPS_ALIGN_LOW), svgHighBitdepth(false), + tiffSubifd(-1), + openSlideLevel(0), pdfBackground{ 255.0, 255.0, 255.0, 255.0 }, jp2Oneshot(false) {} }; From e26d4e9d5b9207c9db575b6d1f73d40c1e892538 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Sat, 21 Jun 2025 11:33:52 +0100 Subject: [PATCH 034/115] Add pageHeight param to create/new for animated input #3236 --- docs/src/content/docs/api-constructor.md | 6 ++- docs/src/content/docs/changelog.md | 3 ++ lib/constructor.js | 6 ++- lib/index.d.ts | 7 ++- lib/input.js | 58 +++++++++++++++++++----- package.json | 6 +-- src/common.cc | 10 ++++ src/common.h | 4 ++ test/types/sharp.test-d.ts | 8 ++++ test/unit/noise.js | 45 ++++++++++++++++++ test/unit/raw.js | 46 +++++++++++++++++++ 11 files changed, 179 insertions(+), 20 deletions(-) diff --git a/docs/src/content/docs/api-constructor.md b/docs/src/content/docs/api-constructor.md index 139e08f45..3504239dc 100644 --- a/docs/src/content/docs/api-constructor.md +++ b/docs/src/content/docs/api-constructor.md @@ -50,15 +50,17 @@ where the overall height is the `pageHeight` multiplied by the number of `pages` | [options.raw.height] | number | | integral number of pixels high. | | [options.raw.channels] | number | | integral number of channels, between 1 and 4. | | [options.raw.premultiplied] | boolean | | specifies that the raw input has already been premultiplied, set to `true` to avoid sharp premultiplying the image. (optional, default `false`) | +| [options.raw.pageHeight] | number | | The pixel height of each page/frame for animated images, must be an integral factor of `raw.height`. | | [options.create] | Object | | describes a new image to be created. | | [options.create.width] | number | | integral number of pixels wide. | | [options.create.height] | number | | integral number of pixels high. | | [options.create.channels] | number | | integral number of channels, either 3 (RGB) or 4 (RGBA). | | [options.create.background] | string \| Object | | parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha. | +| [options.create.pageHeight] | number | | The pixel height of each page/frame for animated images, must be an integral factor of `create.height`. | | [options.create.noise] | Object | | describes a noise to be created. | | [options.create.noise.type] | string | | type of generated noise, currently only `gaussian` is supported. | -| [options.create.noise.mean] | number | | mean of pixels in generated noise. | -| [options.create.noise.sigma] | number | | standard deviation of pixels in generated noise. | +| [options.create.noise.mean] | number | 128 | Mean value of pixels in the generated noise. | +| [options.create.noise.sigma] | number | 30 | Standard deviation of pixel values in the generated noise. | | [options.text] | Object | | describes a new text image to be created. | | [options.text.text] | string | | text to render as a UTF-8 string. It can contain Pango markup, for example `LeMonde`. | | [options.text.font] | string | | font name to render with. | diff --git a/docs/src/content/docs/changelog.md b/docs/src/content/docs/changelog.md index d39669d76..0a248750b 100644 --- a/docs/src/content/docs/changelog.md +++ b/docs/src/content/docs/changelog.md @@ -18,6 +18,9 @@ Requires libvips v8.17.0 * Expose `keepDuplicateFrames` GIF output parameter. +* Add `pageHeight` option to `create` and `raw` input for animated images. + [#3236](https://github.com/lovell/sharp/issues/3236) + * Expose JPEG 2000 `oneshot` decoder option. [#4262](https://github.com/lovell/sharp/pull/4262) [@mbklein](https://github.com/mbklein) diff --git a/lib/constructor.js b/lib/constructor.js index daac3b5f9..e5d2a0c51 100644 --- a/lib/constructor.js +++ b/lib/constructor.js @@ -160,15 +160,17 @@ const debuglog = util.debuglog('sharp'); * @param {number} [options.raw.channels] - integral number of channels, between 1 and 4. * @param {boolean} [options.raw.premultiplied] - specifies that the raw input has already been premultiplied, set to `true` * to avoid sharp premultiplying the image. (optional, default `false`) + * @param {number} [options.raw.pageHeight] - The pixel height of each page/frame for animated images, must be an integral factor of `raw.height`. * @param {Object} [options.create] - describes a new image to be created. * @param {number} [options.create.width] - integral number of pixels wide. * @param {number} [options.create.height] - integral number of pixels high. * @param {number} [options.create.channels] - integral number of channels, either 3 (RGB) or 4 (RGBA). * @param {string|Object} [options.create.background] - parsed by the [color](https://www.npmjs.org/package/color) module to extract values for red, green, blue and alpha. + * @param {number} [options.create.pageHeight] - The pixel height of each page/frame for animated images, must be an integral factor of `create.height`. * @param {Object} [options.create.noise] - describes a noise to be created. * @param {string} [options.create.noise.type] - type of generated noise, currently only `gaussian` is supported. - * @param {number} [options.create.noise.mean] - mean of pixels in generated noise. - * @param {number} [options.create.noise.sigma] - standard deviation of pixels in generated noise. + * @param {number} [options.create.noise.mean=128] - Mean value of pixels in the generated noise. + * @param {number} [options.create.noise.sigma=30] - Standard deviation of pixel values in the generated noise. * @param {Object} [options.text] - describes a new text image to be created. * @param {string} [options.text.text] - text to render as a UTF-8 string. It can contain Pango markup, for example `LeMonde`. * @param {string} [options.text.font] - font name to render with. diff --git a/lib/index.d.ts b/lib/index.d.ts index 4b39148e8..395ec977d 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1061,6 +1061,8 @@ declare namespace sharp { interface CreateRaw extends Raw { /** Specifies that the raw input has already been premultiplied, set to true to avoid sharp premultiplying the image. (optional, default false) */ premultiplied?: boolean | undefined; + /** The height of each page/frame for animated images, must be an integral factor of the overall image height. */ + pageHeight?: number | undefined; } type CreateChannels = 3 | 4; @@ -1076,6 +1078,9 @@ declare namespace sharp { background: Colour | Color; /** Describes a noise to be created. */ noise?: Noise | undefined; + /** The height of each page/frame for animated images, must be an integral factor of the overall image height. */ + pageHeight?: number | undefined; + } interface CreateText { @@ -1549,7 +1554,7 @@ declare namespace sharp { interface Noise { /** type of generated noise, currently only gaussian is supported. */ - type?: 'gaussian' | undefined; + type: 'gaussian'; /** mean of pixels in generated noise. */ mean?: number | undefined; /** standard deviation of pixels in generated noise. */ diff --git a/lib/input.js b/lib/input.js index 436bfb753..ceb6d8549 100644 --- a/lib/input.js +++ b/lib/input.js @@ -185,8 +185,6 @@ function _createInputDescriptor (input, inputOptions, containerOptions) { inputDescriptor.rawWidth = inputOptions.raw.width; inputDescriptor.rawHeight = inputOptions.raw.height; inputDescriptor.rawChannels = inputOptions.raw.channels; - inputDescriptor.rawPremultiplied = !!inputOptions.raw.premultiplied; - switch (input.constructor) { case Uint8Array: case Uint8ClampedArray: @@ -220,6 +218,25 @@ function _createInputDescriptor (input, inputOptions, containerOptions) { } else { throw new Error('Expected width, height and channels for raw pixel input'); } + inputDescriptor.rawPremultiplied = false; + if (is.defined(inputOptions.raw.premultiplied)) { + if (is.bool(inputOptions.raw.premultiplied)) { + inputDescriptor.rawPremultiplied = inputOptions.raw.premultiplied; + } else { + throw is.invalidParameterError('raw.premultiplied', 'boolean', inputOptions.raw.premultiplied); + } + } + inputDescriptor.rawPageHeight = 0; + if (is.defined(inputOptions.raw.pageHeight)) { + if (is.integer(inputOptions.raw.pageHeight) && inputOptions.raw.pageHeight > 0 && inputOptions.raw.pageHeight <= inputOptions.raw.height) { + if (inputOptions.raw.height % inputOptions.raw.pageHeight !== 0) { + throw new Error(`Expected raw.height ${inputOptions.raw.height} to be a multiple of raw.pageHeight ${inputOptions.raw.pageHeight}`); + } + inputDescriptor.rawPageHeight = inputOptions.raw.pageHeight; + } else { + throw is.invalidParameterError('raw.pageHeight', 'positive integer', inputOptions.raw.pageHeight); + } + } } // Multi-page input (GIF, TIFF, PDF) if (is.defined(inputOptions.animated)) { @@ -316,27 +333,44 @@ function _createInputDescriptor (input, inputOptions, containerOptions) { inputDescriptor.createWidth = inputOptions.create.width; inputDescriptor.createHeight = inputOptions.create.height; inputDescriptor.createChannels = inputOptions.create.channels; + inputDescriptor.createPageHeight = 0; + if (is.defined(inputOptions.create.pageHeight)) { + if (is.integer(inputOptions.create.pageHeight) && inputOptions.create.pageHeight > 0 && inputOptions.create.pageHeight <= inputOptions.create.height) { + if (inputOptions.create.height % inputOptions.create.pageHeight !== 0) { + throw new Error(`Expected create.height ${inputOptions.create.height} to be a multiple of create.pageHeight ${inputOptions.create.pageHeight}`); + } + inputDescriptor.createPageHeight = inputOptions.create.pageHeight; + } else { + throw is.invalidParameterError('create.pageHeight', 'positive integer', inputOptions.create.pageHeight); + } + } // Noise if (is.defined(inputOptions.create.noise)) { if (!is.object(inputOptions.create.noise)) { throw new Error('Expected noise to be an object'); } - if (!is.inArray(inputOptions.create.noise.type, ['gaussian'])) { + if (inputOptions.create.noise.type !== 'gaussian') { throw new Error('Only gaussian noise is supported at the moment'); } + inputDescriptor.createNoiseType = inputOptions.create.noise.type; if (!is.inRange(inputOptions.create.channels, 1, 4)) { throw is.invalidParameterError('create.channels', 'number between 1 and 4', inputOptions.create.channels); } - inputDescriptor.createNoiseType = inputOptions.create.noise.type; - if (is.number(inputOptions.create.noise.mean) && is.inRange(inputOptions.create.noise.mean, 0, 10000)) { - inputDescriptor.createNoiseMean = inputOptions.create.noise.mean; - } else { - throw is.invalidParameterError('create.noise.mean', 'number between 0 and 10000', inputOptions.create.noise.mean); + inputDescriptor.createNoiseMean = 128; + if (is.defined(inputOptions.create.noise.mean)) { + if (is.number(inputOptions.create.noise.mean) && is.inRange(inputOptions.create.noise.mean, 0, 10000)) { + inputDescriptor.createNoiseMean = inputOptions.create.noise.mean; + } else { + throw is.invalidParameterError('create.noise.mean', 'number between 0 and 10000', inputOptions.create.noise.mean); + } } - if (is.number(inputOptions.create.noise.sigma) && is.inRange(inputOptions.create.noise.sigma, 0, 10000)) { - inputDescriptor.createNoiseSigma = inputOptions.create.noise.sigma; - } else { - throw is.invalidParameterError('create.noise.sigma', 'number between 0 and 10000', inputOptions.create.noise.sigma); + inputDescriptor.createNoiseSigma = 30; + if (is.defined(inputOptions.create.noise.sigma)) { + if (is.number(inputOptions.create.noise.sigma) && is.inRange(inputOptions.create.noise.sigma, 0, 10000)) { + inputDescriptor.createNoiseSigma = inputOptions.create.noise.sigma; + } else { + throw is.invalidParameterError('create.noise.sigma', 'number between 0 and 10000', inputOptions.create.noise.sigma); + } } } else if (is.defined(inputOptions.create.background)) { if (!is.inRange(inputOptions.create.channels, 3, 4)) { diff --git a/package.json b/package.json index 13816bce0..a3d2a9ed8 100644 --- a/package.json +++ b/package.json @@ -179,12 +179,12 @@ "icc": "^3.0.0", "jsdoc-to-markdown": "^9.1.1", "license-checker": "^25.0.1", - "mocha": "^11.6.0", - "node-addon-api": "^8.3.1", + "mocha": "^11.7.0", + "node-addon-api": "^8.4.0", "node-gyp": "^11.2.0", "nyc": "^17.1.0", "semistandard": "^17.0.0", - "tar-fs": "^3.0.9", + "tar-fs": "^3.0.10", "tsd": "^0.32.0" }, "license": "Apache-2.0", diff --git a/src/common.cc b/src/common.cc index e465dc2f7..df779e8bf 100644 --- a/src/common.cc +++ b/src/common.cc @@ -93,6 +93,7 @@ namespace sharp { descriptor->rawWidth = AttrAsUint32(input, "rawWidth"); descriptor->rawHeight = AttrAsUint32(input, "rawHeight"); descriptor->rawPremultiplied = AttrAsBool(input, "rawPremultiplied"); + descriptor->rawPageHeight = AttrAsUint32(input, "rawPageHeight"); } // Multi-page input (GIF, TIFF, PDF) if (HasAttr(input, "pages")) { @@ -129,6 +130,7 @@ namespace sharp { descriptor->createChannels = AttrAsUint32(input, "createChannels"); descriptor->createWidth = AttrAsUint32(input, "createWidth"); descriptor->createHeight = AttrAsUint32(input, "createHeight"); + descriptor->createPageHeight = AttrAsUint32(input, "createPageHeight"); if (HasAttr(input, "createNoiseType")) { descriptor->createNoiseType = AttrAsStr(input, "createNoiseType"); descriptor->createNoiseMean = AttrAsDouble(input, "createNoiseMean"); @@ -453,6 +455,10 @@ namespace sharp { } else { image.get_image()->Type = is8bit ? VIPS_INTERPRETATION_sRGB : VIPS_INTERPRETATION_RGB16; } + if (descriptor->rawPageHeight > 0) { + image.set(VIPS_META_PAGE_HEIGHT, descriptor->rawPageHeight); + image.set(VIPS_META_N_PAGES, static_cast(descriptor->rawHeight / descriptor->rawPageHeight)); + } if (descriptor->rawPremultiplied) { image = image.unpremultiply(); } @@ -502,6 +508,10 @@ namespace sharp { channels < 3 ? VIPS_INTERPRETATION_B_W : VIPS_INTERPRETATION_sRGB)) .new_from_image(background); } + if (descriptor->createPageHeight > 0) { + image.set(VIPS_META_PAGE_HEIGHT, descriptor->createPageHeight); + image.set(VIPS_META_N_PAGES, static_cast(descriptor->createHeight / descriptor->createPageHeight)); + } image = image.cast(VIPS_FORMAT_UCHAR); imageType = ImageType::RAW; } else if (descriptor->textValue.length() > 0) { diff --git a/src/common.h b/src/common.h index e199942d1..40048aa2b 100644 --- a/src/common.h +++ b/src/common.h @@ -48,11 +48,13 @@ namespace sharp { int rawWidth; int rawHeight; bool rawPremultiplied; + int rawPageHeight; int pages; int page; int createChannels; int createWidth; int createHeight; + int createPageHeight; std::vector createBackground; std::string createNoiseType; double createNoiseMean; @@ -98,11 +100,13 @@ namespace sharp { rawWidth(0), rawHeight(0), rawPremultiplied(false), + rawPageHeight(0), pages(1), page(0), createChannels(0), createWidth(0), createHeight(0), + createPageHeight(0), createBackground{ 0.0, 0.0, 0.0, 255.0 }, createNoiseMean(0.0), createNoiseSigma(0.0), diff --git a/test/types/sharp.test-d.ts b/test/types/sharp.test-d.ts index d00cbd29b..2d65eb49a 100644 --- a/test/types/sharp.test-d.ts +++ b/test/types/sharp.test-d.ts @@ -418,6 +418,7 @@ sharp({ channels: 4, height: 25000, width: 25000, + pageHeight: 1000, }, limitInputPixels: false, }) @@ -734,6 +735,13 @@ sharp({ svg: { stylesheet: 'test' }}); sharp({ svg: { highBitdepth: true }}); sharp({ svg: { highBitdepth: false }}); +// Raw input options +const raw: sharp.Raw = { width: 1, height: 1, channels: 3 }; +sharp({ raw }); +sharp({ raw: { ...raw, premultiplied: true } }); +sharp({ raw: { ...raw, premultiplied: false } }); +sharp({ raw: { ...raw, pageHeight: 1 } }); + sharp({ autoOrient: true }); sharp({ autoOrient: false }); sharp().autoOrient(); diff --git a/test/unit/noise.js b/test/unit/noise.js index bdd6bbbca..ac3a63db0 100644 --- a/test/unit/noise.js +++ b/test/unit/noise.js @@ -173,6 +173,26 @@ describe('Gaussian noise', function () { }); }); + it('animated noise', async () => { + const gif = await sharp({ + create: { + width: 16, + height: 64, + pageHeight: 16, + channels: 3, + noise: { type: 'gaussian' } + } + }) + .gif() + .toBuffer(); + + const { width, height, pages, delay } = await sharp(gif).metadata(); + assert.strictEqual(width, 16); + assert.strictEqual(height, 16); + assert.strictEqual(pages, 4); + assert.strictEqual(delay.length, 4); + }); + it('no create object properties specified', function () { assert.throws(function () { sharp({ @@ -259,4 +279,29 @@ describe('Gaussian noise', function () { }); }); }); + + it('Invalid pageHeight', () => { + const create = { + width: 8, + height: 8, + channels: 4, + noise: { type: 'gaussian' } + }; + assert.throws( + () => sharp({ create: { ...create, pageHeight: 'zoinks' } }), + /Expected positive integer for create\.pageHeight but received zoinks of type string/ + ); + assert.throws( + () => sharp({ create: { ...create, pageHeight: -1 } }), + /Expected positive integer for create\.pageHeight but received -1 of type number/ + ); + assert.throws( + () => sharp({ create: { ...create, pageHeight: 9 } }), + /Expected positive integer for create\.pageHeight but received 9 of type number/ + ); + assert.throws( + () => sharp({ create: { ...create, pageHeight: 3 } }), + /Expected create\.height 8 to be a multiple of create\.pageHeight 3/ + ); + }); }); diff --git a/test/unit/raw.js b/test/unit/raw.js index 7ad240121..9a01d0f03 100644 --- a/test/unit/raw.js +++ b/test/unit/raw.js @@ -55,6 +55,35 @@ describe('Raw pixel data', function () { }); }); + it('Invalid premultiplied', () => { + assert.throws( + () => sharp({ raw: { width: 1, height: 1, channels: 4, premultiplied: 'zoinks' } }), + /Expected boolean for raw\.premultiplied but received zoinks of type string/ + ); + }); + + it('Invalid pageHeight', () => { + const width = 8; + const height = 8; + const channels = 4; + assert.throws( + () => sharp({ raw: { width, height, channels, pageHeight: 'zoinks' } }), + /Expected positive integer for raw\.pageHeight but received zoinks of type string/ + ); + assert.throws( + () => sharp({ raw: { width, height, channels, pageHeight: -1 } }), + /Expected positive integer for raw\.pageHeight but received -1 of type number/ + ); + assert.throws( + () => sharp({ raw: { width, height, channels, pageHeight: 9 } }), + /Expected positive integer for raw\.pageHeight but received 9 of type number/ + ); + assert.throws( + () => sharp({ raw: { width, height, channels, pageHeight: 3 } }), + /Expected raw\.height 8 to be a multiple of raw\.pageHeight 3/ + ); + }); + it('RGB', function (done) { // Convert to raw pixel data sharp(fixtures.inputJpg) @@ -285,6 +314,23 @@ describe('Raw pixel data', function () { } }); + it('Animated', async () => { + const gif = await sharp( + Buffer.alloc(8), + { raw: { width: 1, height: 2, channels: 4, pageHeight: 1 }, animated: true } + ) + .gif({ keepDuplicateFrames: true }) + .toBuffer(); + + console.log(await sharp(gif).metadata()); + + const { width, height, pages, delay } = await sharp(gif).metadata(); + assert.strictEqual(width, 1); + assert.strictEqual(height, 1); + assert.strictEqual(pages, 2); + assert.strictEqual(delay.length, 2); + }); + describe('16-bit roundtrip', () => { it('grey', async () => { const grey = 42000; From 1422798c1d47a6f9359d04a7b6e7bfb72a981e2d Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Tue, 24 Jun 2025 13:11:12 +0100 Subject: [PATCH 035/115] Upgrade to sharp-libvips v1.2.0-rc.3 --- npm/darwin-arm64/package.json | 2 +- npm/darwin-x64/package.json | 2 +- npm/linux-arm/package.json | 2 +- npm/linux-arm64/package.json | 2 +- npm/linux-ppc64/package.json | 2 +- npm/linux-s390x/package.json | 2 +- npm/linux-x64/package.json | 2 +- npm/linuxmusl-arm64/package.json | 2 +- npm/linuxmusl-x64/package.json | 2 +- package.json | 28 ++++++++++++++-------------- test/unit/libvips.js | 2 +- 11 files changed, 24 insertions(+), 24 deletions(-) diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index 58f4617b6..e2c0dabf6 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.0-rc.2" + "@img/sharp-libvips-darwin-arm64": "1.2.0-rc.3" }, "files": [ "lib" diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index 4c7af9191..57039e485 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.0-rc.2" + "@img/sharp-libvips-darwin-x64": "1.2.0-rc.3" }, "files": [ "lib" diff --git a/npm/linux-arm/package.json b/npm/linux-arm/package.json index 4fe4d7dca..47ecd0e1a 100644 --- a/npm/linux-arm/package.json +++ b/npm/linux-arm/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.0-rc.2" + "@img/sharp-libvips-linux-arm": "1.2.0-rc.3" }, "files": [ "lib" diff --git a/npm/linux-arm64/package.json b/npm/linux-arm64/package.json index 8ffc90d87..953ed2129 100644 --- a/npm/linux-arm64/package.json +++ b/npm/linux-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.0-rc.2" + "@img/sharp-libvips-linux-arm64": "1.2.0-rc.3" }, "files": [ "lib" diff --git a/npm/linux-ppc64/package.json b/npm/linux-ppc64/package.json index 0e2e66538..7a4b8b6e2 100644 --- a/npm/linux-ppc64/package.json +++ b/npm/linux-ppc64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.2.0-rc.2" + "@img/sharp-libvips-linux-ppc64": "1.2.0-rc.3" }, "files": [ "lib" diff --git a/npm/linux-s390x/package.json b/npm/linux-s390x/package.json index 6ff791d92..c74a46406 100644 --- a/npm/linux-s390x/package.json +++ b/npm/linux-s390x/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.2.0-rc.2" + "@img/sharp-libvips-linux-s390x": "1.2.0-rc.3" }, "files": [ "lib" diff --git a/npm/linux-x64/package.json b/npm/linux-x64/package.json index 120855e8e..510a777a2 100644 --- a/npm/linux-x64/package.json +++ b/npm/linux-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.0-rc.2" + "@img/sharp-libvips-linux-x64": "1.2.0-rc.3" }, "files": [ "lib" diff --git a/npm/linuxmusl-arm64/package.json b/npm/linuxmusl-arm64/package.json index 05ef9bfd4..831eddfa6 100644 --- a/npm/linuxmusl-arm64/package.json +++ b/npm/linuxmusl-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.0-rc.2" + "@img/sharp-libvips-linuxmusl-arm64": "1.2.0-rc.3" }, "files": [ "lib" diff --git a/npm/linuxmusl-x64/package.json b/npm/linuxmusl-x64/package.json index 9425ed3fc..d75b4ab42 100644 --- a/npm/linuxmusl-x64/package.json +++ b/npm/linuxmusl-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.0-rc.2" + "@img/sharp-libvips-linuxmusl-x64": "1.2.0-rc.3" }, "files": [ "lib" diff --git a/package.json b/package.json index a3d2a9ed8..2be1d8c30 100644 --- a/package.json +++ b/package.json @@ -143,15 +143,15 @@ "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.3-rc.0", "@img/sharp-darwin-x64": "0.34.3-rc.0", - "@img/sharp-libvips-darwin-arm64": "1.2.0-rc.2", - "@img/sharp-libvips-darwin-x64": "1.2.0-rc.2", - "@img/sharp-libvips-linux-arm": "1.2.0-rc.2", - "@img/sharp-libvips-linux-arm64": "1.2.0-rc.2", - "@img/sharp-libvips-linux-ppc64": "1.2.0-rc.2", - "@img/sharp-libvips-linux-s390x": "1.2.0-rc.2", - "@img/sharp-libvips-linux-x64": "1.2.0-rc.2", - "@img/sharp-libvips-linuxmusl-arm64": "1.2.0-rc.2", - "@img/sharp-libvips-linuxmusl-x64": "1.2.0-rc.2", + "@img/sharp-libvips-darwin-arm64": "1.2.0-rc.3", + "@img/sharp-libvips-darwin-x64": "1.2.0-rc.3", + "@img/sharp-libvips-linux-arm": "1.2.0-rc.3", + "@img/sharp-libvips-linux-arm64": "1.2.0-rc.3", + "@img/sharp-libvips-linux-ppc64": "1.2.0-rc.3", + "@img/sharp-libvips-linux-s390x": "1.2.0-rc.3", + "@img/sharp-libvips-linux-x64": "1.2.0-rc.3", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.0-rc.3", + "@img/sharp-libvips-linuxmusl-x64": "1.2.0-rc.3", "@img/sharp-linux-arm": "0.34.3-rc.0", "@img/sharp-linux-arm64": "0.34.3-rc.0", "@img/sharp-linux-ppc64": "0.34.3-rc.0", @@ -166,11 +166,11 @@ }, "devDependencies": { "@emnapi/runtime": "^1.4.3", - "@img/sharp-libvips-dev": "1.2.0-rc.2", - "@img/sharp-libvips-dev-wasm32": "1.2.0-rc.2", - "@img/sharp-libvips-win32-arm64": "1.2.0-rc.2", - "@img/sharp-libvips-win32-ia32": "1.2.0-rc.2", - "@img/sharp-libvips-win32-x64": "1.2.0-rc.2", + "@img/sharp-libvips-dev": "1.2.0-rc.3", + "@img/sharp-libvips-dev-wasm32": "1.2.0-rc.3", + "@img/sharp-libvips-win32-arm64": "1.2.0-rc.3", + "@img/sharp-libvips-win32-ia32": "1.2.0-rc.3", + "@img/sharp-libvips-win32-x64": "1.2.0-rc.3", "@types/node": "*", "cc": "^3.0.1", "emnapi": "^1.4.3", diff --git a/test/unit/libvips.js b/test/unit/libvips.js index 434be9e15..002ef0fd7 100644 --- a/test/unit/libvips.js +++ b/test/unit/libvips.js @@ -179,7 +179,7 @@ describe('libvips binaries', function () { process.env.npm_config_arch = 's390x'; process.env.npm_config_libc = ''; const locatorHash = libvips.yarnLocator(); - assert.strictEqual(locatorHash, 'e23686d7dd'); + assert.strictEqual(locatorHash, '20827701d8'); delete process.env.npm_config_platform; delete process.env.npm_config_arch; delete process.env.npm_config_libc; From 96dfd400b2387fb91fa5af8ef4888ef514429374 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Thu, 26 Jun 2025 11:16:54 +0100 Subject: [PATCH 036/115] Tests: update benchmark environment --- test/bench/Dockerfile | 4 ++-- test/bench/perf.js | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/test/bench/Dockerfile b/test/bench/Dockerfile index 63ad36fd5..fc23deab0 100644 --- a/test/bench/Dockerfile +++ b/test/bench/Dockerfile @@ -1,11 +1,11 @@ -FROM ubuntu:24.10 +FROM ubuntu:25.04 ARG BRANCH=main # Install basic dependencies RUN apt-get -y update && apt-get install -y build-essential curl git ca-certificates gnupg # Install latest Node.js LTS -RUN curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh +RUN curl -fsSL https://deb.nodesource.com/setup_24.x -o nodesource_setup.sh RUN bash nodesource_setup.sh RUN apt-get install -y nodejs diff --git a/test/bench/perf.js b/test/bench/perf.js index 54b05d6b9..eef42808f 100644 --- a/test/bench/perf.js +++ b/test/bench/perf.js @@ -552,6 +552,32 @@ async.series({ } }); } + }).add('sharp-mks2013', { + defer: true, + fn: function (deferred) { + sharp(inputJpgBuffer) + .resize(width, height, { kernel: 'mks2013' }) + .toBuffer(function (err) { + if (err) { + throw err; + } else { + deferred.resolve(); + } + }); + } + }).add('sharp-mks2021', { + defer: true, + fn: function (deferred) { + sharp(inputJpgBuffer) + .resize(width, height, { kernel: 'mks2021' }) + .toBuffer(function (err) { + if (err) { + throw err; + } else { + deferred.resolve(); + } + }); + } }).on('cycle', function (event) { console.log('kernels ' + String(event.target)); }).on('complete', function () { From 32cf6be1b8a93c0a5100fc4764c2f02b618e34c5 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Thu, 26 Jun 2025 14:49:36 +0100 Subject: [PATCH 037/115] Docs: update benchmark results ahead of v0.34.3 --- docs/src/content/docs/performance.md | 86 ++++++++++++++-------------- 1 file changed, 44 insertions(+), 42 deletions(-) diff --git a/docs/src/content/docs/performance.md b/docs/src/content/docs/performance.md index cc75a44c3..0c0344aaa 100644 --- a/docs/src/content/docs/performance.md +++ b/docs/src/content/docs/performance.md @@ -43,24 +43,24 @@ The I/O limits of the relevant (de)compression library will generally determine ### Contenders -* [jimp](https://www.npmjs.com/package/jimp) v1.6.0 - Image processing in pure JavaScript. -* [imagemagick](https://www.npmjs.com/package/imagemagick) v0.1.3 - Supports filesystem only and "*has been unmaintained for a long time*". -* [gm](https://www.npmjs.com/package/gm) v1.25.1 - Fully featured wrapper around GraphicsMagick's `gm` command line utility, but "*has been sunset*". -* sharp v0.34.0 / libvips v8.16.1 - Caching within libvips disabled to ensure a fair comparison. +- [jimp](https://www.npmjs.com/package/jimp) v1.6.0 - Image processing in pure JavaScript. +- [imagemagick](https://www.npmjs.com/package/imagemagick) v0.1.3 - Supports filesystem only and "_has been unmaintained for a long time_". +- [gm](https://www.npmjs.com/package/gm) v1.25.1 - Fully featured wrapper around GraphicsMagick's `gm` command line utility, but "_has been sunset_". +- sharp v0.34.3 / libvips v8.17.0 - Caching within libvips disabled to ensure a fair comparison. ### Environment #### AMD64 -* AWS EC2 us-west-2 [c7a.xlarge](https://aws.amazon.com/ec2/instance-types/c7a/) (4x AMD EPYC 9R14) -* Ubuntu 24.10 [fad5ba7223f8](https://hub.docker.com/layers/library/ubuntu/24.10/images/sha256-fad5ba7223f8d87179dfa23211d31845d47e07a474ac31ad5258afb606523c0d) -* Node.js 22.14.0 +- AWS EC2 us-west-2 [c7a.xlarge](https://aws.amazon.com/ec2/instance-types/c7a/) (4x AMD EPYC 9R14) +- Ubuntu 25.04 +- Node.js 24.3.0 #### ARM64 -* AWS EC2 us-west-2 [c8g.xlarge](https://aws.amazon.com/ec2/instance-types/c8g/) (4x ARM Graviton4) -* Ubuntu 24.10 [133f2e05cb69](https://hub.docker.com/layers/library/ubuntu/24.10/images/sha256-133f2e05cb6958c3ce7ec870fd5a864558ba780fb7062315b51a23670bff7e76) -* Node.js 22.14.0 +- AWS EC2 us-west-2 [c8g.xlarge](https://aws.amazon.com/ec2/instance-types/c8g/) (4x ARM Graviton4) +- Ubuntu 25.04 +- Node.js 24.3.0 ### Task: JPEG @@ -72,27 +72,29 @@ Note: jimp does not support Lanczos 3, bicubic resampling used instead. #### Results: JPEG (AMD64) -| Module | Input | Output | Ops/sec | Speed-up | -| :----------------- | :----- | :----- | ------: | -------: | -| jimp | buffer | buffer | 2.35 | 1.0 | -| imagemagick | file | file | 10.51 | 4.5 | -| gm | buffer | buffer | 11.67 | 5.0 | -| gm | file | file | 11.75 | 5.1 | -| sharp | stream | stream | 60.72 | 25.8 | -| sharp | file | file | 62.37 | 26.5 | -| sharp | buffer | buffer | 65.15 | 27.7 | +| Package | I/O | Ops/sec | Speed-up | +| :---------- | :----- | ------: | -------: | +| jimp | buffer | 2.40 | 1.0 | +| jimp | file | 2.60 | 1.1 | +| imagemagick | file | 9.70 | 4.0 | +| gm | buffer | 11.60 | 4.8 | +| gm | file | 11.72 | 4.9 | +| sharp | stream | 59.40 | 24.8 | +| sharp | file | 62.67 | 26.1 | +| sharp | buffer | 64.42 | 26.8 | #### Results: JPEG (ARM64) -| Module | Input | Output | Ops/sec | Speed-up | -| :----------------- | :----- | :----- | ------: | -------: | -| jimp | buffer | buffer | 2.13 | 1.0 | -| imagemagick | file | file | 12.95 | 6.1 | -| gm | buffer | buffer | 13.53 | 6.4 | -| gm | file | file | 13.52 | 6.4 | -| sharp | stream | stream | 46.58 | 21.9 | -| sharp | file | file | 48.42 | 22.7 | -| sharp | buffer | buffer | 50.16 | 23.6 | +| Package | I/O | Ops/sec | Speed-up | +| :---------- | :----- | ------: | -------: | +| jimp | buffer | 2.24 | 1.0 | +| jimp | file | 2.47 | 1.1 | +| imagemagick | file | 10.42 | 4.7 | +| gm | buffer | 12.80 | 5.7 | +| gm | file | 12.88 | 5.7 | +| sharp | stream | 45.58 | 20.3 | +| sharp | file | 47.99 | 21.4 | +| sharp | buffer | 49.20 | 22.0 | ### Task: PNG @@ -106,23 +108,23 @@ Note: jimp does not support premultiply/unpremultiply. #### Results: PNG (AMD64) -| Module | Input | Output | Ops/sec | Speed-up | -| :----------------- | :----- | :----- | ------: | -------: | -| gm | file | file | 8.66 | 1.0 | -| imagemagick | file | file | 8.79 | 1.0 | -| jimp | buffer | buffer | 11.26 | 1.3 | -| sharp | file | file | 27.93 | 3.2 | -| sharp | buffer | buffer | 28.69 | 3.3 | +| Package | I/O | Ops/sec | Speed-up | +| :---------- | :----- | ------: | -------: | +| imagemagick | file | 6.06 | 1.0 | +| gm | file | 8.44 | 1.4 | +| jimp | buffer | 10.98 | 1.8 | +| sharp | file | 28.26 | 4.7 | +| sharp | buffer | 28.70 | 4.7 | #### Results: PNG (ARM64) -| Module | Input | Output | Ops/sec | Speed-up | -| :----------------- | :----- | :----- | ------: | -------: | -| gm | file | file | 9.65 | 1.0 | -| imagemagick | file | file | 9.72 | 1.0 | -| jimp | buffer | buffer | 10.68 | 1.1 | -| sharp | file | file | 23.90 | 2.5 | -| sharp | buffer | buffer | 24.48 | 2.5 | +| Package | I/O | Ops/sec | Speed-up | +| :---------- | :----- | ------: | -------: | +| imagemagick | file | 7.09 | 1.0 | +| gm | file | 8.93 | 1.3 | +| jimp | buffer | 10.28 | 1.5 | +| sharp | file | 23.81 | 3.4 | +| sharp | buffer | 24.19 | 3.4 | ## Running the benchmark test From df5454e7dc582256fb0c29a7d080054d0efedc99 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Mon, 30 Jun 2025 12:14:06 +0100 Subject: [PATCH 038/115] Add support for RAW digicam input, requires custom libvips+libraw --- docs/src/content/docs/changelog.md | 2 ++ lib/index.d.ts | 1 + package.json | 4 ++-- src/common.cc | 3 +++ src/common.h | 1 + src/utilities.cc | 2 +- 6 files changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/src/content/docs/changelog.md b/docs/src/content/docs/changelog.md index 0a248750b..de7d34ca1 100644 --- a/docs/src/content/docs/changelog.md +++ b/docs/src/content/docs/changelog.md @@ -18,6 +18,8 @@ Requires libvips v8.17.0 * Expose `keepDuplicateFrames` GIF output parameter. +* Add support for RAW digital camera image input. Requires libvips compiled with libraw support. + * Add `pageHeight` option to `create` and `raw` input for animated images. [#3236](https://github.com/lovell/sharp/issues/3236) diff --git a/lib/index.d.ts b/lib/index.d.ts index 395ec977d..ab7825c5f 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1890,6 +1890,7 @@ declare namespace sharp { interface FormatEnum { avif: AvailableFormatInfo; + dcraw: AvailableFormatInfo; dz: AvailableFormatInfo; exr: AvailableFormatInfo; fits: AvailableFormatInfo; diff --git a/package.json b/package.json index 2be1d8c30..466584c19 100644 --- a/package.json +++ b/package.json @@ -179,12 +179,12 @@ "icc": "^3.0.0", "jsdoc-to-markdown": "^9.1.1", "license-checker": "^25.0.1", - "mocha": "^11.7.0", + "mocha": "^11.7.1", "node-addon-api": "^8.4.0", "node-gyp": "^11.2.0", "nyc": "^17.1.0", "semistandard": "^17.0.0", - "tar-fs": "^3.0.10", + "tar-fs": "^3.1.0", "tsd": "^0.32.0" }, "license": "Apache-2.0", diff --git a/src/common.cc b/src/common.cc index df779e8bf..42e4a442d 100644 --- a/src/common.cc +++ b/src/common.cc @@ -284,6 +284,7 @@ namespace sharp { case ImageType::EXR: id = "exr"; break; case ImageType::JXL: id = "jxl"; break; case ImageType::RAD: id = "rad"; break; + case ImageType::DCRAW: id = "dcraw"; break; case ImageType::VIPS: id = "vips"; break; case ImageType::RAW: id = "raw"; break; case ImageType::UNKNOWN: id = "unknown"; break; @@ -332,6 +333,8 @@ namespace sharp { { "VipsForeignLoadJxlBuffer", ImageType::JXL }, { "VipsForeignLoadRadFile", ImageType::RAD }, { "VipsForeignLoadRadBuffer", ImageType::RAD }, + { "VipsForeignLoadDcRawFile", ImageType::DCRAW }, + { "VipsForeignLoadDcRawBuffer", ImageType::DCRAW }, { "VipsForeignLoadVips", ImageType::VIPS }, { "VipsForeignLoadVipsFile", ImageType::VIPS }, { "VipsForeignLoadRaw", ImageType::RAW } diff --git a/src/common.h b/src/common.h index 40048aa2b..7baf37e35 100644 --- a/src/common.h +++ b/src/common.h @@ -169,6 +169,7 @@ namespace sharp { EXR, JXL, RAD, + DCRAW, VIPS, RAW, UNKNOWN, diff --git a/src/utilities.cc b/src/utilities.cc index 93bd50cdf..1f78cdd84 100644 --- a/src/utilities.cc +++ b/src/utilities.cc @@ -119,7 +119,7 @@ Napi::Value format(const Napi::CallbackInfo& info) { Napi::Object format = Napi::Object::New(env); for (std::string const f : { "jpeg", "png", "webp", "tiff", "magick", "openslide", "dz", - "ppm", "fits", "gif", "svg", "heif", "pdf", "vips", "jp2k", "jxl", "rad" + "ppm", "fits", "gif", "svg", "heif", "pdf", "vips", "jp2k", "jxl", "rad", "dcraw" }) { // Input const VipsObjectClass *oc = vips_class_find("VipsOperation", (f + "load").c_str()); From 4e3f3792adc5dd00843668ed8ef326365163d609 Mon Sep 17 00:00:00 2001 From: Thibaut Patel Date: Wed, 11 Jun 2025 21:24:09 +0200 Subject: [PATCH 039/115] Add keepXmp and withXmp for control over output XMP metadata #4416 --- docs/public/humans.txt | 3 + docs/src/content/docs/api-output.md | 51 +++++++++ docs/src/content/docs/changelog.md | 4 + lib/constructor.js | 1 + lib/index.d.ts | 16 ++- lib/output.js | 55 ++++++++++ src/pipeline.cc | 8 +- src/pipeline.h | 1 + test/types/sharp.test-d.ts | 2 + test/unit/metadata.js | 164 ++++++++++++++++++++++++++++ 10 files changed, 303 insertions(+), 2 deletions(-) diff --git a/docs/public/humans.txt b/docs/public/humans.txt index 01af76f07..327f55321 100644 --- a/docs/public/humans.txt +++ b/docs/public/humans.txt @@ -320,3 +320,6 @@ GitHub: https://github.com/qpincon Name: Hans Chen GitHub: https://github.com/hans00 + +Name: Thibaut Patel +GitHub: https://github.com/tpatel diff --git a/docs/src/content/docs/api-output.md b/docs/src/content/docs/api-output.md index 40cc74cfd..7c966fd72 100644 --- a/docs/src/content/docs/api-output.md +++ b/docs/src/content/docs/api-output.md @@ -242,6 +242,57 @@ const outputWithP3 = await sharp(input) ``` +## keepXmp +> keepXmp() ⇒ Sharp + +Keep XMP metadata from the input image in the output image. + + +**Since**: 0.34.3 +**Example** +```js +const outputWithXmp = await sharp(inputWithXmp) + .keepXmp() + .toBuffer(); +``` + + +## withXmp +> withXmp(xmp) ⇒ Sharp + +Set XMP metadata in the output image. + +Supported by PNG, JPEG, WebP, and TIFF output. + + +**Throws**: + +- Error Invalid parameters + +**Since**: 0.34.3 + +| Param | Type | Description | +| --- | --- | --- | +| xmp | string | String containing XMP metadata to be embedded in the output image. | + +**Example** +```js +const xmpString = ` + + + + + John Doe + + + `; + +const data = await sharp(input) + .withXmp(xmpString) + .toBuffer(); +``` + + ## keepMetadata > keepMetadata() ⇒ Sharp diff --git a/docs/src/content/docs/changelog.md b/docs/src/content/docs/changelog.md index de7d34ca1..92f483205 100644 --- a/docs/src/content/docs/changelog.md +++ b/docs/src/content/docs/changelog.md @@ -31,6 +31,10 @@ Requires libvips v8.17.0 [#4412](https://github.com/lovell/sharp/pull/4412) [@kleisauke](https://github.com/kleisauke) +* Add `keepXmp` and `withXmp` for control over output XMP metadata. + [#4416](https://github.com/lovell/sharp/pull/4416) + [@tpatel](https://github.com/tpatel) + ### v0.34.2 - 20th May 2025 * Ensure animated GIF to WebP conversion retains loop (regression in 0.34.0). diff --git a/lib/constructor.js b/lib/constructor.js index e5d2a0c51..131a21a46 100644 --- a/lib/constructor.js +++ b/lib/constructor.js @@ -306,6 +306,7 @@ const Sharp = function (input, options) { withIccProfile: '', withExif: {}, withExifMerge: true, + withXmp: '', resolveWithObject: false, loop: -1, delay: [], diff --git a/lib/index.d.ts b/lib/index.d.ts index ab7825c5f..90de835e7 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -419,7 +419,7 @@ declare namespace sharp { * @returns {Sharp} */ autoOrient(): Sharp - + /** * Flip the image about the vertical Y axis. This always occurs after rotation, if any. * The use of flip implies the removal of the EXIF Orientation tag, if any. @@ -730,6 +730,20 @@ declare namespace sharp { */ withIccProfile(icc: string, options?: WithIccProfileOptions): Sharp; + /** + * Keep all XMP metadata from the input image in the output image. + * @returns A sharp instance that can be used to chain operations + */ + keepXmp(): Sharp; + + /** + * Set XMP metadata in the output image. + * @param {string} xmp - String containing XMP metadata to be embedded in the output image. + * @returns A sharp instance that can be used to chain operations + * @throws {Error} Invalid parameters + */ + withXmp(xmp: string): Sharp; + /** * Include all metadata (EXIF, XMP, IPTC) from the input image in the output image. * The default behaviour, when withMetadata is not used, is to strip all metadata and convert to the device-independent sRGB colour space. diff --git a/lib/output.js b/lib/output.js index a8b32277c..f1cdaf842 100644 --- a/lib/output.js +++ b/lib/output.js @@ -312,6 +312,59 @@ function withIccProfile (icc, options) { return this; } +/** + * Keep XMP metadata from the input image in the output image. + * + * @since 0.34.3 + * + * @example + * const outputWithXmp = await sharp(inputWithXmp) + * .keepXmp() + * .toBuffer(); + * + * @returns {Sharp} + */ +function keepXmp () { + this.options.keepMetadata |= 0b00010; + return this; +} + +/** + * Set XMP metadata in the output image. + * + * Supported by PNG, JPEG, WebP, and TIFF output. + * + * @since 0.34.3 + * + * @example + * const xmpString = ` + * + * + * + * + * John Doe + * + * + * `; + * + * const data = await sharp(input) + * .withXmp(xmpString) + * .toBuffer(); + * + * @param {string} xmp String containing XMP metadata to be embedded in the output image. + * @returns {Sharp} + * @throws {Error} Invalid parameters + */ +function withXmp (xmp) { + if (is.string(xmp) && xmp.length > 0) { + this.options.withXmp = xmp; + this.options.keepMetadata |= 0b00010; + } else { + throw is.invalidParameterError('xmp', 'non-empty string', xmp); + } + return this; +} + /** * Keep all metadata (EXIF, ICC, XMP, IPTC) from the input image in the output image. * @@ -1576,6 +1629,8 @@ module.exports = function (Sharp) { withExifMerge, keepIccProfile, withIccProfile, + keepXmp, + withXmp, keepMetadata, withMetadata, toFormat, diff --git a/src/pipeline.cc b/src/pipeline.cc index bddec2bac..3aa526f3e 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -876,7 +876,12 @@ class PipelineWorker : public Napi::AsyncWorker { image.set(s.first.data(), s.second.data()); } } - + // XMP buffer + if ((baton->keepMetadata & VIPS_FOREIGN_KEEP_XMP) && !baton->withXmp.empty()) { + image = image.copy(); + image.set(VIPS_META_XMP_NAME, nullptr, + const_cast(static_cast(baton->withXmp.c_str())), baton->withXmp.size()); + } // Number of channels used in output image baton->channels = image.bands(); baton->width = image.width(); @@ -1706,6 +1711,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) { } } baton->withExifMerge = sharp::AttrAsBool(options, "withExifMerge"); + baton->withXmp = sharp::AttrAsStr(options, "withXmp"); baton->timeoutSeconds = sharp::AttrAsUint32(options, "timeoutSeconds"); baton->loop = sharp::AttrAsUint32(options, "loop"); baton->delay = sharp::AttrAsInt32Vector(options, "delay"); diff --git a/src/pipeline.h b/src/pipeline.h index 63c9f7c21..d5d5b3fb1 100644 --- a/src/pipeline.h +++ b/src/pipeline.h @@ -202,6 +202,7 @@ struct PipelineBaton { std::string withIccProfile; std::unordered_map withExif; bool withExifMerge; + std::string withXmp; int timeoutSeconds; std::vector convKernel; int convKernelWidth; diff --git a/test/types/sharp.test-d.ts b/test/types/sharp.test-d.ts index 2d65eb49a..27e5ec462 100644 --- a/test/types/sharp.test-d.ts +++ b/test/types/sharp.test-d.ts @@ -692,6 +692,8 @@ sharp(input) k2: 'v2' } }) + .keepXmp() + .withXmp('test') .keepIccProfile() .withIccProfile('filename') .withIccProfile('filename', { attach: false }); diff --git a/test/unit/metadata.js b/test/unit/metadata.js index b5bb5e59d..ccf7e86e0 100644 --- a/test/unit/metadata.js +++ b/test/unit/metadata.js @@ -1100,6 +1100,170 @@ describe('Image metadata', function () { assert.strictEqual(exif2.Image.Software, 'sharp'); }); + describe('XMP metadata tests', function () { + it('withMetadata preserves existing XMP metadata from input', async () => { + const data = await sharp(fixtures.inputJpgWithIptcAndXmp) + .resize(320, 240) + .withMetadata() + .toBuffer(); + + const metadata = await sharp(data).metadata(); + assert.strictEqual('object', typeof metadata.xmp); + assert.strictEqual(true, metadata.xmp instanceof Buffer); + assert.strictEqual(true, metadata.xmp.length > 0); + // Check that XMP starts with the expected XML declaration + assert.strictEqual(metadata.xmp.indexOf(Buffer.from(' { + const data = await sharp(fixtures.inputJpgWithIptcAndXmp) + .resize(320, 240) + .keepXmp() + .toBuffer(); + + const metadata = await sharp(data).metadata(); + assert.strictEqual('object', typeof metadata.xmp); + assert.strictEqual(true, metadata.xmp instanceof Buffer); + assert.strictEqual(true, metadata.xmp.length > 0); + // Check that XMP starts with the expected XML declaration + assert.strictEqual(metadata.xmp.indexOf(Buffer.from(' { + const customXmp = 'Test CreatorTest Title'; + + const data = await sharp(fixtures.inputJpgWithIptcAndXmp) + .resize(320, 240) + .withXmp(customXmp) + .toBuffer(); + + const metadata = await sharp(data).metadata(); + assert.strictEqual('object', typeof metadata.xmp); + assert.strictEqual(true, metadata.xmp instanceof Buffer); + + // Check that the XMP contains our custom content + const xmpString = metadata.xmp.toString(); + assert.strictEqual(true, xmpString.includes('Test Creator')); + assert.strictEqual(true, xmpString.includes('Test Title')); + }); + + it('withXmp with custom XMP buffer on image without existing XMP', async () => { + const customXmp = 'Added via Sharp'; + + const data = await sharp(fixtures.inputJpg) + .resize(320, 240) + .withXmp(customXmp) + .toBuffer(); + + const metadata = await sharp(data).metadata(); + assert.strictEqual('object', typeof metadata.xmp); + assert.strictEqual(true, metadata.xmp instanceof Buffer); + + // Check that the XMP contains our custom content + const xmpString = metadata.xmp.toString(); + assert.strictEqual(true, xmpString.includes('Added via Sharp')); + }); + + it('withXmp with valid XMP metadata for different image formats', async () => { + const customXmp = 'testmetadata'; + + // Test with JPEG output + const jpegData = await sharp(fixtures.inputJpg) + .resize(100, 100) + .jpeg() + .withXmp(customXmp) + .toBuffer(); + + const jpegMetadata = await sharp(jpegData).metadata(); + assert.strictEqual('object', typeof jpegMetadata.xmp); + assert.strictEqual(true, jpegMetadata.xmp instanceof Buffer); + assert.strictEqual(true, jpegMetadata.xmp.toString().includes('test')); + + // Test with PNG output (PNG should also support XMP metadata) + const pngData = await sharp(fixtures.inputJpg) + .resize(100, 100) + .png() + .withXmp(customXmp) + .toBuffer(); + + const pngMetadata = await sharp(pngData).metadata(); + // PNG format should preserve XMP metadata when using withXmp + assert.strictEqual('object', typeof pngMetadata.xmp); + assert.strictEqual(true, pngMetadata.xmp instanceof Buffer); + assert.strictEqual(true, pngMetadata.xmp.toString().includes('test')); + + // Test with WebP output (WebP should also support XMP metadata) + const webpData = await sharp(fixtures.inputJpg) + .resize(100, 100) + .webp() + .withXmp(customXmp) + .toBuffer(); + + const webpMetadata = await sharp(webpData).metadata(); + // WebP format should preserve XMP metadata when using withXmp + assert.strictEqual('object', typeof webpMetadata.xmp); + assert.strictEqual(true, webpMetadata.xmp instanceof Buffer); + assert.strictEqual(true, webpMetadata.xmp.toString().includes('test')); + }); + + it('XMP metadata persists through multiple operations', async () => { + const customXmp = 'persistent-test'; + + const data = await sharp(fixtures.inputJpg) + .resize(320, 240) + .withXmp(customXmp) + .rotate(90) + .blur(1) + .sharpen() + .toBuffer(); + + const metadata = await sharp(data).metadata(); + assert.strictEqual('object', typeof metadata.xmp); + assert.strictEqual(true, metadata.xmp instanceof Buffer); + assert.strictEqual(true, metadata.xmp.toString().includes('persistent-test')); + }); + + it('withXmp XMP works with WebP format specifically', async () => { + const webpXmp = 'WebP Creatorimage/webp'; + + const data = await sharp(fixtures.inputJpg) + .resize(120, 80) + .webp({ quality: 80 }) + .withXmp(webpXmp) + .toBuffer(); + + const metadata = await sharp(data).metadata(); + assert.strictEqual('webp', metadata.format); + assert.strictEqual('object', typeof metadata.xmp); + assert.strictEqual(true, metadata.xmp instanceof Buffer); + + const xmpString = metadata.xmp.toString(); + assert.strictEqual(true, xmpString.includes('WebP Creator')); + assert.strictEqual(true, xmpString.includes('image/webp')); + }); + + it('withXmp XMP validation - non-string input', function () { + assert.throws( + () => sharp().withXmp(123), + /Expected non-empty string for xmp but received 123 of type number/ + ); + }); + + it('withXmp XMP validation - null input', function () { + assert.throws( + () => sharp().withXmp(null), + /Expected non-empty string for xmp but received null of type object/ + ); + }); + + it('withXmp XMP validation - empty string', function () { + assert.throws( + () => sharp().withXmp(''), + /Expected non-empty string for xmp/ + ); + }); + }); + describe('Invalid parameters', function () { it('String orientation', function () { assert.throws(function () { From 8ee8d273ee5f6f238bbb06f18e0365787257bde6 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Fri, 4 Jul 2025 15:55:41 +0100 Subject: [PATCH 040/115] Provide XMP as a string, as well as a Buffer, where possible --- docs/src/content/docs/changelog.md | 2 ++ lib/index.d.ts | 2 ++ lib/input.js | 1 + src/metadata.cc | 4 ++++ test/unit/metadata.js | 3 +++ 5 files changed, 12 insertions(+) diff --git a/docs/src/content/docs/changelog.md b/docs/src/content/docs/changelog.md index 92f483205..b233c9613 100644 --- a/docs/src/content/docs/changelog.md +++ b/docs/src/content/docs/changelog.md @@ -20,6 +20,8 @@ Requires libvips v8.17.0 * Add support for RAW digital camera image input. Requires libvips compiled with libraw support. +* Provide XMP metadata as a string, as well as a Buffer, where possible. + * Add `pageHeight` option to `create` and `raw` input for animated images. [#3236](https://github.com/lovell/sharp/issues/3236) diff --git a/lib/index.d.ts b/lib/index.d.ts index 90de835e7..198e443e5 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1254,6 +1254,8 @@ declare namespace sharp { iptc?: Buffer | undefined; /** Buffer containing raw XMP data, if present */ xmp?: Buffer | undefined; + /** String containing XMP data, if valid UTF-8 */ + xmpAsString?: string | undefined; /** Buffer containing raw TIFFTAG_PHOTOSHOP data, if present */ tifftagPhotoshop?: Buffer | undefined; /** The encoder used to compress an HEIF file, `av1` (AVIF) or `hevc` (HEIC) */ diff --git a/lib/input.js b/lib/input.js index ceb6d8549..aca0b16c9 100644 --- a/lib/input.js +++ b/lib/input.js @@ -605,6 +605,7 @@ function _isStreamInput () { * - `icc`: Buffer containing raw [ICC](https://www.npmjs.com/package/icc) profile data, if present * - `iptc`: Buffer containing raw IPTC data, if present * - `xmp`: Buffer containing raw XMP data, if present + * - `xmpAsString`: String containing XMP data, if valid UTF-8. * - `tifftagPhotoshop`: Buffer containing raw TIFFTAG_PHOTOSHOP data, if present * - `formatMagick`: String containing format for images loaded via *magick * - `comments`: Array of keyword/text pairs representing PNG text blocks, if present. diff --git a/src/metadata.cc b/src/metadata.cc index 9991d1040..703199106 100644 --- a/src/metadata.cc +++ b/src/metadata.cc @@ -262,6 +262,10 @@ class MetadataWorker : public Napi::AsyncWorker { } if (baton->xmpLength > 0) { info.Set("xmp", Napi::Buffer::NewOrCopy(env, baton->xmp, baton->xmpLength, sharp::FreeCallback)); + if (g_utf8_validate(static_cast(baton->xmp), baton->xmpLength, nullptr)) { + info.Set("xmpAsString", + Napi::String::New(env, static_cast(baton->xmp), baton->xmpLength)); + } } if (baton->tifftagPhotoshopLength > 0) { info.Set("tifftagPhotoshop", diff --git a/test/unit/metadata.js b/test/unit/metadata.js index ccf7e86e0..14f48afa5 100644 --- a/test/unit/metadata.js +++ b/test/unit/metadata.js @@ -82,6 +82,7 @@ describe('Image metadata', function () { assert.strictEqual(true, metadata.xmp instanceof Buffer); assert.strictEqual(12466, metadata.xmp.byteLength); assert.strictEqual(metadata.xmp.indexOf(Buffer.from('')); done(); }); }); @@ -106,6 +107,8 @@ describe('Image metadata', function () { assert.strictEqual(3248, metadata.autoOrient.height); assert.strictEqual('undefined', typeof metadata.exif); assert.strictEqual('undefined', typeof metadata.icc); + assert.strictEqual('undefined', typeof metadata.xmp); + assert.strictEqual('undefined', typeof metadata.xmpAsString); assert.strictEqual('inch', metadata.resolutionUnit); done(); }); From 2cd2f8430a2e64f9c8604a7aea0c0ace88fb03da Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Tue, 8 Jul 2025 08:36:44 +0100 Subject: [PATCH 041/115] Upgrade to libvips v8.17.1 --- docs/src/content/docs/changelog.md | 4 ++-- npm/darwin-arm64/package.json | 2 +- npm/darwin-x64/package.json | 2 +- npm/linux-arm/package.json | 2 +- npm/linux-arm64/package.json | 2 +- npm/linux-ppc64/package.json | 2 +- npm/linux-s390x/package.json | 2 +- npm/linux-x64/package.json | 2 +- npm/linuxmusl-arm64/package.json | 2 +- npm/linuxmusl-x64/package.json | 2 +- package.json | 30 +++++++++++++++--------------- src/common.h | 4 ++-- test/unit/libvips.js | 2 +- 13 files changed, 29 insertions(+), 29 deletions(-) diff --git a/docs/src/content/docs/changelog.md b/docs/src/content/docs/changelog.md index b233c9613..335ca659f 100644 --- a/docs/src/content/docs/changelog.md +++ b/docs/src/content/docs/changelog.md @@ -4,11 +4,11 @@ title: Changelog ## v0.34 - *hat* -Requires libvips v8.17.0 +Requires libvips v8.17.1 ### v0.34.3 - TBD -* Upgrade to libvips v8.17.0 for upstream bug fixes. +* Upgrade to libvips v8.17.1 for upstream bug fixes. * Add "Magic Kernel Sharp" (no relation) to resizing kernels. diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index e2c0dabf6..98882daf7 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.0-rc.3" + "@img/sharp-libvips-darwin-arm64": "1.2.0-rc.4" }, "files": [ "lib" diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index 57039e485..65aed430f 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.0-rc.3" + "@img/sharp-libvips-darwin-x64": "1.2.0-rc.4" }, "files": [ "lib" diff --git a/npm/linux-arm/package.json b/npm/linux-arm/package.json index 47ecd0e1a..5df4159b2 100644 --- a/npm/linux-arm/package.json +++ b/npm/linux-arm/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.0-rc.3" + "@img/sharp-libvips-linux-arm": "1.2.0-rc.4" }, "files": [ "lib" diff --git a/npm/linux-arm64/package.json b/npm/linux-arm64/package.json index 953ed2129..3c87780d7 100644 --- a/npm/linux-arm64/package.json +++ b/npm/linux-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.0-rc.3" + "@img/sharp-libvips-linux-arm64": "1.2.0-rc.4" }, "files": [ "lib" diff --git a/npm/linux-ppc64/package.json b/npm/linux-ppc64/package.json index 7a4b8b6e2..a3f987201 100644 --- a/npm/linux-ppc64/package.json +++ b/npm/linux-ppc64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.2.0-rc.3" + "@img/sharp-libvips-linux-ppc64": "1.2.0-rc.4" }, "files": [ "lib" diff --git a/npm/linux-s390x/package.json b/npm/linux-s390x/package.json index c74a46406..30a57507c 100644 --- a/npm/linux-s390x/package.json +++ b/npm/linux-s390x/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.2.0-rc.3" + "@img/sharp-libvips-linux-s390x": "1.2.0-rc.4" }, "files": [ "lib" diff --git a/npm/linux-x64/package.json b/npm/linux-x64/package.json index 510a777a2..27870930d 100644 --- a/npm/linux-x64/package.json +++ b/npm/linux-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.0-rc.3" + "@img/sharp-libvips-linux-x64": "1.2.0-rc.4" }, "files": [ "lib" diff --git a/npm/linuxmusl-arm64/package.json b/npm/linuxmusl-arm64/package.json index 831eddfa6..992eda95b 100644 --- a/npm/linuxmusl-arm64/package.json +++ b/npm/linuxmusl-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.0-rc.3" + "@img/sharp-libvips-linuxmusl-arm64": "1.2.0-rc.4" }, "files": [ "lib" diff --git a/npm/linuxmusl-x64/package.json b/npm/linuxmusl-x64/package.json index d75b4ab42..6c9674ad1 100644 --- a/npm/linuxmusl-x64/package.json +++ b/npm/linuxmusl-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.0-rc.3" + "@img/sharp-libvips-linuxmusl-x64": "1.2.0-rc.4" }, "files": [ "lib" diff --git a/package.json b/package.json index 466584c19..076a5e363 100644 --- a/package.json +++ b/package.json @@ -143,15 +143,15 @@ "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.3-rc.0", "@img/sharp-darwin-x64": "0.34.3-rc.0", - "@img/sharp-libvips-darwin-arm64": "1.2.0-rc.3", - "@img/sharp-libvips-darwin-x64": "1.2.0-rc.3", - "@img/sharp-libvips-linux-arm": "1.2.0-rc.3", - "@img/sharp-libvips-linux-arm64": "1.2.0-rc.3", - "@img/sharp-libvips-linux-ppc64": "1.2.0-rc.3", - "@img/sharp-libvips-linux-s390x": "1.2.0-rc.3", - "@img/sharp-libvips-linux-x64": "1.2.0-rc.3", - "@img/sharp-libvips-linuxmusl-arm64": "1.2.0-rc.3", - "@img/sharp-libvips-linuxmusl-x64": "1.2.0-rc.3", + "@img/sharp-libvips-darwin-arm64": "1.2.0-rc.4", + "@img/sharp-libvips-darwin-x64": "1.2.0-rc.4", + "@img/sharp-libvips-linux-arm": "1.2.0-rc.4", + "@img/sharp-libvips-linux-arm64": "1.2.0-rc.4", + "@img/sharp-libvips-linux-ppc64": "1.2.0-rc.4", + "@img/sharp-libvips-linux-s390x": "1.2.0-rc.4", + "@img/sharp-libvips-linux-x64": "1.2.0-rc.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.0-rc.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.0-rc.4", "@img/sharp-linux-arm": "0.34.3-rc.0", "@img/sharp-linux-arm64": "0.34.3-rc.0", "@img/sharp-linux-ppc64": "0.34.3-rc.0", @@ -166,11 +166,11 @@ }, "devDependencies": { "@emnapi/runtime": "^1.4.3", - "@img/sharp-libvips-dev": "1.2.0-rc.3", - "@img/sharp-libvips-dev-wasm32": "1.2.0-rc.3", - "@img/sharp-libvips-win32-arm64": "1.2.0-rc.3", - "@img/sharp-libvips-win32-ia32": "1.2.0-rc.3", - "@img/sharp-libvips-win32-x64": "1.2.0-rc.3", + "@img/sharp-libvips-dev": "1.2.0-rc.4", + "@img/sharp-libvips-dev-wasm32": "1.2.0-rc.4", + "@img/sharp-libvips-win32-arm64": "1.2.0-rc.4", + "@img/sharp-libvips-win32-ia32": "1.2.0-rc.4", + "@img/sharp-libvips-win32-x64": "1.2.0-rc.4", "@types/node": "*", "cc": "^3.0.1", "emnapi": "^1.4.3", @@ -192,7 +192,7 @@ "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "config": { - "libvips": ">=8.17.0" + "libvips": ">=8.17.1" }, "funding": { "url": "https://opencollective.com/libvips" diff --git a/src/common.h b/src/common.h index 7baf37e35..4d871d33f 100644 --- a/src/common.h +++ b/src/common.h @@ -16,8 +16,8 @@ #if (VIPS_MAJOR_VERSION < 8) || \ (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 17) || \ - (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 17 && VIPS_MICRO_VERSION < 0) -#error "libvips version 8.17.0+ is required - please see https://sharp.pixelplumbing.com/install" + (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 17 && VIPS_MICRO_VERSION < 1) +#error "libvips version 8.17.1+ is required - please see https://sharp.pixelplumbing.com/install" #endif #if defined(__has_include) diff --git a/test/unit/libvips.js b/test/unit/libvips.js index 002ef0fd7..64494e012 100644 --- a/test/unit/libvips.js +++ b/test/unit/libvips.js @@ -179,7 +179,7 @@ describe('libvips binaries', function () { process.env.npm_config_arch = 's390x'; process.env.npm_config_libc = ''; const locatorHash = libvips.yarnLocator(); - assert.strictEqual(locatorHash, '20827701d8'); + assert.strictEqual(locatorHash, '236db00005'); delete process.env.npm_config_platform; delete process.env.npm_config_arch; delete process.env.npm_config_libc; From 92f21451c1837b4e67f8c26ffc20408cdfeed37d Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Tue, 8 Jul 2025 21:58:53 +0100 Subject: [PATCH 042/115] Upgrade to sharp-libvips v1.2.0 --- npm/darwin-arm64/package.json | 2 +- npm/darwin-x64/package.json | 2 +- npm/linux-arm/package.json | 2 +- npm/linux-arm64/package.json | 2 +- npm/linux-ppc64/package.json | 2 +- npm/linux-s390x/package.json | 2 +- npm/linux-x64/package.json | 2 +- npm/linuxmusl-arm64/package.json | 2 +- npm/linuxmusl-x64/package.json | 2 +- npm/wasm32/package.json | 2 +- package.json | 32 ++++++++++++++++---------------- test/unit/libvips.js | 2 +- 12 files changed, 27 insertions(+), 27 deletions(-) diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index 98882daf7..c1eb3bcd5 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.0-rc.4" + "@img/sharp-libvips-darwin-arm64": "1.2.0" }, "files": [ "lib" diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index 65aed430f..4f9778ae7 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.0-rc.4" + "@img/sharp-libvips-darwin-x64": "1.2.0" }, "files": [ "lib" diff --git a/npm/linux-arm/package.json b/npm/linux-arm/package.json index 5df4159b2..35cbec20e 100644 --- a/npm/linux-arm/package.json +++ b/npm/linux-arm/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.0-rc.4" + "@img/sharp-libvips-linux-arm": "1.2.0" }, "files": [ "lib" diff --git a/npm/linux-arm64/package.json b/npm/linux-arm64/package.json index 3c87780d7..3a1a474ce 100644 --- a/npm/linux-arm64/package.json +++ b/npm/linux-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.0-rc.4" + "@img/sharp-libvips-linux-arm64": "1.2.0" }, "files": [ "lib" diff --git a/npm/linux-ppc64/package.json b/npm/linux-ppc64/package.json index a3f987201..46294d696 100644 --- a/npm/linux-ppc64/package.json +++ b/npm/linux-ppc64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.2.0-rc.4" + "@img/sharp-libvips-linux-ppc64": "1.2.0" }, "files": [ "lib" diff --git a/npm/linux-s390x/package.json b/npm/linux-s390x/package.json index 30a57507c..54ed7750f 100644 --- a/npm/linux-s390x/package.json +++ b/npm/linux-s390x/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.2.0-rc.4" + "@img/sharp-libvips-linux-s390x": "1.2.0" }, "files": [ "lib" diff --git a/npm/linux-x64/package.json b/npm/linux-x64/package.json index 27870930d..1354d08a8 100644 --- a/npm/linux-x64/package.json +++ b/npm/linux-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.0-rc.4" + "@img/sharp-libvips-linux-x64": "1.2.0" }, "files": [ "lib" diff --git a/npm/linuxmusl-arm64/package.json b/npm/linuxmusl-arm64/package.json index 992eda95b..f9c71b1eb 100644 --- a/npm/linuxmusl-arm64/package.json +++ b/npm/linuxmusl-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.0-rc.4" + "@img/sharp-libvips-linuxmusl-arm64": "1.2.0" }, "files": [ "lib" diff --git a/npm/linuxmusl-x64/package.json b/npm/linuxmusl-x64/package.json index 6c9674ad1..99685f8d9 100644 --- a/npm/linuxmusl-x64/package.json +++ b/npm/linuxmusl-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.0-rc.4" + "@img/sharp-libvips-linuxmusl-x64": "1.2.0" }, "files": [ "lib" diff --git a/npm/wasm32/package.json b/npm/wasm32/package.json index 0e02c5b96..9ed9a02c3 100644 --- a/npm/wasm32/package.json +++ b/npm/wasm32/package.json @@ -31,7 +31,7 @@ "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "dependencies": { - "@emnapi/runtime": "^1.4.3" + "@emnapi/runtime": "^1.4.4" }, "cpu": [ "wasm32" diff --git a/package.json b/package.json index 076a5e363..282d21545 100644 --- a/package.json +++ b/package.json @@ -143,15 +143,15 @@ "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.3-rc.0", "@img/sharp-darwin-x64": "0.34.3-rc.0", - "@img/sharp-libvips-darwin-arm64": "1.2.0-rc.4", - "@img/sharp-libvips-darwin-x64": "1.2.0-rc.4", - "@img/sharp-libvips-linux-arm": "1.2.0-rc.4", - "@img/sharp-libvips-linux-arm64": "1.2.0-rc.4", - "@img/sharp-libvips-linux-ppc64": "1.2.0-rc.4", - "@img/sharp-libvips-linux-s390x": "1.2.0-rc.4", - "@img/sharp-libvips-linux-x64": "1.2.0-rc.4", - "@img/sharp-libvips-linuxmusl-arm64": "1.2.0-rc.4", - "@img/sharp-libvips-linuxmusl-x64": "1.2.0-rc.4", + "@img/sharp-libvips-darwin-arm64": "1.2.0", + "@img/sharp-libvips-darwin-x64": "1.2.0", + "@img/sharp-libvips-linux-arm": "1.2.0", + "@img/sharp-libvips-linux-arm64": "1.2.0", + "@img/sharp-libvips-linux-ppc64": "1.2.0", + "@img/sharp-libvips-linux-s390x": "1.2.0", + "@img/sharp-libvips-linux-x64": "1.2.0", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.0", + "@img/sharp-libvips-linuxmusl-x64": "1.2.0", "@img/sharp-linux-arm": "0.34.3-rc.0", "@img/sharp-linux-arm64": "0.34.3-rc.0", "@img/sharp-linux-ppc64": "0.34.3-rc.0", @@ -165,15 +165,15 @@ "@img/sharp-win32-x64": "0.34.3-rc.0" }, "devDependencies": { - "@emnapi/runtime": "^1.4.3", - "@img/sharp-libvips-dev": "1.2.0-rc.4", - "@img/sharp-libvips-dev-wasm32": "1.2.0-rc.4", - "@img/sharp-libvips-win32-arm64": "1.2.0-rc.4", - "@img/sharp-libvips-win32-ia32": "1.2.0-rc.4", - "@img/sharp-libvips-win32-x64": "1.2.0-rc.4", + "@emnapi/runtime": "^1.4.4", + "@img/sharp-libvips-dev": "1.2.0", + "@img/sharp-libvips-dev-wasm32": "1.2.0", + "@img/sharp-libvips-win32-arm64": "1.2.0", + "@img/sharp-libvips-win32-ia32": "1.2.0", + "@img/sharp-libvips-win32-x64": "1.2.0", "@types/node": "*", "cc": "^3.0.1", - "emnapi": "^1.4.3", + "emnapi": "^1.4.4", "exif-reader": "^2.0.2", "extract-zip": "^2.0.1", "icc": "^3.0.0", diff --git a/test/unit/libvips.js b/test/unit/libvips.js index 64494e012..770acf61c 100644 --- a/test/unit/libvips.js +++ b/test/unit/libvips.js @@ -179,7 +179,7 @@ describe('libvips binaries', function () { process.env.npm_config_arch = 's390x'; process.env.npm_config_libc = ''; const locatorHash = libvips.yarnLocator(); - assert.strictEqual(locatorHash, '236db00005'); + assert.strictEqual(locatorHash, '30afd744f9'); delete process.env.npm_config_platform; delete process.env.npm_config_arch; delete process.env.npm_config_libc; From 2dedcf35a083c9cb1ff871ea43564bc45c9904fa Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Wed, 9 Jul 2025 21:14:50 +0100 Subject: [PATCH 043/115] Prerelease v0.34.3-rc.1 --- docs/src/content/docs/api-input.md | 1 + npm/darwin-arm64/package.json | 2 +- npm/darwin-x64/package.json | 2 +- npm/linux-arm/package.json | 2 +- npm/linux-arm64/package.json | 2 +- npm/linux-ppc64/package.json | 2 +- npm/linux-s390x/package.json | 2 +- npm/linux-x64/package.json | 2 +- npm/linuxmusl-arm64/package.json | 2 +- npm/linuxmusl-x64/package.json | 2 +- npm/package.json | 2 +- npm/wasm32/package.json | 2 +- npm/win32-arm64/package.json | 2 +- npm/win32-ia32/package.json | 2 +- npm/win32-x64/package.json | 2 +- package.json | 28 ++++++++++++++-------------- 16 files changed, 29 insertions(+), 28 deletions(-) diff --git a/docs/src/content/docs/api-input.md b/docs/src/content/docs/api-input.md index 3e1f9a7da..e460723ce 100644 --- a/docs/src/content/docs/api-input.md +++ b/docs/src/content/docs/api-input.md @@ -46,6 +46,7 @@ A `Promise` is returned when `callback` is not provided. - `icc`: Buffer containing raw [ICC](https://www.npmjs.com/package/icc) profile data, if present - `iptc`: Buffer containing raw IPTC data, if present - `xmp`: Buffer containing raw XMP data, if present +- `xmpAsString`: String containing XMP data, if valid UTF-8. - `tifftagPhotoshop`: Buffer containing raw TIFFTAG_PHOTOSHOP data, if present - `formatMagick`: String containing format for images loaded via *magick - `comments`: Array of keyword/text pairs representing PNG text blocks, if present. diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index c1eb3bcd5..d3799a8b7 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-arm64", - "version": "0.34.3-rc.0", + "version": "0.34.3-rc.1", "description": "Prebuilt sharp for use with macOS 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index 4f9778ae7..560946b1a 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-x64", - "version": "0.34.3-rc.0", + "version": "0.34.3-rc.1", "description": "Prebuilt sharp for use with macOS x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm/package.json b/npm/linux-arm/package.json index 35cbec20e..98f380cb0 100644 --- a/npm/linux-arm/package.json +++ b/npm/linux-arm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm", - "version": "0.34.3-rc.0", + "version": "0.34.3-rc.1", "description": "Prebuilt sharp for use with Linux (glibc) ARM (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm64/package.json b/npm/linux-arm64/package.json index 3a1a474ce..108a4d3e6 100644 --- a/npm/linux-arm64/package.json +++ b/npm/linux-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm64", - "version": "0.34.3-rc.0", + "version": "0.34.3-rc.1", "description": "Prebuilt sharp for use with Linux (glibc) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-ppc64/package.json b/npm/linux-ppc64/package.json index 46294d696..bcecdb411 100644 --- a/npm/linux-ppc64/package.json +++ b/npm/linux-ppc64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-ppc64", - "version": "0.34.3-rc.0", + "version": "0.34.3-rc.1", "description": "Prebuilt sharp for use with Linux (glibc) ppc64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-s390x/package.json b/npm/linux-s390x/package.json index 54ed7750f..8f84c72cc 100644 --- a/npm/linux-s390x/package.json +++ b/npm/linux-s390x/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-s390x", - "version": "0.34.3-rc.0", + "version": "0.34.3-rc.1", "description": "Prebuilt sharp for use with Linux (glibc) s390x", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-x64/package.json b/npm/linux-x64/package.json index 1354d08a8..27d2d217a 100644 --- a/npm/linux-x64/package.json +++ b/npm/linux-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-x64", - "version": "0.34.3-rc.0", + "version": "0.34.3-rc.1", "description": "Prebuilt sharp for use with Linux (glibc) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-arm64/package.json b/npm/linuxmusl-arm64/package.json index f9c71b1eb..3a45ea9d1 100644 --- a/npm/linuxmusl-arm64/package.json +++ b/npm/linuxmusl-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-arm64", - "version": "0.34.3-rc.0", + "version": "0.34.3-rc.1", "description": "Prebuilt sharp for use with Linux (musl) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-x64/package.json b/npm/linuxmusl-x64/package.json index 99685f8d9..2b0fd5ae7 100644 --- a/npm/linuxmusl-x64/package.json +++ b/npm/linuxmusl-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-x64", - "version": "0.34.3-rc.0", + "version": "0.34.3-rc.1", "description": "Prebuilt sharp for use with Linux (musl) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/package.json b/npm/package.json index de00c0dd6..a6760d6ea 100644 --- a/npm/package.json +++ b/npm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp", - "version": "0.34.3-rc.0", + "version": "0.34.3-rc.1", "private": "true", "workspaces": [ "darwin-arm64", diff --git a/npm/wasm32/package.json b/npm/wasm32/package.json index 9ed9a02c3..fe0fe6945 100644 --- a/npm/wasm32/package.json +++ b/npm/wasm32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-wasm32", - "version": "0.34.3-rc.0", + "version": "0.34.3-rc.1", "description": "Prebuilt sharp for use with wasm32", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-arm64/package.json b/npm/win32-arm64/package.json index 35a5da2cb..31043c3c3 100644 --- a/npm/win32-arm64/package.json +++ b/npm/win32-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-arm64", - "version": "0.34.3-rc.0", + "version": "0.34.3-rc.1", "description": "Prebuilt sharp for use with Windows 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-ia32/package.json b/npm/win32-ia32/package.json index 52c7beb77..7f589069f 100644 --- a/npm/win32-ia32/package.json +++ b/npm/win32-ia32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-ia32", - "version": "0.34.3-rc.0", + "version": "0.34.3-rc.1", "description": "Prebuilt sharp for use with Windows x86 (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-x64/package.json b/npm/win32-x64/package.json index 5f0f67b35..f5967aa84 100644 --- a/npm/win32-x64/package.json +++ b/npm/win32-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-x64", - "version": "0.34.3-rc.0", + "version": "0.34.3-rc.1", "description": "Prebuilt sharp for use with Windows x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/package.json b/package.json index 282d21545..174671cb9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "sharp", "description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images", - "version": "0.34.3-rc.0", + "version": "0.34.3-rc.1", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", "contributors": [ @@ -141,8 +141,8 @@ "semver": "^7.7.2" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.3-rc.0", - "@img/sharp-darwin-x64": "0.34.3-rc.0", + "@img/sharp-darwin-arm64": "0.34.3-rc.1", + "@img/sharp-darwin-x64": "0.34.3-rc.1", "@img/sharp-libvips-darwin-arm64": "1.2.0", "@img/sharp-libvips-darwin-x64": "1.2.0", "@img/sharp-libvips-linux-arm": "1.2.0", @@ -152,17 +152,17 @@ "@img/sharp-libvips-linux-x64": "1.2.0", "@img/sharp-libvips-linuxmusl-arm64": "1.2.0", "@img/sharp-libvips-linuxmusl-x64": "1.2.0", - "@img/sharp-linux-arm": "0.34.3-rc.0", - "@img/sharp-linux-arm64": "0.34.3-rc.0", - "@img/sharp-linux-ppc64": "0.34.3-rc.0", - "@img/sharp-linux-s390x": "0.34.3-rc.0", - "@img/sharp-linux-x64": "0.34.3-rc.0", - "@img/sharp-linuxmusl-arm64": "0.34.3-rc.0", - "@img/sharp-linuxmusl-x64": "0.34.3-rc.0", - "@img/sharp-wasm32": "0.34.3-rc.0", - "@img/sharp-win32-arm64": "0.34.3-rc.0", - "@img/sharp-win32-ia32": "0.34.3-rc.0", - "@img/sharp-win32-x64": "0.34.3-rc.0" + "@img/sharp-linux-arm": "0.34.3-rc.1", + "@img/sharp-linux-arm64": "0.34.3-rc.1", + "@img/sharp-linux-ppc64": "0.34.3-rc.1", + "@img/sharp-linux-s390x": "0.34.3-rc.1", + "@img/sharp-linux-x64": "0.34.3-rc.1", + "@img/sharp-linuxmusl-arm64": "0.34.3-rc.1", + "@img/sharp-linuxmusl-x64": "0.34.3-rc.1", + "@img/sharp-wasm32": "0.34.3-rc.1", + "@img/sharp-win32-arm64": "0.34.3-rc.1", + "@img/sharp-win32-ia32": "0.34.3-rc.1", + "@img/sharp-win32-x64": "0.34.3-rc.1" }, "devDependencies": { "@emnapi/runtime": "^1.4.4", From 276ac2df8d83f357f2d6825a9f0fc53ceb07d6b0 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Thu, 10 Jul 2025 08:34:49 +0100 Subject: [PATCH 044/115] Release v0.34.3 --- docs/src/content/docs/changelog.md | 2 +- npm/darwin-arm64/package.json | 2 +- npm/darwin-x64/package.json | 2 +- npm/linux-arm/package.json | 2 +- npm/linux-arm64/package.json | 2 +- npm/linux-ppc64/package.json | 2 +- npm/linux-s390x/package.json | 2 +- npm/linux-x64/package.json | 2 +- npm/linuxmusl-arm64/package.json | 2 +- npm/linuxmusl-x64/package.json | 2 +- npm/package.json | 2 +- npm/wasm32/package.json | 2 +- npm/win32-arm64/package.json | 2 +- npm/win32-ia32/package.json | 2 +- npm/win32-x64/package.json | 2 +- package.json | 28 ++++++++++++++-------------- 16 files changed, 29 insertions(+), 29 deletions(-) diff --git a/docs/src/content/docs/changelog.md b/docs/src/content/docs/changelog.md index 335ca659f..8b19249bf 100644 --- a/docs/src/content/docs/changelog.md +++ b/docs/src/content/docs/changelog.md @@ -6,7 +6,7 @@ title: Changelog Requires libvips v8.17.1 -### v0.34.3 - TBD +### v0.34.3 - 10th July 2025 * Upgrade to libvips v8.17.1 for upstream bug fixes. diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index d3799a8b7..235974579 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-arm64", - "version": "0.34.3-rc.1", + "version": "0.34.3", "description": "Prebuilt sharp for use with macOS 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index 560946b1a..bb28645bd 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-x64", - "version": "0.34.3-rc.1", + "version": "0.34.3", "description": "Prebuilt sharp for use with macOS x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm/package.json b/npm/linux-arm/package.json index 98f380cb0..f8408346d 100644 --- a/npm/linux-arm/package.json +++ b/npm/linux-arm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm", - "version": "0.34.3-rc.1", + "version": "0.34.3", "description": "Prebuilt sharp for use with Linux (glibc) ARM (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm64/package.json b/npm/linux-arm64/package.json index 108a4d3e6..8cac11535 100644 --- a/npm/linux-arm64/package.json +++ b/npm/linux-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm64", - "version": "0.34.3-rc.1", + "version": "0.34.3", "description": "Prebuilt sharp for use with Linux (glibc) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-ppc64/package.json b/npm/linux-ppc64/package.json index bcecdb411..495440149 100644 --- a/npm/linux-ppc64/package.json +++ b/npm/linux-ppc64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-ppc64", - "version": "0.34.3-rc.1", + "version": "0.34.3", "description": "Prebuilt sharp for use with Linux (glibc) ppc64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-s390x/package.json b/npm/linux-s390x/package.json index 8f84c72cc..7294d7173 100644 --- a/npm/linux-s390x/package.json +++ b/npm/linux-s390x/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-s390x", - "version": "0.34.3-rc.1", + "version": "0.34.3", "description": "Prebuilt sharp for use with Linux (glibc) s390x", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-x64/package.json b/npm/linux-x64/package.json index 27d2d217a..709c3a306 100644 --- a/npm/linux-x64/package.json +++ b/npm/linux-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-x64", - "version": "0.34.3-rc.1", + "version": "0.34.3", "description": "Prebuilt sharp for use with Linux (glibc) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-arm64/package.json b/npm/linuxmusl-arm64/package.json index 3a45ea9d1..a5b0bb6bd 100644 --- a/npm/linuxmusl-arm64/package.json +++ b/npm/linuxmusl-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-arm64", - "version": "0.34.3-rc.1", + "version": "0.34.3", "description": "Prebuilt sharp for use with Linux (musl) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-x64/package.json b/npm/linuxmusl-x64/package.json index 2b0fd5ae7..1e1db57d4 100644 --- a/npm/linuxmusl-x64/package.json +++ b/npm/linuxmusl-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-x64", - "version": "0.34.3-rc.1", + "version": "0.34.3", "description": "Prebuilt sharp for use with Linux (musl) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/package.json b/npm/package.json index a6760d6ea..f7562ed41 100644 --- a/npm/package.json +++ b/npm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp", - "version": "0.34.3-rc.1", + "version": "0.34.3", "private": "true", "workspaces": [ "darwin-arm64", diff --git a/npm/wasm32/package.json b/npm/wasm32/package.json index fe0fe6945..fcf0d3b39 100644 --- a/npm/wasm32/package.json +++ b/npm/wasm32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-wasm32", - "version": "0.34.3-rc.1", + "version": "0.34.3", "description": "Prebuilt sharp for use with wasm32", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-arm64/package.json b/npm/win32-arm64/package.json index 31043c3c3..44ce09acb 100644 --- a/npm/win32-arm64/package.json +++ b/npm/win32-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-arm64", - "version": "0.34.3-rc.1", + "version": "0.34.3", "description": "Prebuilt sharp for use with Windows 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-ia32/package.json b/npm/win32-ia32/package.json index 7f589069f..3645bce40 100644 --- a/npm/win32-ia32/package.json +++ b/npm/win32-ia32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-ia32", - "version": "0.34.3-rc.1", + "version": "0.34.3", "description": "Prebuilt sharp for use with Windows x86 (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-x64/package.json b/npm/win32-x64/package.json index f5967aa84..e2e557193 100644 --- a/npm/win32-x64/package.json +++ b/npm/win32-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-x64", - "version": "0.34.3-rc.1", + "version": "0.34.3", "description": "Prebuilt sharp for use with Windows x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/package.json b/package.json index 174671cb9..9262ac094 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "sharp", "description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images", - "version": "0.34.3-rc.1", + "version": "0.34.3", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", "contributors": [ @@ -141,8 +141,8 @@ "semver": "^7.7.2" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.3-rc.1", - "@img/sharp-darwin-x64": "0.34.3-rc.1", + "@img/sharp-darwin-arm64": "0.34.3", + "@img/sharp-darwin-x64": "0.34.3", "@img/sharp-libvips-darwin-arm64": "1.2.0", "@img/sharp-libvips-darwin-x64": "1.2.0", "@img/sharp-libvips-linux-arm": "1.2.0", @@ -152,17 +152,17 @@ "@img/sharp-libvips-linux-x64": "1.2.0", "@img/sharp-libvips-linuxmusl-arm64": "1.2.0", "@img/sharp-libvips-linuxmusl-x64": "1.2.0", - "@img/sharp-linux-arm": "0.34.3-rc.1", - "@img/sharp-linux-arm64": "0.34.3-rc.1", - "@img/sharp-linux-ppc64": "0.34.3-rc.1", - "@img/sharp-linux-s390x": "0.34.3-rc.1", - "@img/sharp-linux-x64": "0.34.3-rc.1", - "@img/sharp-linuxmusl-arm64": "0.34.3-rc.1", - "@img/sharp-linuxmusl-x64": "0.34.3-rc.1", - "@img/sharp-wasm32": "0.34.3-rc.1", - "@img/sharp-win32-arm64": "0.34.3-rc.1", - "@img/sharp-win32-ia32": "0.34.3-rc.1", - "@img/sharp-win32-x64": "0.34.3-rc.1" + "@img/sharp-linux-arm": "0.34.3", + "@img/sharp-linux-arm64": "0.34.3", + "@img/sharp-linux-ppc64": "0.34.3", + "@img/sharp-linux-s390x": "0.34.3", + "@img/sharp-linux-x64": "0.34.3", + "@img/sharp-linuxmusl-arm64": "0.34.3", + "@img/sharp-linuxmusl-x64": "0.34.3", + "@img/sharp-wasm32": "0.34.3", + "@img/sharp-win32-arm64": "0.34.3", + "@img/sharp-win32-ia32": "0.34.3", + "@img/sharp-win32-x64": "0.34.3" }, "devDependencies": { "@emnapi/runtime": "^1.4.4", From 6cde18d4433c4e0b38adb4ab0fa21017627d70cf Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Thu, 10 Jul 2025 15:57:04 +0200 Subject: [PATCH 045/115] Remove redundant TIFF warning handler setup (#4422) This became redundant after commit libvips/libvips@22994d9. --- src/sharp.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sharp.cc b/src/sharp.cc index f41ad14f7..ed54c501a 100644 --- a/src/sharp.cc +++ b/src/sharp.cc @@ -18,10 +18,8 @@ Napi::Object init(Napi::Env env, Napi::Object exports) { vips_init("sharp"); }); - for (auto domain : { "VIPS", "vips2tiff" }) { - g_log_set_handler(domain, static_cast(G_LOG_LEVEL_WARNING), - static_cast(sharp::VipsWarningCallback), nullptr); - } + g_log_set_handler("VIPS", static_cast(G_LOG_LEVEL_WARNING), + static_cast(sharp::VipsWarningCallback), nullptr); // Methods available to JavaScript exports.Set("metadata", Napi::Function::New(env, metadata)); From ecfc77c18504f8be58a8dca3060e0c195ecc2332 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Tue, 15 Jul 2025 17:21:09 +0100 Subject: [PATCH 046/115] Docs: split changelog into per-release files Use these as the body for (future) GitHub releases --- .github/workflows/ci.yml | 7 + docs/astro.config.mjs | 17 +- docs/package.json | 5 +- docs/src/content.config.ts | 3 + docs/src/content/docs/changelog.md | 2178 -------------------- docs/src/content/docs/changelog/_meta.yml | 1 + docs/src/content/docs/changelog/v0.10.0.md | 22 + docs/src/content/docs/changelog/v0.10.1.md | 12 + docs/src/content/docs/changelog/v0.11.0.md | 30 + docs/src/content/docs/changelog/v0.11.1.md | 12 + docs/src/content/docs/changelog/v0.11.2.md | 10 + docs/src/content/docs/changelog/v0.11.3.md | 8 + docs/src/content/docs/changelog/v0.11.4.md | 16 + docs/src/content/docs/changelog/v0.12.0.md | 38 + docs/src/content/docs/changelog/v0.12.1.md | 15 + docs/src/content/docs/changelog/v0.12.2.md | 20 + docs/src/content/docs/changelog/v0.13.0.md | 47 + docs/src/content/docs/changelog/v0.13.1.md | 8 + docs/src/content/docs/changelog/v0.14.0.md | 39 + docs/src/content/docs/changelog/v0.14.1.md | 26 + docs/src/content/docs/changelog/v0.15.0.md | 20 + docs/src/content/docs/changelog/v0.15.1.md | 68 + docs/src/content/docs/changelog/v0.16.0.md | 42 + docs/src/content/docs/changelog/v0.16.1.md | 21 + docs/src/content/docs/changelog/v0.16.2.md | 8 + docs/src/content/docs/changelog/v0.17.0.md | 39 + docs/src/content/docs/changelog/v0.17.1.md | 15 + docs/src/content/docs/changelog/v0.17.2.md | 12 + docs/src/content/docs/changelog/v0.17.3.md | 20 + docs/src/content/docs/changelog/v0.18.0.md | 60 + docs/src/content/docs/changelog/v0.18.1.md | 8 + docs/src/content/docs/changelog/v0.18.2.md | 19 + docs/src/content/docs/changelog/v0.18.3.md | 12 + docs/src/content/docs/changelog/v0.18.4.md | 8 + docs/src/content/docs/changelog/v0.19.0.md | 46 + docs/src/content/docs/changelog/v0.19.1.md | 16 + docs/src/content/docs/changelog/v0.20.0.md | 7 + docs/src/content/docs/changelog/v0.20.1.md | 15 + docs/src/content/docs/changelog/v0.20.2.md | 20 + docs/src/content/docs/changelog/v0.20.3.md | 8 + docs/src/content/docs/changelog/v0.20.4.md | 12 + docs/src/content/docs/changelog/v0.20.5.md | 8 + docs/src/content/docs/changelog/v0.20.6.md | 33 + docs/src/content/docs/changelog/v0.20.7.md | 7 + docs/src/content/docs/changelog/v0.20.8.md | 12 + docs/src/content/docs/changelog/v0.21.0.md | 39 + docs/src/content/docs/changelog/v0.21.1.md | 31 + docs/src/content/docs/changelog/v0.21.2.md | 27 + docs/src/content/docs/changelog/v0.21.3.md | 9 + docs/src/content/docs/changelog/v0.22.0.md | 20 + docs/src/content/docs/changelog/v0.22.1.md | 15 + docs/src/content/docs/changelog/v0.23.0.md | 32 + docs/src/content/docs/changelog/v0.23.1.md | 24 + docs/src/content/docs/changelog/v0.23.2.md | 12 + docs/src/content/docs/changelog/v0.23.3.md | 18 + docs/src/content/docs/changelog/v0.23.4.md | 12 + docs/src/content/docs/changelog/v0.24.0.md | 28 + docs/src/content/docs/changelog/v0.24.1.md | 10 + docs/src/content/docs/changelog/v0.25.0.md | 18 + docs/src/content/docs/changelog/v0.25.1.md | 7 + docs/src/content/docs/changelog/v0.25.2.md | 19 + docs/src/content/docs/changelog/v0.25.3.md | 14 + docs/src/content/docs/changelog/v0.25.4.md | 25 + docs/src/content/docs/changelog/v0.26.0.md | 33 + docs/src/content/docs/changelog/v0.26.1.md | 22 + docs/src/content/docs/changelog/v0.26.2.md | 15 + docs/src/content/docs/changelog/v0.26.3.md | 12 + docs/src/content/docs/changelog/v0.27.0.md | 15 + docs/src/content/docs/changelog/v0.27.1.md | 19 + docs/src/content/docs/changelog/v0.27.2.md | 20 + docs/src/content/docs/changelog/v0.28.0.md | 32 + docs/src/content/docs/changelog/v0.28.1.md | 15 + docs/src/content/docs/changelog/v0.28.2.md | 26 + docs/src/content/docs/changelog/v0.28.3.md | 13 + docs/src/content/docs/changelog/v0.29.0.md | 35 + docs/src/content/docs/changelog/v0.29.1.md | 30 + docs/src/content/docs/changelog/v0.29.2.md | 22 + docs/src/content/docs/changelog/v0.29.3.md | 11 + docs/src/content/docs/changelog/v0.30.0.md | 48 + docs/src/content/docs/changelog/v0.30.1.md | 19 + docs/src/content/docs/changelog/v0.30.2.md | 17 + docs/src/content/docs/changelog/v0.30.3.md | 13 + docs/src/content/docs/changelog/v0.30.4.md | 20 + docs/src/content/docs/changelog/v0.30.5.md | 19 + docs/src/content/docs/changelog/v0.30.6.md | 10 + docs/src/content/docs/changelog/v0.30.7.md | 15 + docs/src/content/docs/changelog/v0.31.0.md | 63 + docs/src/content/docs/changelog/v0.31.1.md | 22 + docs/src/content/docs/changelog/v0.31.2.md | 12 + docs/src/content/docs/changelog/v0.31.3.md | 34 + docs/src/content/docs/changelog/v0.32.0.md | 61 + docs/src/content/docs/changelog/v0.32.1.md | 30 + docs/src/content/docs/changelog/v0.32.2.md | 25 + docs/src/content/docs/changelog/v0.32.3.md | 10 + docs/src/content/docs/changelog/v0.32.4.md | 11 + docs/src/content/docs/changelog/v0.32.5.md | 24 + docs/src/content/docs/changelog/v0.32.6.md | 19 + docs/src/content/docs/changelog/v0.33.0.md | 47 + docs/src/content/docs/changelog/v0.33.1.md | 14 + docs/src/content/docs/changelog/v0.33.2.md | 16 + docs/src/content/docs/changelog/v0.33.3.md | 21 + docs/src/content/docs/changelog/v0.33.4.md | 32 + docs/src/content/docs/changelog/v0.33.5.md | 39 + docs/src/content/docs/changelog/v0.34.0.md | 52 + docs/src/content/docs/changelog/v0.34.1.md | 8 + docs/src/content/docs/changelog/v0.34.2.md | 28 + docs/src/content/docs/changelog/v0.34.3.md | 33 + 107 files changed, 2309 insertions(+), 2183 deletions(-) delete mode 100644 docs/src/content/docs/changelog.md create mode 100644 docs/src/content/docs/changelog/_meta.yml create mode 100644 docs/src/content/docs/changelog/v0.10.0.md create mode 100644 docs/src/content/docs/changelog/v0.10.1.md create mode 100644 docs/src/content/docs/changelog/v0.11.0.md create mode 100644 docs/src/content/docs/changelog/v0.11.1.md create mode 100644 docs/src/content/docs/changelog/v0.11.2.md create mode 100644 docs/src/content/docs/changelog/v0.11.3.md create mode 100644 docs/src/content/docs/changelog/v0.11.4.md create mode 100644 docs/src/content/docs/changelog/v0.12.0.md create mode 100644 docs/src/content/docs/changelog/v0.12.1.md create mode 100644 docs/src/content/docs/changelog/v0.12.2.md create mode 100644 docs/src/content/docs/changelog/v0.13.0.md create mode 100644 docs/src/content/docs/changelog/v0.13.1.md create mode 100644 docs/src/content/docs/changelog/v0.14.0.md create mode 100644 docs/src/content/docs/changelog/v0.14.1.md create mode 100644 docs/src/content/docs/changelog/v0.15.0.md create mode 100644 docs/src/content/docs/changelog/v0.15.1.md create mode 100644 docs/src/content/docs/changelog/v0.16.0.md create mode 100644 docs/src/content/docs/changelog/v0.16.1.md create mode 100644 docs/src/content/docs/changelog/v0.16.2.md create mode 100644 docs/src/content/docs/changelog/v0.17.0.md create mode 100644 docs/src/content/docs/changelog/v0.17.1.md create mode 100644 docs/src/content/docs/changelog/v0.17.2.md create mode 100644 docs/src/content/docs/changelog/v0.17.3.md create mode 100644 docs/src/content/docs/changelog/v0.18.0.md create mode 100644 docs/src/content/docs/changelog/v0.18.1.md create mode 100644 docs/src/content/docs/changelog/v0.18.2.md create mode 100644 docs/src/content/docs/changelog/v0.18.3.md create mode 100644 docs/src/content/docs/changelog/v0.18.4.md create mode 100644 docs/src/content/docs/changelog/v0.19.0.md create mode 100644 docs/src/content/docs/changelog/v0.19.1.md create mode 100644 docs/src/content/docs/changelog/v0.20.0.md create mode 100644 docs/src/content/docs/changelog/v0.20.1.md create mode 100644 docs/src/content/docs/changelog/v0.20.2.md create mode 100644 docs/src/content/docs/changelog/v0.20.3.md create mode 100644 docs/src/content/docs/changelog/v0.20.4.md create mode 100644 docs/src/content/docs/changelog/v0.20.5.md create mode 100644 docs/src/content/docs/changelog/v0.20.6.md create mode 100644 docs/src/content/docs/changelog/v0.20.7.md create mode 100644 docs/src/content/docs/changelog/v0.20.8.md create mode 100644 docs/src/content/docs/changelog/v0.21.0.md create mode 100644 docs/src/content/docs/changelog/v0.21.1.md create mode 100644 docs/src/content/docs/changelog/v0.21.2.md create mode 100644 docs/src/content/docs/changelog/v0.21.3.md create mode 100644 docs/src/content/docs/changelog/v0.22.0.md create mode 100644 docs/src/content/docs/changelog/v0.22.1.md create mode 100644 docs/src/content/docs/changelog/v0.23.0.md create mode 100644 docs/src/content/docs/changelog/v0.23.1.md create mode 100644 docs/src/content/docs/changelog/v0.23.2.md create mode 100644 docs/src/content/docs/changelog/v0.23.3.md create mode 100644 docs/src/content/docs/changelog/v0.23.4.md create mode 100644 docs/src/content/docs/changelog/v0.24.0.md create mode 100644 docs/src/content/docs/changelog/v0.24.1.md create mode 100644 docs/src/content/docs/changelog/v0.25.0.md create mode 100644 docs/src/content/docs/changelog/v0.25.1.md create mode 100644 docs/src/content/docs/changelog/v0.25.2.md create mode 100644 docs/src/content/docs/changelog/v0.25.3.md create mode 100644 docs/src/content/docs/changelog/v0.25.4.md create mode 100644 docs/src/content/docs/changelog/v0.26.0.md create mode 100644 docs/src/content/docs/changelog/v0.26.1.md create mode 100644 docs/src/content/docs/changelog/v0.26.2.md create mode 100644 docs/src/content/docs/changelog/v0.26.3.md create mode 100644 docs/src/content/docs/changelog/v0.27.0.md create mode 100644 docs/src/content/docs/changelog/v0.27.1.md create mode 100644 docs/src/content/docs/changelog/v0.27.2.md create mode 100644 docs/src/content/docs/changelog/v0.28.0.md create mode 100644 docs/src/content/docs/changelog/v0.28.1.md create mode 100644 docs/src/content/docs/changelog/v0.28.2.md create mode 100644 docs/src/content/docs/changelog/v0.28.3.md create mode 100644 docs/src/content/docs/changelog/v0.29.0.md create mode 100644 docs/src/content/docs/changelog/v0.29.1.md create mode 100644 docs/src/content/docs/changelog/v0.29.2.md create mode 100644 docs/src/content/docs/changelog/v0.29.3.md create mode 100644 docs/src/content/docs/changelog/v0.30.0.md create mode 100644 docs/src/content/docs/changelog/v0.30.1.md create mode 100644 docs/src/content/docs/changelog/v0.30.2.md create mode 100644 docs/src/content/docs/changelog/v0.30.3.md create mode 100644 docs/src/content/docs/changelog/v0.30.4.md create mode 100644 docs/src/content/docs/changelog/v0.30.5.md create mode 100644 docs/src/content/docs/changelog/v0.30.6.md create mode 100644 docs/src/content/docs/changelog/v0.30.7.md create mode 100644 docs/src/content/docs/changelog/v0.31.0.md create mode 100644 docs/src/content/docs/changelog/v0.31.1.md create mode 100644 docs/src/content/docs/changelog/v0.31.2.md create mode 100644 docs/src/content/docs/changelog/v0.31.3.md create mode 100644 docs/src/content/docs/changelog/v0.32.0.md create mode 100644 docs/src/content/docs/changelog/v0.32.1.md create mode 100644 docs/src/content/docs/changelog/v0.32.2.md create mode 100644 docs/src/content/docs/changelog/v0.32.3.md create mode 100644 docs/src/content/docs/changelog/v0.32.4.md create mode 100644 docs/src/content/docs/changelog/v0.32.5.md create mode 100644 docs/src/content/docs/changelog/v0.32.6.md create mode 100644 docs/src/content/docs/changelog/v0.33.0.md create mode 100644 docs/src/content/docs/changelog/v0.33.1.md create mode 100644 docs/src/content/docs/changelog/v0.33.2.md create mode 100644 docs/src/content/docs/changelog/v0.33.3.md create mode 100644 docs/src/content/docs/changelog/v0.33.4.md create mode 100644 docs/src/content/docs/changelog/v0.33.5.md create mode 100644 docs/src/content/docs/changelog/v0.34.0.md create mode 100644 docs/src/content/docs/changelog/v0.34.1.md create mode 100644 docs/src/content/docs/changelog/v0.34.2.md create mode 100644 docs/src/content/docs/changelog/v0.34.3.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ec95b072c..da3af0b31 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -314,6 +314,12 @@ jobs: path: npm - name: Create npm workspace tarball run: tar -vcaf npm-workspace.tar.xz --directory npm --exclude=from-local-build.js . + - name: Parse semver for tag + if: startsWith(github.ref, 'refs/tags/v') + uses: madhead/semver-utils@v4 + id: semver + with: + version: ${{ github.ref_name }} - name: Create GitHub release for tag if: startsWith(github.ref, 'refs/tags/v') uses: ncipollo/release-action@v1 @@ -322,3 +328,4 @@ jobs: artifactContentType: application/x-xz prerelease: ${{ contains(github.ref, '-rc') }} makeLatest: ${{ !contains(github.ref, '-rc') }} + bodyFile: "docs/src/content/docs/changelog/v${{ steps.semver.outputs.major }}.${{ steps.semver.outputs.minor }}.${{ steps.semver.outputs.patch }}.md" diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index 87ffdab2b..49b1c00e8 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -1,6 +1,9 @@ // @ts-check import { defineConfig } from 'astro/config'; import starlight from '@astrojs/starlight'; +import starlightAutoSidebar from 'starlight-auto-sidebar'; + +import { version } from '../package.json'; export default defineConfig({ site: 'https://sharp.pixelplumbing.com', @@ -68,12 +71,20 @@ export default defineConfig({ ] }, { label: 'Performance', slug: 'performance' }, - { label: 'Changelog', slug: 'changelog' } + { + label: 'Changelog', + collapsed: true, + autogenerate: { directory: 'changelog' } + } ], social: [ { icon: 'openCollective', label: 'Open Collective', href: 'https://opencollective.com/libvips' }, { icon: 'github', label: 'GitHub', href: 'https://github.com/lovell/sharp' } - ] + ], + plugins: [starlightAutoSidebar()] }) - ] + ], + redirects: { + '/changelog': `/changelog/v${version}` + } }); diff --git a/docs/package.json b/docs/package.json index cfb0f6520..c433dea07 100644 --- a/docs/package.json +++ b/docs/package.json @@ -11,7 +11,8 @@ "astro": "astro" }, "dependencies": { - "@astrojs/starlight": "^0.34.3", - "astro": "^5.7.13" + "@astrojs/starlight": "^0.34.6", + "astro": "^5.11.1", + "starlight-auto-sidebar": "^0.1.2" } } diff --git a/docs/src/content.config.ts b/docs/src/content.config.ts index d9ee8c9d1..06cf12929 100644 --- a/docs/src/content.config.ts +++ b/docs/src/content.config.ts @@ -1,7 +1,10 @@ import { defineCollection } from 'astro:content'; import { docsLoader } from '@astrojs/starlight/loaders'; import { docsSchema } from '@astrojs/starlight/schema'; +import { autoSidebarLoader } from 'starlight-auto-sidebar/loader' +import { autoSidebarSchema } from 'starlight-auto-sidebar/schema' export const collections = { docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }), + autoSidebar: defineCollection({ loader: autoSidebarLoader(), schema: autoSidebarSchema() }) }; diff --git a/docs/src/content/docs/changelog.md b/docs/src/content/docs/changelog.md deleted file mode 100644 index 8b19249bf..000000000 --- a/docs/src/content/docs/changelog.md +++ /dev/null @@ -1,2178 +0,0 @@ ---- -title: Changelog ---- - -## v0.34 - *hat* - -Requires libvips v8.17.1 - -### v0.34.3 - 10th July 2025 - -* Upgrade to libvips v8.17.1 for upstream bug fixes. - -* Add "Magic Kernel Sharp" (no relation) to resizing kernels. - -* Deprecate top-level, format-specific constructor parameters, e.g. `subifd` becomes `tiff.subifd`. - -* Expose `stylesheet` and `highBitdepth` SVG input parameters. - -* Expose `keepDuplicateFrames` GIF output parameter. - -* Add support for RAW digital camera image input. Requires libvips compiled with libraw support. - -* Provide XMP metadata as a string, as well as a Buffer, where possible. - -* Add `pageHeight` option to `create` and `raw` input for animated images. - [#3236](https://github.com/lovell/sharp/issues/3236) - -* Expose JPEG 2000 `oneshot` decoder option. - [#4262](https://github.com/lovell/sharp/pull/4262) - [@mbklein](https://github.com/mbklein) - -* Support composite operation with non-sRGB pipeline colourspace. - [#4412](https://github.com/lovell/sharp/pull/4412) - [@kleisauke](https://github.com/kleisauke) - -* Add `keepXmp` and `withXmp` for control over output XMP metadata. - [#4416](https://github.com/lovell/sharp/pull/4416) - [@tpatel](https://github.com/tpatel) - -### v0.34.2 - 20th May 2025 - -* Ensure animated GIF to WebP conversion retains loop (regression in 0.34.0). - [#3394](https://github.com/lovell/sharp/issues/3394) - -* Ensure `pdfBackground` constructor property is used. - [#4207](https://github.com/lovell/sharp/pull/4207) - [#4398](https://github.com/lovell/sharp/issues/4398) - -* Add experimental support for prebuilt Windows ARM64 binaries. - [#4375](https://github.com/lovell/sharp/pull/4375) - [@hans00](https://github.com/hans00) - -* Ensure resizing with a `fit` of `contain` supports multiple alpha channels. - [#4382](https://github.com/lovell/sharp/issues/4382) - -* TypeScript: Ensure `metadata` response more closely matches reality. - [#4383](https://github.com/lovell/sharp/issues/4383) - -* TypeScript: Ensure `smartDeblock` property is included in WebP definition. - [#4387](https://github.com/lovell/sharp/pull/4387) - [@Stephen-X](https://github.com/Stephen-X) - -* Ensure support for wide-character filenames on Windows (regression in 0.34.0). - [#4391](https://github.com/lovell/sharp/issues/4391) - -### v0.34.1 - 7th April 2025 - -* TypeScript: Ensure new `autoOrient` property is optional. - [#4362](https://github.com/lovell/sharp/pull/4362) - [@styfle](https://github.com/styfle) - -### v0.34.0 - 4th April 2025 - -* Breaking: Support array of input images to be joined or animated. - [#1580](https://github.com/lovell/sharp/issues/1580) - -* Breaking: Ensure `removeAlpha` removes all alpha channels. - [#2266](https://github.com/lovell/sharp/issues/2266) - -* Breaking: Non-animated GIF output defaults to no-loop instead of loop-forever. - [#3394](https://github.com/lovell/sharp/issues/3394) - -* Breaking: Support `info.size` on wide-character systems via upgrade to C++17. - [#3943](https://github.com/lovell/sharp/issues/3943) - -* Breaking: Ensure `background` metadata can be parsed by `color` package. - [#4090](https://github.com/lovell/sharp/issues/4090) - -* Add `isPalette` and `bitsPerSample` to metadata, deprecate `paletteBitDepth`. - -* Expose WebP `smartDeblock` output option. - -* Prevent use of linux-x64 binaries with v1 microarchitecture. - -* Add `autoOrient` operation and constructor option. - [#4151](https://github.com/lovell/sharp/pull/4151) - [@happycollision](https://github.com/happycollision) - -* TypeScript: Ensure channel counts use the correct range. - [#4197](https://github.com/lovell/sharp/pull/4197) - [@DavidVaness](https://github.com/DavidVaness) - -* Improve support for ppc64le architecture. - [#4203](https://github.com/lovell/sharp/pull/4203) - [@sumitd2](https://github.com/sumitd2) - -* Add `pdfBackground` constructor property. - [#4207](https://github.com/lovell/sharp/pull/4207) - [@calebmer](https://github.com/calebmer) - -* Expose erode and dilate operations. - [#4243](https://github.com/lovell/sharp/pull/4243) - [@qpincon](https://github.com/qpincon) - -* Add support for RGBE images. Requires libvips compiled with radiance support. - [#4316](https://github.com/lovell/sharp/pull/4316) - [@florentzabera](https://github.com/florentzabera) - -* Allow wide-gamut HEIF output at higher bitdepths. - [#4344](https://github.com/lovell/sharp/issues/4344) - -## v0.33 - *gauge* - -Requires libvips v8.15.3 - -### v0.33.5 - 16th August 2024 - -* Upgrade to libvips v8.15.3 for upstream bug fixes. - -* Add `pageHeight` and `pages` to response of multi-page output. - [#3411](https://github.com/lovell/sharp/issues/3411) - -* Ensure option to force use of a globally-installed libvips works correctly. - [#4111](https://github.com/lovell/sharp/pull/4111) - [@project0](https://github.com/project0) - -* Minimise use of `engines` property to improve yarn v1 support. - [#4130](https://github.com/lovell/sharp/issues/4130) - -* Ensure `sharp.format.heif` includes only AVIF when using prebuilt binaries. - [#4132](https://github.com/lovell/sharp/issues/4132) - -* Add support to recomb operation for 4x4 matrices. - [#4147](https://github.com/lovell/sharp/pull/4147) - [@ton11797](https://github.com/ton11797) - -* Expose PNG text chunks as `comments` metadata. - [#4157](https://github.com/lovell/sharp/pull/4157) - [@nkeynes](https://github.com/nkeynes) - -* Expose optional `precision` and `minAmplitude` parameters of `blur` operation. - [#4168](https://github.com/lovell/sharp/pull/4168) - [#4172](https://github.com/lovell/sharp/pull/4172) - [@marcosc90](https://github.com/marcosc90) - -* Ensure `keepIccProfile` avoids colour transformation where possible. - [#4186](https://github.com/lovell/sharp/issues/4186) - -* TypeScript: `chromaSubsampling` metadata is optional. - [#4191](https://github.com/lovell/sharp/pull/4191) - [@DavidVaness](https://github.com/DavidVaness) - -### v0.33.4 - 16th May 2024 - -* Remove experimental status from `pipelineColourspace`. - -* Reduce default concurrency when musl thread over-subscription detected. - -* TypeScript: add missing definitions for `OverlayOptions`. - [#4048](https://github.com/lovell/sharp/pull/4048) - [@ike-gg](https://github.com/ike-gg) - -* Install: add advanced option to force use of a globally-installed libvips. - [#4060](https://github.com/lovell/sharp/issues/4060) - -* Expose `bilinear` resizing kernel (and interpolator). - [#4061](https://github.com/lovell/sharp/issues/4061) - -* Ensure `extend` operation stays sequential for multi-page TIFF (regression in 0.32.0). - [#4069](https://github.com/lovell/sharp/issues/4069) - -* Tighten validation of constructor `text` integer properties. - [#4071](https://github.com/lovell/sharp/issues/4071) - -* Simplify internal StaySequential logic. - [#4074](https://github.com/lovell/sharp/pull/4074) - [@kleisauke](https://github.com/kleisauke) - -* Ensure negate operation occurs after profile conversion. - [#4096](https://github.com/lovell/sharp/pull/4096) - [@adriaanmeuris](https://github.com/adriaanmeuris) - -### v0.33.3 - 23rd March 2024 - -* Upgrade to libvips v8.15.2 for upstream bug fixes. - -* Ensure `keepIccProfile` retains P3 and CMYK input profiles. - [#3906](https://github.com/lovell/sharp/issues/3906) - [#4008](https://github.com/lovell/sharp/issues/4008) - -* Ensure `text.wrap` property can accept `word-char` as value. - [#4028](https://github.com/lovell/sharp/pull/4028) - [@yolopunk](https://github.com/yolopunk) - -* Ensure `clone` takes a deep copy of existing options. - [#4029](https://github.com/lovell/sharp/issues/4029) - -* Add `bitdepth` option to `heif` output (prebuilt binaries support 8-bit only). - [#4036](https://github.com/lovell/sharp/pull/4036) - [@mertalev](https://github.com/mertalev) - -### v0.33.2 - 12th January 2024 - -* Upgrade to libvips v8.15.1 for upstream bug fixes. - -* TypeScript: add definition for `keepMetadata`. - [#3914](https://github.com/lovell/sharp/pull/3914) - [@abhi0498](https://github.com/abhi0498) - -* Ensure `extend` operation stays sequential when copying (regression in 0.32.0). - [#3928](https://github.com/lovell/sharp/issues/3928) - -* Improve error handling for unsupported multi-page rotation. - [#3940](https://github.com/lovell/sharp/issues/3940) - -### v0.33.1 - 17th December 2023 - -* Add support for Yarn Plug'n'Play filesystem layout. - [#3888](https://github.com/lovell/sharp/issues/3888) - -* Emit warning when attempting to use invalid ICC profiles. - [#3895](https://github.com/lovell/sharp/issues/3895) - -* Ensure `VIPS_NOVECTOR` environment variable is respected. - [#3897](https://github.com/lovell/sharp/pull/3897) - [@icetee](https://github.com/icetee) - -### v0.33.0 - 29th November 2023 - -* Drop support for Node.js 14 and 16, now requires Node.js ^18.17.0 or >= 20.3.0 - -* Prebuilt binaries distributed via npm registry and installed via package manager. - -* Building from source requires dependency on `node-addon-api`. - -* Remove `sharp.vendor`. - -* Partially deprecate `withMetadata()`, use `withExif()` and `withIccProfile()`. - -* Add experimental support for WebAssembly-based runtimes. - [@RReverser](https://github.com/RReverser) - -* Options for `trim` operation must be an Object, add new `lineArt` option. - [#2363](https://github.com/lovell/sharp/issues/2363) - -* Improve luminance of `tint` operation with weighting function. - [#3338](https://github.com/lovell/sharp/issues/3338) - [@jcupitt](https://github.com/jcupitt) - -* Ensure all `Error` objects contain a `stack` property. - [#3653](https://github.com/lovell/sharp/issues/3653) - -* Make `compression` option of `heif` mandatory to help reduce HEIF vs HEIC confusion. - [#3740](https://github.com/lovell/sharp/issues/3740) - -* Ensure correct interpretation of 16-bit raw input. - [#3808](https://github.com/lovell/sharp/issues/3808) - -* Add support for `miniswhite` when using TIFF output. - [#3812](https://github.com/lovell/sharp/pull/3812) - [@dnsbty](https://github.com/dnsbty) - -* TypeScript: add missing definition for `withMetadata` boolean. - [#3823](https://github.com/lovell/sharp/pull/3823) - [@uhthomas](https://github.com/uhthomas) - -* Add more fine-grained control over output metadata. - [#3824](https://github.com/lovell/sharp/issues/3824) - -* Ensure multi-page extract remains sequential. - [#3837](https://github.com/lovell/sharp/issues/3837) - -## v0.32 - *flow* - -Requires libvips v8.14.5 - -### v0.32.6 - 18th September 2023 - -* Upgrade to libvips v8.14.5 for upstream bug fixes. - -* Ensure composite tile images are fully decoded (regression in 0.32.0). - [#3767](https://github.com/lovell/sharp/issues/3767) - -* Ensure `withMetadata` can add ICC profiles to RGB16 output. - [#3773](https://github.com/lovell/sharp/issues/3773) - -* Ensure `withMetadata` does not reduce 16-bit images to 8-bit (regression in 0.32.5). - [#3773](https://github.com/lovell/sharp/issues/3773) - -* TypeScript: Add definitions for block and unblock. - [#3799](https://github.com/lovell/sharp/pull/3799) - [@ldrick](https://github.com/ldrick) - -### v0.32.5 - 15th August 2023 - -* Upgrade to libvips v8.14.4 for upstream bug fixes. - -* TypeScript: Add missing `WebpPresetEnum` to definitions. - [#3748](https://github.com/lovell/sharp/pull/3748) - [@pilotso11](https://github.com/pilotso11) - -* Ensure compilation using musl v1.2.4. - [#3755](https://github.com/lovell/sharp/pull/3755) - [@kleisauke](https://github.com/kleisauke) - -* Ensure resize with a `fit` of `inside` respects 90/270 degree rotation. - [#3756](https://github.com/lovell/sharp/issues/3756) - -* TypeScript: Ensure `minSize` property of `WebpOptions` is boolean. - [#3758](https://github.com/lovell/sharp/pull/3758) - [@sho-xizz](https://github.com/sho-xizz) - -* Ensure `withMetadata` adds default sRGB profile. - [#3761](https://github.com/lovell/sharp/issues/3761) - -### v0.32.4 - 21st July 2023 - -* Upgrade to libvips v8.14.3 for upstream bug fixes. - -* Expose ability to (un)block low-level libvips operations by name. - -* Prebuilt binaries: restore support for tile-based output. - [#3581](https://github.com/lovell/sharp/issues/3581) - -### v0.32.3 - 14th July 2023 - -* Expose `preset` option for WebP output. - [#3639](https://github.com/lovell/sharp/issues/3639) - -* Ensure decoding remains sequential for all operations (regression in 0.32.2). - [#3725](https://github.com/lovell/sharp/issues/3725) - -### v0.32.2 - 11th July 2023 - -* Limit HEIF output dimensions to 16384x16384, matches libvips. - -* Ensure exceptions are not thrown when terminating. - [#3569](https://github.com/lovell/sharp/issues/3569) - -* Ensure the same access method is used for all inputs (regression in 0.32.0). - [#3669](https://github.com/lovell/sharp/issues/3669) - -* Improve detection of jp2 filename extensions. - [#3674](https://github.com/lovell/sharp/pull/3674) - [@bianjunjie1981](https://github.com/bianjunjie1981) - -* Guard use of smartcrop premultiplied option to prevent warning (regression in 0.32.1). - [#3710](https://github.com/lovell/sharp/issues/3710) - -* Prevent over-compute in affine-based rotate before resize. - [#3722](https://github.com/lovell/sharp/issues/3722) - -* Allow sequential read for EXIF-based auto-orientation. - [#3725](https://github.com/lovell/sharp/issues/3725) - -### v0.32.1 - 27th April 2023 - -* Add experimental `unflatten` operation. - [#3461](https://github.com/lovell/sharp/pull/3461) - [@antonmarsden](https://github.com/antonmarsden) - -* Ensure use of `flip` operation forces random access read (regression in 0.32.0). - [#3600](https://github.com/lovell/sharp/issues/3600) - -* Ensure `linear` operation works with 16-bit input (regression in 0.31.3). - [#3605](https://github.com/lovell/sharp/issues/3605) - -* Install: ensure proxy URLs are logged correctly. - [#3615](https://github.com/lovell/sharp/pull/3615) - [@TomWis97](https://github.com/TomWis97) - -* Ensure profile-less CMYK to CMYK roundtrip skips colourspace conversion. - [#3620](https://github.com/lovell/sharp/issues/3620) - -* Add support for `modulate` operation when using non-sRGB pipeline colourspace. - [#3620](https://github.com/lovell/sharp/issues/3620) - -* Ensure `trim` operation works with CMYK images (regression in 0.31.0). - [#3636](https://github.com/lovell/sharp/issues/3636) - -* Install: coerce libc version to semver. - [#3641](https://github.com/lovell/sharp/issues/3641) - -### v0.32.0 - 24th March 2023 - -* Default to using sequential rather than random access read where possible. - -* Replace GIF output `optimise` / `optimize` option with `reuse`. - -* Add `progressive` option to GIF output for interlacing. - -* Add `wrap` option to text image creation. - -* Add `formatMagick` property to metadata of images loaded via *magick. - -* Prefer integer (un)premultiply for faster resizing of RGBA images. - -* Add `ignoreIcc` input option to ignore embedded ICC profile. - -* Allow use of GPS (IFD3) EXIF metadata. - [#2767](https://github.com/lovell/sharp/issues/2767) - -* TypeScript definitions are now maintained and published directly, deprecating the `@types/sharp` package. - [#3369](https://github.com/lovell/sharp/issues/3369) - -* Prebuilt binaries: ensure macOS 10.13+ support, as documented. - [#3438](https://github.com/lovell/sharp/issues/3438) - -* Prebuilt binaries: prevent use of glib slice allocator, improves QEMU support. - [#3448](https://github.com/lovell/sharp/issues/3448) - -* Add focus point coordinates to output when using attention based crop. - [#3470](https://github.com/lovell/sharp/pull/3470) - [@ejoebstl](https://github.com/ejoebstl) - -* Expose sharp version as `sharp.versions.sharp`. - [#3471](https://github.com/lovell/sharp/issues/3471) - -* Respect `fastShrinkOnLoad` resize option for WebP input. - [#3516](https://github.com/lovell/sharp/issues/3516) - -* Reduce sharpen `sigma` maximum from 10000 to 10. - [#3521](https://github.com/lovell/sharp/issues/3521) - -* Add support for `ArrayBuffer` input. - [#3548](https://github.com/lovell/sharp/pull/3548) - [@kapouer](https://github.com/kapouer) - -* Add support to `extend` operation for `extendWith` to allow copy/mirror/repeat. - [#3556](https://github.com/lovell/sharp/pull/3556) - [@janaz](https://github.com/janaz) - -* Ensure all async JS callbacks are wrapped to help avoid possible race condition. - [#3569](https://github.com/lovell/sharp/issues/3569) - -* Prebuilt binaries: support for tile-based output temporarily removed due to licensing issue. - [#3581](https://github.com/lovell/sharp/issues/3581) - -* Add support to `normalise` for `lower` and `upper` percentiles. - [#3583](https://github.com/lovell/sharp/pull/3583) - [@LachlanNewman](https://github.com/LachlanNewman) - -## v0.31 - *eagle* - -Requires libvips v8.13.3 - -### v0.31.3 - 21st December 2022 - -* Add experimental support for JPEG-XL images. Requires libvips compiled with libjxl. - [#2731](https://github.com/lovell/sharp/issues/2731) - -* Add runtime detection of V8 memory cage, ensures compatibility with Electron 21 onwards. - [#3384](https://github.com/lovell/sharp/issues/3384) - -* Expose `interFrameMaxError` and `interPaletteMaxError` GIF optimisation properties. - [#3401](https://github.com/lovell/sharp/issues/3401) - -* Allow installation on Linux with glibc patch versions e.g. Fedora 38. - [#3423](https://github.com/lovell/sharp/issues/3423) - -* Expand range of existing `sharpen` parameters to match libvips. - [#3427](https://github.com/lovell/sharp/issues/3427) - -* Prevent possible race condition awaiting metadata of Stream-based input. - [#3451](https://github.com/lovell/sharp/issues/3451) - -* Improve `extractChannel` support for 16-bit output colourspaces. - [#3453](https://github.com/lovell/sharp/issues/3453) - -* Ignore `sequentialRead` option when calculating image statistics. - [#3462](https://github.com/lovell/sharp/issues/3462) - -* Small performance improvement for operations that introduce a non-opaque background. - [#3465](https://github.com/lovell/sharp/issues/3465) - -* Ensure integral output of `linear` operation. - [#3468](https://github.com/lovell/sharp/issues/3468) - -### v0.31.2 - 4th November 2022 - -* Upgrade to libvips v8.13.3 for upstream bug fixes. - -* Ensure manual flip, rotate, resize operation ordering (regression in 0.31.1) - [#3391](https://github.com/lovell/sharp/issues/3391) - -* Ensure auto-rotation works without resize (regression in 0.31.1) - [#3422](https://github.com/lovell/sharp/issues/3422) - -### v0.31.1 - 29th September 2022 - -* Upgrade to libvips v8.13.2 for upstream bug fixes. - -* Ensure `close` event occurs after `end` event for Stream-based output. - [#3313](https://github.com/lovell/sharp/issues/3313) - -* Ensure `limitInputPixels` constructor option uses uint64. - [#3349](https://github.com/lovell/sharp/pull/3349) - [@marcosc90](https://github.com/marcosc90) - -* Ensure auto-rotation works with shrink-on-load and extract (regression in 0.31.0). - [#3352](https://github.com/lovell/sharp/issues/3352) - -* Ensure AVIF output is always 8-bit. - [#3358](https://github.com/lovell/sharp/issues/3358) - -* Ensure greyscale images can be trimmed (regression in 0.31.0). - [#3386](https://github.com/lovell/sharp/issues/3386) - -### v0.31.0 - 5th September 2022 - -* Drop support for Node.js 12, now requires Node.js >= 14.15.0. - -* GIF output now re-uses input palette if possible. Use `reoptimise` option to generate a new palette. - -* Add WebP `minSize` and `mixed` options for greater control over animation frames. - -* Remove previously-deprecated WebP `reductionEffort` and HEIF `speed` options. Use `effort` to control these. - -* The `flip` and `flop` operations will now occur before the `rotate` operation. - -* Improve `normalise` operation with use of histogram. - [#200](https://github.com/lovell/sharp/issues/200) - -* Use combined bounding box of alpha and non-alpha channels for `trim` operation. - [#2166](https://github.com/lovell/sharp/issues/2166) - -* Add Buffer and Stream support to tile-based output. - [#2238](https://github.com/lovell/sharp/issues/2238) - -* Add input `fileSuffix` and output `alias` to `format` information. - [#2642](https://github.com/lovell/sharp/issues/2642) - -* Re-introduce support for greyscale ICC profiles (temporarily removed in 0.30.2). - [#3114](https://github.com/lovell/sharp/issues/3114) - -* Add support for WebP and PackBits `compression` options with TIFF output. - [#3198](https://github.com/lovell/sharp/issues/3198) - -* Ensure OpenSlide and FITS input works with custom libvips. - [#3226](https://github.com/lovell/sharp/issues/3226) - -* Ensure `trim` operation is a no-op when it would reduce an image to nothing. - [#3223](https://github.com/lovell/sharp/issues/3223) - -* Expose `vips_text` to create an image containing rendered text. - [#3252](https://github.com/lovell/sharp/pull/3252) - [@brahima](https://github.com/brahima) - -* Ensure only properties owned by the `withMetadata` EXIF Object are parsed. - [#3292](https://github.com/lovell/sharp/issues/3292) - -* Expand `linear` operation to allow use of per-channel arrays. - [#3303](https://github.com/lovell/sharp/pull/3303) - [@antonmarsden](https://github.com/antonmarsden) - -* Ensure the order of `rotate`, `resize` and `extend` operations is respected where possible. - Emit warnings when previous calls in the same pipeline will be ignored. - [#3319](https://github.com/lovell/sharp/issues/3319) - -* Ensure PNG bitdepth can be set for non-palette output. - [#3322](https://github.com/lovell/sharp/issues/3322) - -* Add trim option to provide a specific background colour. - [#3332](https://github.com/lovell/sharp/pull/3332) - [@mart-jansink](https://github.com/mart-jansink) - -* Ensure resized image is unpremultiplied before composite. - [#3334](https://github.com/lovell/sharp/issues/3334) - -## v0.30 - *dresser* - -Requires libvips v8.12.2 - -### v0.30.7 - 22nd June 2022 - -* Ensure tiled composition always works with outside resizing. - [#3227](https://github.com/lovell/sharp/issues/3227) - -* Allow WebP encoding effort of 0. - [#3261](https://github.com/lovell/sharp/pull/3261) - [@AlexanderTheGrey](https://github.com/AlexanderTheGrey) - -* Prevent upsampling via libwebp. - [#3267](https://github.com/lovell/sharp/pull/3267) - [@blacha](https://github.com/blacha) - -### v0.30.6 - 30th May 2022 - -* Allow values for `limitInputPixels` larger than 32-bit. - [#3238](https://github.com/lovell/sharp/issues/3238) - -* Ensure brew-installed `vips` can be detected (regression in 0.30.5). - [#3239](https://github.com/lovell/sharp/issues/3239) - -### v0.30.5 - 23rd May 2022 - -* Install: pass `PKG_CONFIG_PATH` via env rather than substitution. - [@dwisiswant0](https://github.com/dwisiswant0) - -* Add support for `--libc` flag to improve cross-platform installation. - [#3160](https://github.com/lovell/sharp/pull/3160) - [@joonamo](https://github.com/joonamo) - -* Allow installation of prebuilt libvips binaries from filesystem. - [#3196](https://github.com/lovell/sharp/pull/3196) - [@ankurparihar](https://github.com/ankurparihar) - -* Fix rotate-then-extract for EXIF orientation 2. - [#3218](https://github.com/lovell/sharp/pull/3218) - [@jakob0fischl](https://github.com/jakob0fischl) - -### v0.30.4 - 18th April 2022 - -* Increase control over sensitivity to invalid images via `failOn`, deprecate `failOnError` (equivalent to `failOn: 'warning'`). - -* Ensure `create` input image has correct bit depth and colour space. - [#3139](https://github.com/lovell/sharp/issues/3139) - -* Add support for `TypedArray` input with `byteOffset` and `length`. - [#3146](https://github.com/lovell/sharp/pull/3146) - [@codepage949](https://github.com/codepage949) - -* Improve error message when attempting to render SVG input greater than 32767x32767. - [#3167](https://github.com/lovell/sharp/issues/3167) - -* Add missing file name to 'Input file is missing' error message. - [#3178](https://github.com/lovell/sharp/pull/3178) - [@Brodan](https://github.com/Brodan) - -### v0.30.3 - 14th March 2022 - -* Allow `sharpen` options to be provided more consistently as an Object. - [#2561](https://github.com/lovell/sharp/issues/2561) - -* Expose `x1`, `y2` and `y3` parameters of `sharpen` operation. - [#2935](https://github.com/lovell/sharp/issues/2935) - -* Prevent double unpremultiply with some composite blend modes (regression in 0.30.2). - [#3118](https://github.com/lovell/sharp/issues/3118) - -### v0.30.2 - 2nd March 2022 - -* Improve performance and accuracy when compositing multiple images. - [#2286](https://github.com/lovell/sharp/issues/2286) - -* Expand pkgconfig search path for wider BSD support. - [#3106](https://github.com/lovell/sharp/issues/3106) - -* Ensure Windows C++ runtime is linked statically (regression in 0.30.0). - [#3110](https://github.com/lovell/sharp/pull/3110) - [@kleisauke](https://github.com/kleisauke) - -* Temporarily ignore greyscale ICC profiles to workaround lcms bug. - [#3112](https://github.com/lovell/sharp/issues/3112) - -### v0.30.1 - 9th February 2022 - -* Allow use of `toBuffer` and `toFile` on the same instance. - [#3044](https://github.com/lovell/sharp/issues/3044) - -* Skip shrink-on-load for known libjpeg rounding errors. - [#3066](https://github.com/lovell/sharp/issues/3066) - [@kleisauke](https://github.com/kleisauke) - -* Ensure withoutReduction does not interfere with contain/crop/embed. - [#3081](https://github.com/lovell/sharp/pull/3081) - [@kleisauke](https://github.com/kleisauke) - -* Ensure affine interpolator is correctly finalised. - [#3083](https://github.com/lovell/sharp/pull/3083) - [@kleisauke](https://github.com/kleisauke) - -### v0.30.0 - 1st February 2022 - -* Add support for GIF output to prebuilt binaries. - -* Reduce minimum Linux ARM64v8 glibc requirement to 2.17. - -* Verify prebuilt binaries with a Subresource Integrity check. - -* Standardise WebP `effort` option name, deprecate `reductionEffort`. - -* Standardise HEIF `effort` option name, deprecate `speed`. - -* Add support for IIIF v3 tile-based output. - -* Expose control over CPU effort for palette-based PNG output. - [#2541](https://github.com/lovell/sharp/issues/2541) - -* Improve animated (multi-page) image resize and extract. - [#2789](https://github.com/lovell/sharp/pull/2789) - [@kleisauke](https://github.com/kleisauke) - -* Expose platform and architecture of vendored binaries as `sharp.vendor`. - [#2928](https://github.com/lovell/sharp/issues/2928) - -* Ensure 16-bit PNG output uses correct bitdepth. - [#2958](https://github.com/lovell/sharp/pull/2958) - [@gforge](https://github.com/gforge) - -* Properly emit close events for duplex streams. - [#2976](https://github.com/lovell/sharp/pull/2976) - [@driannaude](https://github.com/driannaude) - -* Expose `unlimited` option for SVG and PNG input, switches off safety features. - [#2984](https://github.com/lovell/sharp/issues/2984) - -* Add `withoutReduction` option to resize operation. - [#3006](https://github.com/lovell/sharp/pull/3006) - [@christopherbradleybanks](https://github.com/christopherbradleybanks) - -* Add `resolutionUnit` as `tiff` option and expose in metadata. - [#3023](https://github.com/lovell/sharp/pull/3023) - [@ompal-sisodiya](https://github.com/ompal-sisodiya) - -* Ensure rotate-then-extract works with EXIF mirroring. - [#3024](https://github.com/lovell/sharp/issues/3024) - -## v0.29 - *circle* - -Requires libvips v8.11.3 - -### v0.29.3 - 14th November 2021 - -* Ensure correct dimensions when containing image resized to 1px. - [#2951](https://github.com/lovell/sharp/issues/2951) - -* Impute TIFF `xres`/`yres` from `density` provided to `withMetadata`. - [#2952](https://github.com/lovell/sharp/pull/2952) - [@mbklein](https://github.com/mbklein) - -### v0.29.2 - 21st October 2021 - -* Add `timeout` function to limit processing time. - -* Ensure `sharp.versions` is populated from vendored libvips. - -* Remove animation properties from single page images. - [#2890](https://github.com/lovell/sharp/issues/2890) - -* Allow use of 'tif' to select TIFF output. - [#2893](https://github.com/lovell/sharp/pull/2893) - [@erf](https://github.com/erf) - -* Improve error message on Windows for version conflict. - [#2918](https://github.com/lovell/sharp/pull/2918) - [@dkrnl](https://github.com/dkrnl) - -* Throw error rather than exit when invalid binaries detected. - [#2931](https://github.com/lovell/sharp/issues/2931) - -### v0.29.1 - 7th September 2021 - -* Add `lightness` option to `modulate` operation. - [#2846](https://github.com/lovell/sharp/pull/2846) - -* Ensure correct PNG bitdepth is set based on number of colours. - [#2855](https://github.com/lovell/sharp/issues/2855) - -* Ensure background is always premultiplied when compositing. - [#2858](https://github.com/lovell/sharp/issues/2858) - -* Ensure images with P3 profiles retain full gamut. - [#2862](https://github.com/lovell/sharp/issues/2862) - -* Add support for libvips compiled with OpenJPEG. - [#2868](https://github.com/lovell/sharp/pull/2868) - -* Remove unsupported animation properties from AVIF output. - [#2870](https://github.com/lovell/sharp/issues/2870) - -* Resolve paths before comparing input/output filenames. - [#2878](https://github.com/lovell/sharp/pull/2878) - [@rexxars](https://github.com/rexxars) - -* Allow use of speed 9 (fastest) for HEIF encoding. - [#2879](https://github.com/lovell/sharp/pull/2879) - [@rexxars](https://github.com/rexxars) - -### v0.29.0 - 17th August 2021 - -* Drop support for Node.js 10, now requires Node.js >= 12.13.0. - -* Add `background` property to PNG and GIF image metadata. - -* Add `compression` property to HEIF image metadata. - [#2504](https://github.com/lovell/sharp/issues/2504) - -* AVIF encoding now defaults to `4:4:4` chroma subsampling. - [#2562](https://github.com/lovell/sharp/issues/2562) - -* Allow multiple platform-arch binaries in same `node_modules` installation tree. - [#2575](https://github.com/lovell/sharp/issues/2575) - -* Default to single-channel `b-w` space when `extractChannel` is used. - [#2658](https://github.com/lovell/sharp/issues/2658) - -* Allow installation directory to contain spaces (regression in v0.26.0). - [#2777](https://github.com/lovell/sharp/issues/2777) - -* Add `pipelineColourspace` operator to set the processing space. - [#2704](https://github.com/lovell/sharp/pull/2704) - [@Daiz](https://github.com/Daiz) - -* Allow bit depth to be set when using raw input and output. - [#2762](https://github.com/lovell/sharp/pull/2762) - [@mart-jansink](https://github.com/mart-jansink) - -* Allow `negate` to act only on non-alpha channels. - [#2808](https://github.com/lovell/sharp/pull/2808) - [@rexxars](https://github.com/rexxars) - -## v0.28 - *bijou* - -Requires libvips v8.10.6 - -### v0.28.3 - 24th May 2021 - -* Ensure presence of libvips, vendored or global, before invoking node-gyp. - -* Skip shrink-on-load for multi-page WebP. - [#2714](https://github.com/lovell/sharp/issues/2714) - -* Add contrast limiting adaptive histogram equalization (CLAHE) operator. - [#2726](https://github.com/lovell/sharp/pull/2726) - [@baparham](https://github.com/baparham) - -### v0.28.2 - 10th May 2021 - -* Allow `withMetadata` to set `density`. - [#967](https://github.com/lovell/sharp/issues/967) - -* Skip shrink-on-load where one dimension <4px. - [#2653](https://github.com/lovell/sharp/issues/2653) - -* Allow escaped proxy credentials. - [#2664](https://github.com/lovell/sharp/pull/2664) - [@msalettes](https://github.com/msalettes) - -* Add `premultiplied` flag for raw pixel data input. - [#2685](https://github.com/lovell/sharp/pull/2685) - [@mnutt](https://github.com/mnutt) - -* Detect empty input and throw a helpful error. - [#2687](https://github.com/lovell/sharp/pull/2687) - [@JakobJingleheimer](https://github.com/JakobJingleheimer) - -* Add install-time flag to skip version compatibility checks. - [#2692](https://github.com/lovell/sharp/pull/2692) - [@xemle](https://github.com/xemle) - -### v0.28.1 - 5th April 2021 - -* Ensure all installation errors are logged with a more obvious prefix. - -* Allow `withMetadata` to set and update EXIF metadata. - [#650](https://github.com/lovell/sharp/issues/650) - -* Add support for OME-TIFF Sub Image File Directories (subIFD). - [#2557](https://github.com/lovell/sharp/issues/2557) - -* Allow `ensureAlpha` to set the alpha transparency level. - [#2634](https://github.com/lovell/sharp/issues/2634) - -### v0.28.0 - 29th March 2021 - -* Prebuilt binaries now include mozjpeg and libimagequant (BSD 2-Clause). - -* Prebuilt binaries limit AVIF support to the most common 8-bit depth. - -* Add `mozjpeg` option to `jpeg` method, sets mozjpeg defaults. - -* Reduce the default PNG `compressionLevel` to the more commonly used 6. - -* Reduce concurrency on glibc-based Linux when using the default memory allocator to help prevent fragmentation. - -* Default missing edge properties of extend operation to zero. - [#2578](https://github.com/lovell/sharp/issues/2578) - -* Ensure composite does not clip top and left offsets. - [#2594](https://github.com/lovell/sharp/pull/2594) - [@SHG42](https://github.com/SHG42) - -* Improve error handling of network failure at install time. - [#2608](https://github.com/lovell/sharp/pull/2608) - [@abradley](https://github.com/abradley) - -* Ensure `@id` attribute can be set for IIIF tile-based output. - [#2612](https://github.com/lovell/sharp/issues/2612) - [@edsilv](https://github.com/edsilv) - -* Ensure composite replicates the correct number of tiles for centred gravities. - [#2626](https://github.com/lovell/sharp/issues/2626) - -## v0.27 - *avif* - -Requires libvips v8.10.5 - -### v0.27.2 - 22nd February 2021 - -* macOS: Prevent use of globally-installed ARM64 libvips with Rosetta x64 emulation. - [#2460](https://github.com/lovell/sharp/issues/2460) - -* Linux (musl): Prevent use of prebuilt linuxmusl-x64 binaries with musl >= 1.2.0. - [#2570](https://github.com/lovell/sharp/issues/2570) - -* Improve 16-bit grey+alpha support by using libvips' `has_alpha` detection. - [#2569](https://github.com/lovell/sharp/issues/2569) - -* Allow the use of non lower case extensions with `toFormat`. - [#2581](https://github.com/lovell/sharp/pull/2581) - [@florian-busch](https://github.com/florian-busch) - -* Allow use of `recomb` operation with single channel input. - [#2584](https://github.com/lovell/sharp/issues/2584) - -### v0.27.1 - 27th January 2021 - -* Ensure TIFF is cast when using float predictor. - [#2502](https://github.com/lovell/sharp/pull/2502) - [@randyridge](https://github.com/randyridge) - -* Add support for Uint8Array and Uint8ClampedArray input. - [#2511](https://github.com/lovell/sharp/pull/2511) - [@leon](https://github.com/leon) - -* Revert: ensure all platforms use fontconfig for font rendering. - [#2515](https://github.com/lovell/sharp/issues/2515) - -* Expose libvips gaussnoise operation to allow creation of Gaussian noise. - [#2527](https://github.com/lovell/sharp/pull/2527) - [@alza54](https://github.com/alza54) - -### v0.27.0 - 22nd December 2020 - -* Add support for AVIF to prebuilt binaries. - -* Remove experimental status from `heif` output, defaults are now AVIF-centric. - -* Allow negative top/left offsets for composite operation. - [#2391](https://github.com/lovell/sharp/pull/2391) - [@CurosMJ](https://github.com/CurosMJ) - -* Ensure all platforms use fontconfig for font rendering. - [#2399](https://github.com/lovell/sharp/issues/2399) - -## v0.26 - *zoom* - -Requires libvips v8.10.0 - -### v0.26.3 - 16th November 2020 - -* Expose libvips' affine operation. - [#2336](https://github.com/lovell/sharp/pull/2336) - [@guillevc](https://github.com/guillevc) - -* Fallback to tar.gz for prebuilt libvips when Brotli not available. - [#2412](https://github.com/lovell/sharp/pull/2412) - [@ascorbic](https://github.com/ascorbic) - -### v0.26.2 - 14th October 2020 - -* Add support for EXR input. Requires libvips compiled with OpenEXR. - [#698](https://github.com/lovell/sharp/issues/698) - -* Ensure support for yarn v2. - [#2379](https://github.com/lovell/sharp/pull/2379) - [@jalovatt](https://github.com/jalovatt) - -* Add centre/center option to tile-based output. - [#2397](https://github.com/lovell/sharp/pull/2397) - [@beig](https://github.com/beig) - -### v0.26.1 - 20th September 2020 - -* Ensure correct pageHeight when verifying multi-page image dimensions. - [#2343](https://github.com/lovell/sharp/pull/2343) - [@derom](https://github.com/derom) - -* Allow input density range up to 100000 DPI. - [#2348](https://github.com/lovell/sharp/pull/2348) - [@stefanprobst](https://github.com/stefanprobst) - -* Ensure animation-related properties can be set for Stream-based input. - [#2369](https://github.com/lovell/sharp/pull/2369) - [@AcrylicShrimp](https://github.com/AcrylicShrimp) - -* Ensure `stats` can be calculated for 1x1 input. - [#2372](https://github.com/lovell/sharp/issues/2372) - -* Ensure animated GIF output is optimised. - [#2376](https://github.com/lovell/sharp/issues/2376) - -### v0.26.0 - 25th August 2020 - -* Prebuilt libvips binaries are now statically-linked and Brotli-compressed, requiring Node.js 10.16.0+. - -* TIFF output `squash` is replaced by `bitdepth` to reduce to 1, 2 or 4 bit. - -* JPEG output `quality` >= 90 no longer automatically sets `chromaSubsampling` to `4:4:4`. - -* Add most `dominant` colour to image `stats`. - [#640](https://github.com/lovell/sharp/issues/640) - -* Add support for animated GIF (requires \*magick) and WebP output. - [#2012](https://github.com/lovell/sharp/pull/2012) - [@deftomat](https://github.com/deftomat) - -* Add support for libvips ImageMagick v7 loaders. - [#2258](https://github.com/lovell/sharp/pull/2258) - [@vouillon](https://github.com/vouillon) - -* Allow multi-page input via \*magick. - [#2259](https://github.com/lovell/sharp/pull/2259) - [@vouillon](https://github.com/vouillon) - -* Add support to `withMetadata` for custom ICC profile. - [#2271](https://github.com/lovell/sharp/pull/2271) - [@roborourke](https://github.com/roborourke) - -* Ensure prebuilt binaries for ARM default to v7 when using Electron. - [#2292](https://github.com/lovell/sharp/pull/2292) - [@diegodev3](https://github.com/diegodev3) - -## v0.25 - *yield* - -Requires libvips v8.9.1 - -### v0.25.4 - 12th June 2020 - -* Allow libvips binary location override where version is appended. - [#2217](https://github.com/lovell/sharp/pull/2217) - [@malice00](https://github.com/malice00) - -* Enable PNG palette when setting quality, colours, colors or dither. - [#2226](https://github.com/lovell/sharp/pull/2226) - [@romaleev](https://github.com/romaleev) - -* Add `level` constructor option to use a specific level of a multi-level image. - Expose `levels` metadata for multi-level images. - [#2222](https://github.com/lovell/sharp/issues/2222) - -* Add support for named `alpha` channel to `extractChannel` operation. - [#2138](https://github.com/lovell/sharp/issues/2138) - -* Add experimental `sharpness` calculation to `stats()` response. - [#2251](https://github.com/lovell/sharp/issues/2251) - -* Emit `warning` event for non-critical processing problems. - [#2032](https://github.com/lovell/sharp/issues/2032) - -### v0.25.3 - 17th May 2020 - -* Ensure libvips is initialised only once, improves worker thread safety. - [#2143](https://github.com/lovell/sharp/issues/2143) - -* Ensure npm platform flag is respected when copying DLLs. - [#2188](https://github.com/lovell/sharp/pull/2188) - [@dimadeveatii](https://github.com/dimadeveatii) - -* Allow SVG input with large inline images to be parsed. - [#2195](https://github.com/lovell/sharp/issues/2195) - -### v0.25.2 - 20th March 2020 - -* Provide prebuilt binaries for Linux ARM64v8. - -* Add IIIF layout support to tile-based output. - [#2098](https://github.com/lovell/sharp/pull/2098) - [@edsilv](https://github.com/edsilv) - -* Ensure input options are consistently and correctly detected. - [#2118](https://github.com/lovell/sharp/issues/2118) - -* Ensure N-API prebuilt binaries work on RHEL7 and its derivatives. - [#2119](https://github.com/lovell/sharp/issues/2119) - -* Ensure AsyncWorker options are persisted. - [#2130](https://github.com/lovell/sharp/issues/2130) - -### v0.25.1 - 7th March 2020 - -* Ensure prebuilt binaries are fetched based on N-API version. - [#2117](https://github.com/lovell/sharp/issues/2117) - -### v0.25.0 - 7th March 2020 - -* Remove `limitInputPixels` and `sequentialRead` previously deprecated in v0.24.0. - -* Migrate internals to N-API. - [#1282](https://github.com/lovell/sharp/issues/1282) - -* Add support for 32-bit Windows. - [#2088](https://github.com/lovell/sharp/issues/2088) - -* Ensure correct ordering of rotate-then-trim operations. - [#2087](https://github.com/lovell/sharp/issues/2087) - -* Ensure composite accepts `limitInputPixels` and `sequentialRead` input options. - [#2099](https://github.com/lovell/sharp/issues/2099) - -## v0.24 - "*wit*" - -Requires libvips v8.9.0. - -### v0.24.1 - 15th February 2020 - -* Prevent use of sequentialRead for EXIF-based rotate operation. - [#2042](https://github.com/lovell/sharp/issues/2042) - -* Ensure RGBA LZW TIFF returns correct channel count. - [#2064](https://github.com/lovell/sharp/issues/2064) - -### v0.24.0 - 16th January 2020 - -* Drop support for Node.js 8. - [#1910](https://github.com/lovell/sharp/issues/1910) - -* Drop support for undefined input where options also provided. - [#1768](https://github.com/lovell/sharp/issues/1768) - -* Move `limitInputPixels` and `sequentialRead` to input options, deprecating functions of the same name. - -* Expose `delay` and `loop` metadata for animated images. - [#1905](https://github.com/lovell/sharp/issues/1905) - -* Ensure correct colour output for 16-bit, 2-channel PNG input with ICC profile. - [#2013](https://github.com/lovell/sharp/issues/2013) - -* Prevent use of sequentialRead for rotate operations. - [#2016](https://github.com/lovell/sharp/issues/2016) - -* Correctly bind max width and height values when using withoutEnlargement. - [#2024](https://github.com/lovell/sharp/pull/2024) - [@BrychanOdlum](https://github.com/BrychanOdlum) - -* Add support for input with 16-bit RGB profile. - [#2037](https://github.com/lovell/sharp/issues/2037) - -## v0.23 - "*vision*" - -Requires libvips v8.8.1. - -### v0.23.4 - 5th December 2019 - -* Handle zero-length Buffer objects when using Node.js v13.2.0+. - -* Expose raw TIFFTAG_PHOTOSHOP metadata. - [#1600](https://github.com/lovell/sharp/issues/1600) - -* Improve thread safety by using copy-on-write when updating metadata. - [#1986](https://github.com/lovell/sharp/issues/1986) - -### v0.23.3 - 17th November 2019 - -* Ensure `trim` operation supports images contained in the alpha channel. - [#1597](https://github.com/lovell/sharp/issues/1597) - -* Ensure tile `overlap` option works as expected. - [#1921](https://github.com/lovell/sharp/pull/1921) - [@rustyguts](https://github.com/rustyguts) - -* Allow compilation on FreeBSD and variants (broken since v0.23.0) - [#1952](https://github.com/lovell/sharp/pull/1952) - [@pouya-eghbali](https://github.com/pouya-eghbali) - -* Ensure `modulate` and other colour-based operations can co-exist. - [#1958](https://github.com/lovell/sharp/issues/1958) - -### v0.23.2 - 28th October 2019 - -* Add `background` option to tile output operation. - [#1924](https://github.com/lovell/sharp/pull/1924) - [@neave](https://github.com/neave) - -* Add support for Node.js 13. - [#1932](https://github.com/lovell/sharp/pull/1932) - [@MayhemYDG](https://github.com/MayhemYDG) - -### v0.23.1 - 26th September 2019 - -* Ensure `sharp.format.vips` is present and correct (filesystem only). - [#1813](https://github.com/lovell/sharp/issues/1813) - -* Ensure invalid `width` and `height` provided as options to `resize` throw. - [#1817](https://github.com/lovell/sharp/issues/1817) - -* Allow use of 'heic' and 'heif' identifiers with `toFormat`. - [#1834](https://github.com/lovell/sharp/pull/1834) - [@jaubourg](https://github.com/jaubourg) - -* Add `premultiplied` option to `composite` operation. - [#1835](https://github.com/lovell/sharp/pull/1835) - [@Andargor](https://github.com/Andargor) - -* Allow instance reuse with differing `toBuffer` options. - [#1860](https://github.com/lovell/sharp/pull/1860) - [@RaboliotTheGrey](https://github.com/RaboliotTheGrey) - -* Ensure image is at least 3x3 pixels before attempting trim operation. - -### v0.23.0 - 29th July 2019 - -* Remove `overlayWith` previously deprecated in v0.22.0. - -* Add experimental support for HEIF images. Requires libvips compiled with libheif. - [#1105](https://github.com/lovell/sharp/issues/1105) - -* Expose libwebp `smartSubsample` and `reductionEffort` options. - [#1545](https://github.com/lovell/sharp/issues/1545) - -* Add experimental support for Worker Threads. - [#1558](https://github.com/lovell/sharp/issues/1558) - -* Use libvips' built-in CMYK and sRGB profiles when required. - [#1619](https://github.com/lovell/sharp/issues/1619) - -* Drop support for Node.js versions 6 and 11. - [#1674](https://github.com/lovell/sharp/issues/1674) - -* Expose `skipBlanks` option for tile-based output. - [#1687](https://github.com/lovell/sharp/pull/1687) - [@RaboliotTheGrey](https://github.com/RaboliotTheGrey) - -* Allow use of `failOnError` option with Stream-based input. - [#1691](https://github.com/lovell/sharp/issues/1691) - -* Fix rotate/extract ordering for non-90 angles. - [#1755](https://github.com/lovell/sharp/pull/1755) - [@iovdin](https://github.com/iovdin) - -## v0.22 - "*uptake*" - -Requires libvips v8.7.4. - -### v0.22.1 - 25th April 2019 - -* Add `modulate` operation for brightness, saturation and hue. - [#1601](https://github.com/lovell/sharp/pull/1601) - [@Goues](https://github.com/Goues) - -* Improve help messaging should `require("sharp")` fail. - [#1638](https://github.com/lovell/sharp/pull/1638) - [@sidharthachatterjee](https://github.com/sidharthachatterjee) - -* Add support for Node 12. - [#1668](https://github.com/lovell/sharp/issues/1668) - -### v0.22.0 - 18th March 2019 - -* Remove functions previously deprecated in v0.21.0: - `background`, `crop`, `embed`, `ignoreAspectRatio`, `max`, `min` and `withoutEnlargement`. - -* Add `composite` operation supporting multiple images and blend modes; deprecate `overlayWith`. - [#728](https://github.com/lovell/sharp/issues/728) - -* Add support for `pages` input option for multi-page input. - [#1566](https://github.com/lovell/sharp/issues/1566) - -* Allow Stream-based input of raw pixel data. - [#1579](https://github.com/lovell/sharp/issues/1579) - -* Add support for `page` input option to GIF and PDF. - [#1595](https://github.com/lovell/sharp/pull/1595) - [@ramiel](https://github.com/ramiel) - -## v0.21 - "*teeth*" - -Requires libvips v8.7.0. - -### v0.21.3 - 19th January 2019 - -* Input image decoding now fails fast, set `failOnError` to change this behaviour. - -* Failed filesystem-based input now separates missing file and invalid format errors. - [#1542](https://github.com/lovell/sharp/issues/1542) - -### v0.21.2 - 13th January 2019 - -* Ensure all metadata is removed from PNG output unless `withMetadata` used. - -* Ensure shortest edge is at least one pixel after resizing. - [#1003](https://github.com/lovell/sharp/issues/1003) - -* Add `ensureAlpha` operation to add an alpha channel, if missing. - [#1153](https://github.com/lovell/sharp/issues/1153) - -* Expose `pages` and `pageHeight` metadata for multi-page input images. - [#1205](https://github.com/lovell/sharp/issues/1205) - -* Expose PNG output options requiring libimagequant. - [#1484](https://github.com/lovell/sharp/issues/1484) - -* Expose underlying error message for invalid input. - [#1505](https://github.com/lovell/sharp/issues/1505) - -* Prevent mutatation of options passed to `jpeg`. - [#1516](https://github.com/lovell/sharp/issues/1516) - -* Ensure forced output format applied correctly when output chaining. - [#1528](https://github.com/lovell/sharp/issues/1528) - -### v0.21.1 - 7th December 2018 - -* Install: support `sharp_dist_base_url` npm config, like existing `SHARP_DIST_BASE_URL`. - [#1422](https://github.com/lovell/sharp/pull/1422) - [@SethWen](https://github.com/SethWen) - -* Ensure `channel` metadata is correct for raw, greyscale output. - [#1425](https://github.com/lovell/sharp/issues/1425) - -* Add support for the "mitchell" kernel for image reductions. - [#1438](https://github.com/lovell/sharp/pull/1438) - [@Daiz](https://github.com/Daiz) - -* Allow separate parameters for gamma encoding and decoding. - [#1439](https://github.com/lovell/sharp/pull/1439) - [@Daiz](https://github.com/Daiz) - -* Build prototype with `Object.assign` to allow minification. - [#1475](https://github.com/lovell/sharp/pull/1475) - [@jaubourg](https://github.com/jaubourg) - -* Expose libvips' recombination matrix operation. - [#1477](https://github.com/lovell/sharp/pull/1477) - [@fromkeith](https://github.com/fromkeith) - -* Expose libvips' pyramid/tile options for TIFF output. - [#1483](https://github.com/lovell/sharp/pull/1483) - [@mbklein](https://github.com/mbklein) - -### v0.21.0 - 4th October 2018 - -* Deprecate the following resize-related functions: - `crop`, `embed`, `ignoreAspectRatio`, `max`, `min` and `withoutEnlargement`. - Access to these is now via options passed to the `resize` function. - For example: - `embed('north')` is now `resize(width, height, { fit: 'contain', position: 'north' })`, - `crop('attention')` is now `resize(width, height, { fit: 'cover', position: 'attention' })`, - `max().withoutEnlargement()` is now `resize(width, height, { fit: 'inside', withoutEnlargement: true })`. - [#1135](https://github.com/lovell/sharp/issues/1135) - -* Deprecate the `background` function. - Per-operation `background` options added to `resize`, `extend` and `flatten` operations. - [#1392](https://github.com/lovell/sharp/issues/1392) - -* Add `size` to `metadata` response (Stream and Buffer input only). - [#695](https://github.com/lovell/sharp/issues/695) - -* Switch from custom trim operation to `vips_find_trim`. - [#914](https://github.com/lovell/sharp/issues/914) - -* Add `chromaSubsampling` and `isProgressive` properties to `metadata` response. - [#1186](https://github.com/lovell/sharp/issues/1186) - -* Drop Node 4 support. - [#1212](https://github.com/lovell/sharp/issues/1212) - -* Enable SIMD convolution by default. - [#1213](https://github.com/lovell/sharp/issues/1213) - -* Add experimental prebuilt binaries for musl-based Linux. - [#1379](https://github.com/lovell/sharp/issues/1379) - -* Add support for arbitrary rotation angle via vips_rotate. - [#1385](https://github.com/lovell/sharp/pull/1385) - [@freezy](https://github.com/freezy) - -## v0.20 - "*prebuild*" - -Requires libvips v8.6.1. - -### v0.20.8 - 5th September 2018 - -* Avoid race conditions when creating directories during installation. - [#1358](https://github.com/lovell/sharp/pull/1358) - [@ajhool](https://github.com/ajhool) - -* Accept floating point values for input density parameter. - [#1362](https://github.com/lovell/sharp/pull/1362) - [@aeirola](https://github.com/aeirola) - -### v0.20.7 - 21st August 2018 - -* Use copy+unlink if rename operation fails during installation. - [#1345](https://github.com/lovell/sharp/issues/1345) - -### v0.20.6 - 20th August 2018 - -* Add removeAlpha operation to remove alpha channel, if any. - [#1248](https://github.com/lovell/sharp/issues/1248) - -* Expose mozjpeg quant_table flag. - [#1285](https://github.com/lovell/sharp/pull/1285) - [@rexxars](https://github.com/rexxars) - -* Allow full WebP alphaQuality range of 0-100. - [#1290](https://github.com/lovell/sharp/pull/1290) - [@sylvaindumont](https://github.com/sylvaindumont) - -* Cache libvips binaries to reduce re-install time. - [#1301](https://github.com/lovell/sharp/issues/1301) - -* Ensure vendor platform mismatch throws error at install time. - [#1303](https://github.com/lovell/sharp/issues/1303) - -* Improve install time error messages for FreeBSD users. - [#1310](https://github.com/lovell/sharp/issues/1310) - -* Ensure extractChannel works with 16-bit images. - [#1330](https://github.com/lovell/sharp/issues/1330) - -* Expose depth option for tile-based output. - [#1342](https://github.com/lovell/sharp/pull/1342) - [@alundavies](https://github.com/alundavies) - -* Add experimental entropy field to stats response. - -### v0.20.5 - 27th June 2018 - -* Expose libjpeg optimize_coding flag. - [#1265](https://github.com/lovell/sharp/pull/1265) - [@tomlokhorst](https://github.com/tomlokhorst) - -### v0.20.4 - 20th June 2018 - -* Prevent possible rounding error when using shrink-on-load and 90/270 degree rotation. - [#1241](https://github.com/lovell/sharp/issues/1241) - [@anahit42](https://github.com/anahit42) - -* Ensure extractChannel sets correct single-channel colour space interpretation. - [#1257](https://github.com/lovell/sharp/issues/1257) - [@jeremychone](https://github.com/jeremychone) - -### v0.20.3 - 29th May 2018 - -* Fix tint operation by ensuring LAB interpretation and allowing negative values. - [#1235](https://github.com/lovell/sharp/issues/1235) - [@wezside](https://github.com/wezside) - -### v0.20.2 - 28th April 2018 - -* Add tint operation to set image chroma. - [#825](https://github.com/lovell/sharp/pull/825) - [@rikh42](https://github.com/rikh42) - -* Add environment variable to ignore globally-installed libvips. - [#1165](https://github.com/lovell/sharp/pull/1165) - [@oncletom](https://github.com/oncletom) - -* Add support for page selection with multi-page input (GIF/TIFF). - [#1204](https://github.com/lovell/sharp/pull/1204) - [@woolite64](https://github.com/woolite64) - -* Add support for Group4 (CCITTFAX4) compression with TIFF output. - [#1208](https://github.com/lovell/sharp/pull/1208) - [@woolite64](https://github.com/woolite64) - -### v0.20.1 - 17th March 2018 - -* Improve installation experience when a globally-installed libvips below the minimum required version is found. - [#1148](https://github.com/lovell/sharp/issues/1148) - -* Prevent smartcrop error when cumulative rounding is below target size. - [#1154](https://github.com/lovell/sharp/issues/1154) - [@ralrom](https://github.com/ralrom) - -* Expose libvips' median filter operation. - [#1161](https://github.com/lovell/sharp/pull/1161) - [@BiancoA](https://github.com/BiancoA) - -### v0.20.0 - 5th March 2018 - -* Add support for prebuilt sharp binaries on common platforms. - [#186](https://github.com/lovell/sharp/issues/186) - -## v0.19 - "*suit*" - -Requires libvips v8.6.1. - -### v0.19.1 - 24th February 2018 - -* Expose libvips' linear transform feature. - [#1024](https://github.com/lovell/sharp/pull/1024) - [@3epnm](https://github.com/3epnm) - -* Expose angle option for tile-based output. - [#1121](https://github.com/lovell/sharp/pull/1121) - [@BiancoA](https://github.com/BiancoA) - -* Prevent crop operation when image already at or below target dimensions. - [#1134](https://github.com/lovell/sharp/issues/1134) - [@pieh](https://github.com/pieh) - -### v0.19.0 - 11th January 2018 - -* Expose offset coordinates of strategy-based crop. - [#868](https://github.com/lovell/sharp/issues/868) - [@mirohristov-com](https://github.com/mirohristov-com) - -* PNG output now defaults to adaptiveFiltering=false, compressionLevel=9 - [#872](https://github.com/lovell/sharp/issues/872) - [@wmertens](https://github.com/wmertens) - -* Add stats feature for pixel-derived image statistics. - [#915](https://github.com/lovell/sharp/pull/915) - [@rnanwani](https://github.com/rnanwani) - -* Add failOnError option to fail-fast on bad input image data. - [#976](https://github.com/lovell/sharp/pull/976) - [@mceachen](https://github.com/mceachen) - -* Resize: switch to libvips' implementation, make fastShrinkOnLoad optional, remove interpolator and centreSampling options. - [#977](https://github.com/lovell/sharp/pull/977) - [@jardakotesovec](https://github.com/jardakotesovec) - -* Attach finish event listener to a clone only for Stream-based input. - [#995](https://github.com/lovell/sharp/issues/995) - [@whmountains](https://github.com/whmountains) - -* Add tilecache before smartcrop to avoid over-computation of previous operations. - [#1028](https://github.com/lovell/sharp/issues/1028) - [@coffeebite](https://github.com/coffeebite) - -* Prevent toFile extension taking precedence over requested format. - [#1037](https://github.com/lovell/sharp/issues/1037) - [@tomgallagher](https://github.com/tomgallagher) - -* Add support for gravity option to existing embed feature. - [#1038](https://github.com/lovell/sharp/pull/1038) - [@AzureByte](https://github.com/AzureByte) - -* Expose IPTC and XMP metadata when available. - [#1079](https://github.com/lovell/sharp/pull/1079) - [@oaleynik](https://github.com/oaleynik) - -* TIFF output: switch default predictor from 'none' to 'horizontal' to match libvips' behaviour. - -## v0.18 - "*ridge*" - -Requires libvips v8.5.5. - -### v0.18.4 - 18th September 2017 - -* Ensure input Buffer really is marked as Persistent, prevents mark-sweep GC. - [#950](https://github.com/lovell/sharp/issues/950) - [@lfdoherty](https://github.com/lfdoherty) - -### v0.18.3 - 13th September 2017 - -* Skip shrink-on-load when trimming. - [#888](https://github.com/lovell/sharp/pull/888) - [@kleisauke](https://github.com/kleisauke) - -* Migrate from got to simple-get for basic auth support. - [#945](https://github.com/lovell/sharp/pull/945) - [@pbomb](https://github.com/pbomb) - -### v0.18.2 - 1st July 2017 - -* Expose libvips' xres and yres properties for TIFF output. - [#828](https://github.com/lovell/sharp/pull/828) - [@YvesBos](https://github.com/YvesBos) - -* Ensure flip and flop operations work with auto-rotate. - [#837](https://github.com/lovell/sharp/issues/837) - [@rexxars](https://github.com/rexxars) - -* Allow binary download URL override via SHARP_DIST_BASE_URL env variable. - [#841](https://github.com/lovell/sharp/issues/841) - -* Add support for Solus Linux. - [#857](https://github.com/lovell/sharp/pull/857) - [@ekremkaraca](https://github.com/ekremkaraca) - -### v0.18.1 - 30th May 2017 - -* Remove regression from #781 that could cause incorrect shrink calculation. - [#831](https://github.com/lovell/sharp/issues/831) - [@suprMax](https://github.com/suprMax) - -### v0.18.0 - 30th May 2017 - -* Remove the previously-deprecated output format "option" functions: - quality, progressive, compressionLevel, withoutAdaptiveFiltering, - withoutChromaSubsampling, trellisQuantisation, trellisQuantization, - overshootDeringing, optimiseScans and optimizeScans. - -* Ensure maximum output dimensions are based on the format to be used. - [#176](https://github.com/lovell/sharp/issues/176) - [@stephanebachelier](https://github.com/stephanebachelier) - -* Avoid costly (un)premultiply when using overlayWith without alpha channel. - [#573](https://github.com/lovell/sharp/issues/573) - [@strarsis](https://github.com/strarsis) - -* Include pixel depth (e.g. "uchar") when reading metadata. - [#577](https://github.com/lovell/sharp/issues/577) - [@moedusa](https://github.com/moedusa) - -* Add support for Buffer and Stream-based TIFF output. - [#587](https://github.com/lovell/sharp/issues/587) - [@strarsis](https://github.com/strarsis) - -* Expose warnings from libvips via NODE_DEBUG=sharp environment variable. - [#607](https://github.com/lovell/sharp/issues/607) - [@puzrin](https://github.com/puzrin) - -* Switch to the libvips implementation of "attention" and "entropy" crop strategies. - [#727](https://github.com/lovell/sharp/issues/727) - -* Improve performance and accuracy of nearest neighbour integral upsampling. - [#752](https://github.com/lovell/sharp/issues/752) - [@MrIbby](https://github.com/MrIbby) - -* Constructor single argument API: allow plain object, reject null/undefined. - [#768](https://github.com/lovell/sharp/issues/768) - [@kub1x](https://github.com/kub1x) - -* Ensure ARM64 pre-built binaries use correct C++11 ABI version. - [#772](https://github.com/lovell/sharp/issues/772) - [@ajiratech2](https://github.com/ajiratech2) - -* Prevent aliasing by using dynamic values for shrink(-on-load). - [#781](https://github.com/lovell/sharp/issues/781) - [@kleisauke](https://github.com/kleisauke) - -* Expose libvips' "squash" parameter to enable 1-bit TIFF output. - [#783](https://github.com/lovell/sharp/pull/783) - [@YvesBos](https://github.com/YvesBos) - -* Add support for rotation using any multiple of +/-90 degrees. - [#791](https://github.com/lovell/sharp/pull/791) - [@ncoden](https://github.com/ncoden) - -* Add "jpg" alias to toFormat as shortened form of "jpeg". - [#814](https://github.com/lovell/sharp/pull/814) - [@jingsam](https://github.com/jingsam) - -## v0.17 - "*quill*" - -Requires libvips v8.4.2. - -### v0.17.3 - 1st April 2017 - -* Allow toBuffer to optionally resolve a Promise with both info and data. - [#143](https://github.com/lovell/sharp/issues/143) - [@salzhrani](https://github.com/salzhrani) - -* Create blank image of given width, height, channels and background. - [#470](https://github.com/lovell/sharp/issues/470) - [@pjarts](https://github.com/pjarts) - -* Add support for the "nearest" kernel for image reductions. - [#732](https://github.com/lovell/sharp/pull/732) - [@alice0meta](https://github.com/alice0meta) - -* Add support for TIFF compression and predictor options. - [#738](https://github.com/lovell/sharp/pull/738) - [@kristojorg](https://github.com/kristojorg) - -### v0.17.2 - 11th February 2017 - -* Ensure Readable side of Stream can start flowing after Writable side has finished. - [#671](https://github.com/lovell/sharp/issues/671) - [@danhaller](https://github.com/danhaller) - -* Expose WebP alpha quality, lossless and near-lossless output options. - [#685](https://github.com/lovell/sharp/pull/685) - [@rnanwani](https://github.com/rnanwani) - -### v0.17.1 - 15th January 2017 - -* Improve error messages for invalid parameters. - [@spikeon](https://github.com/spikeon) - [#644](https://github.com/lovell/sharp/pull/644) - -* Simplify expression for finding vips-cpp libdir. - [#656](https://github.com/lovell/sharp/pull/656) - -* Allow HTTPS-over-HTTP proxy when downloading pre-compiled dependencies. - [@wangzhiwei1888](https://github.com/wangzhiwei1888) - [#679](https://github.com/lovell/sharp/issues/679) - -### v0.17.0 - 11th December 2016 - -* Drop support for versions of Node prior to v4. - -* Deprecate the following output format "option" functions: - quality, progressive, compressionLevel, withoutAdaptiveFiltering, - withoutChromaSubsampling, trellisQuantisation, trellisQuantization, - overshootDeringing, optimiseScans and optimizeScans. - Access to these is now via output format functions, for example `quality(n)` - is now `jpeg({quality: n})` and/or `webp({quality: n})`. - -* Autoconvert GIF and SVG input to PNG output if no other format is specified. - -* Expose libvips' "centre" resize option to mimic \*magick's +0.5px convention. - [#568](https://github.com/lovell/sharp/issues/568) - -* Ensure support for embedded base64 PNG and JPEG images within an SVG. - [#601](https://github.com/lovell/sharp/issues/601) - [@dynamite-ready](https://github.com/dynamite-ready) - -* Ensure premultiply operation occurs before box filter shrink. - [#605](https://github.com/lovell/sharp/issues/605) - [@CmdrShepardsPie](https://github.com/CmdrShepardsPie) - [@teroparvinen](https://github.com/teroparvinen) - -* Add support for PNG and WebP tile-based output formats (in addition to JPEG). - [#622](https://github.com/lovell/sharp/pull/622) - [@ppaskaris](https://github.com/ppaskaris) - -* Allow use of extend with greyscale input. - [#623](https://github.com/lovell/sharp/pull/623) - [@ppaskaris](https://github.com/ppaskaris) - -* Allow non-RGB input to embed/extend onto background with an alpha channel. - [#646](https://github.com/lovell/sharp/issues/646) - [@DaGaMs](https://github.com/DaGaMs) - -## v0.16 - "*pencil*" - -Requires libvips v8.3.3 - -### v0.16.2 - 22nd October 2016 - -* Restrict readelf usage to Linux only when detecting global libvips version. - [#602](https://github.com/lovell/sharp/issues/602) - [@caoko](https://github.com/caoko) - -### v0.16.1 - 13th October 2016 - -* C++11 ABI version is now auto-detected, remove sharp-cxx11 installation flag. - -* Add experimental 'attention' crop strategy. - [#295](https://github.com/lovell/sharp/issues/295) - -* Include .node extension for Meteor's require() implementation. - [#537](https://github.com/lovell/sharp/issues/537) - [@isjackwild](https://github.com/isjackwild) - -* Ensure convolution kernel scale is clamped to a minimum value of 1. - [#561](https://github.com/lovell/sharp/issues/561) - [@abagshaw](https://github.com/abagshaw) - -* Correct calculation of y-axis placement when overlaying image at a fixed point. - [#566](https://github.com/lovell/sharp/issues/566) - [@Nateowami](https://github.com/Nateowami) - -### v0.16.0 - 18th August 2016 - -* Add pre-compiled libvips for OS X, ARMv7 and ARMv8. - [#312](https://github.com/lovell/sharp/issues/312) - -* Ensure boolean, bandbool, extractChannel ops occur before sRGB conversion. - [#504](https://github.com/lovell/sharp/pull/504) - [@mhirsch](https://github.com/mhirsch) - -* Recalculate factors after WebP shrink-on-load to avoid round-to-zero errors. - [#508](https://github.com/lovell/sharp/issues/508) - [@asilvas](https://github.com/asilvas) - -* Prevent boolean errors during extract operation. - [#511](https://github.com/lovell/sharp/pull/511) - [@mhirsch](https://github.com/mhirsch) - -* Add joinChannel and toColourspace/toColorspace operations. - [#513](https://github.com/lovell/sharp/pull/513) - [@mhirsch](https://github.com/mhirsch) - -* Add support for raw pixel data with boolean and withOverlay operations. - [#516](https://github.com/lovell/sharp/pull/516) - [@mhirsch](https://github.com/mhirsch) - -* Prevent bandbool creating a single channel sRGB image. - [#519](https://github.com/lovell/sharp/pull/519) - [@mhirsch](https://github.com/mhirsch) - -* Ensure ICC profiles are removed from PNG output unless withMetadata used. - [#521](https://github.com/lovell/sharp/issues/521) - [@ChrisPinewood](https://github.com/ChrisPinewood) - -* Add alpha channels, if missing, to overlayWith images. - [#540](https://github.com/lovell/sharp/pull/540) - [@cmtt](https://github.com/cmtt) - -* Remove deprecated interpolateWith method - use resize(w, h, { interpolator: ... }) - [#310](https://github.com/lovell/sharp/issues/310) - -## v0.15 - "*outfit*" - -Requires libvips v8.3.1 - -### v0.15.1 - 12th July 2016 - -* Concat Stream-based input in single operation for ~+3% perf and less GC. - [#429](https://github.com/lovell/sharp/issues/429) - [@papandreou](https://github.com/papandreou) - -* Add alpha channel, if required, before extend operation. - [#439](https://github.com/lovell/sharp/pull/439) - [@frulo](https://github.com/frulo) - -* Allow overlay image to be repeated across entire image via tile option. - [#443](https://github.com/lovell/sharp/pull/443) - [@lemnisk8](https://github.com/lemnisk8) - -* Add cutout option to overlayWith feature, applies only the alpha channel of the overlay image. - [#448](https://github.com/lovell/sharp/pull/448) - [@kleisauke](https://github.com/kleisauke) - -* Ensure scaling factors are calculated independently to prevent rounding errors. - [#452](https://github.com/lovell/sharp/issues/452) - [@puzrin](https://github.com/puzrin) - -* Add --sharp-cxx11 flag to compile with gcc's new C++11 ABI. - [#456](https://github.com/lovell/sharp/pull/456) - [@kapouer](https://github.com/kapouer) - -* Add top/left offset support to overlayWith operation. - [#473](https://github.com/lovell/sharp/pull/473) - [@rnanwani](https://github.com/rnanwani) - -* Add convolve operation for kernel-based convolution. - [#479](https://github.com/lovell/sharp/pull/479) - [@mhirsch](https://github.com/mhirsch) - -* Add greyscale option to threshold operation for colourspace conversion control. - [#480](https://github.com/lovell/sharp/pull/480) - [@mhirsch](https://github.com/mhirsch) - -* Ensure ICC profiles are licenced for distribution. - [#486](https://github.com/lovell/sharp/issues/486) - [@kapouer](https://github.com/kapouer) - -* Allow images with an alpha channel to work with LAB-colourspace based sharpen. - [#490](https://github.com/lovell/sharp/issues/490) - [@jwagner](https://github.com/jwagner) - -* Add trim operation to remove "boring" edges. - [#492](https://github.com/lovell/sharp/pull/492) - [@kleisauke](https://github.com/kleisauke) - -* Add bandbool feature for channel-wise boolean operations. - [#496](https://github.com/lovell/sharp/pull/496) - [@mhirsch](https://github.com/mhirsch) - -* Add extractChannel operation to extract a channel from an image. - [#497](https://github.com/lovell/sharp/pull/497) - [@mhirsch](https://github.com/mhirsch) - -* Add ability to read and write native libvips .v files. - [#500](https://github.com/lovell/sharp/pull/500) - [@mhirsch](https://github.com/mhirsch) - -* Add boolean feature for bitwise image operations. - [#501](https://github.com/lovell/sharp/pull/501) - [@mhirsch](https://github.com/mhirsch) - -### v0.15.0 - 21st May 2016 - -* Use libvips' new Lanczos 3 kernel as default for image reduction. - Deprecate interpolateWith method, now provided as a resize option. - [#310](https://github.com/lovell/sharp/issues/310) - [@jcupitt](https://github.com/jcupitt) - -* Take advantage of libvips v8.3 features. - Add support for libvips' new GIF and SVG loaders. - Pre-built binaries now include giflib and librsvg, exclude *magick. - Use shrink-on-load for WebP input. - Break existing sharpen API to accept sigma and improve precision. - [#369](https://github.com/lovell/sharp/issues/369) - -* Remove unnecessary (un)premultiply operations when not resizing/compositing. - [#413](https://github.com/lovell/sharp/issues/413) - [@jardakotesovec](https://github.com/jardakotesovec) - -## v0.14 - "*needle*" - -Requires libvips v8.2.3 - -### v0.14.1 - 16th April 2016 - -* Allow removal of limitation on input pixel count via limitInputPixels. Use with care. - [#250](https://github.com/lovell/sharp/issues/250) - [#316](https://github.com/lovell/sharp/pull/316) - [@anandthakker](https://github.com/anandthakker) - [@kentongray](https://github.com/kentongray) - -* Use final output image for metadata passed to callback. - [#399](https://github.com/lovell/sharp/pull/399) - [@salzhrani](https://github.com/salzhrani) - -* Add support for writing tiled images to a zip container. - [#402](https://github.com/lovell/sharp/pull/402) - [@felixbuenemann](https://github.com/felixbuenemann) - -* Allow use of embed with 1 and 2 channel images. - [#411](https://github.com/lovell/sharp/issues/411) - [@janaz](https://github.com/janaz) - -* Improve Electron compatibility by allowing node-gyp rebuilds without npm. - [#412](https://github.com/lovell/sharp/issues/412) - [@nouh](https://github.com/nouh) - -### v0.14.0 - 2nd April 2016 - -* Add ability to extend (pad) the edges of an image. - [#128](https://github.com/lovell/sharp/issues/128) - [@blowsie](https://github.com/blowsie) - -* Add support for Zoomify and Google tile layouts. Breaks existing tile API. - [#223](https://github.com/lovell/sharp/issues/223) - [@bdunnette](https://github.com/bdunnette) - -* Improvements to overlayWith: differing sizes/formats, gravity, buffer input. - [#239](https://github.com/lovell/sharp/issues/239) - [@chrisriley](https://github.com/chrisriley) - -* Add entropy-based crop strategy to remove least interesting edges. - [#295](https://github.com/lovell/sharp/issues/295) - [@rightaway](https://github.com/rightaway) - -* Expose density metadata; set density of images from vector input. - [#338](https://github.com/lovell/sharp/issues/338) - [@lookfirst](https://github.com/lookfirst) - -* Emit post-processing 'info' event for Stream output. - [#367](https://github.com/lovell/sharp/issues/367) - [@salzhrani](https://github.com/salzhrani) - -* Ensure output image EXIF Orientation values are within 1-8 range. - [#385](https://github.com/lovell/sharp/pull/385) - [@jtobinisaniceguy](https://github.com/jtobinisaniceguy) - -* Ensure ratios are not swapped when rotating 90/270 and ignoring aspect. - [#387](https://github.com/lovell/sharp/issues/387) - [@kleisauke](https://github.com/kleisauke) - -* Remove deprecated style of calling extract API. Breaks calls using positional arguments. - [#276](https://github.com/lovell/sharp/issues/276) - -## v0.13 - "*mind*" - -Requires libvips v8.2.2 - -### v0.13.1 - 27th February 2016 - -* Fix embedding onto transparent backgrounds; regression introduced in v0.13.0. - [#366](https://github.com/lovell/sharp/issues/366) - [@diegocsandrim](https://github.com/diegocsandrim) - -### v0.13.0 - 15th February 2016 - -* Improve vector image support by allowing control of density/DPI. - Switch pre-built libs from Imagemagick to Graphicsmagick. - [#110](https://github.com/lovell/sharp/issues/110) - [@bradisbell](https://github.com/bradisbell) - -* Add support for raw, uncompressed pixel Buffer/Stream input. - [#220](https://github.com/lovell/sharp/issues/220) - [@mikemorris](https://github.com/mikemorris) - -* Switch from libvips' C to C++ bindings, requires upgrade to v8.2.2. - [#299](https://github.com/lovell/sharp/issues/299) - -* Control number of open files in libvips' cache; breaks existing `cache` behaviour. - [#315](https://github.com/lovell/sharp/issues/315) - [@impomezia](https://github.com/impomezia) - -* Ensure 16-bit input images can be normalised and embedded onto transparent backgrounds. - [#339](https://github.com/lovell/sharp/issues/339) - [#340](https://github.com/lovell/sharp/issues/340) - [@janaz](https://github.com/janaz) - -* Ensure selected format takes precedence over any unknown output filename extension. - [#344](https://github.com/lovell/sharp/issues/344) - [@ubaltaci](https://github.com/ubaltaci) - -* Add support for libvips' PBM, PGM, PPM and FITS image format loaders. - [#347](https://github.com/lovell/sharp/issues/347) - [@oaleynik](https://github.com/oaleynik) - -* Ensure default crop gravity is center/centre. - [#351](https://github.com/lovell/sharp/pull/351) - [@joelmukuthu](https://github.com/joelmukuthu) - -* Improve support for musl libc systems e.g. Alpine Linux. - [#354](https://github.com/lovell/sharp/issues/354) - [#359](https://github.com/lovell/sharp/pull/359) - [@download13](https://github.com/download13) - [@wjordan](https://github.com/wjordan) - -* Small optimisation when reducing by an integral factor to favour shrink over affine. - -* Add support for gamma correction of images with an alpha channel. - -## v0.12 - "*look*" - -Requires libvips v8.2.0 - -### v0.12.2 - 16th January 2016 - -* Upgrade libvips to v8.2.0 for improved vips_shrink. - -* Add pre-compiled libvips for ARMv6+ CPUs. - -* Ensure 16-bit input images work with embed option. - [#325](https://github.com/lovell/sharp/issues/325) - [@janaz](https://github.com/janaz) - -* Allow compilation with gmake to provide FreeBSD support. - [#326](https://github.com/lovell/sharp/issues/326) - [@c0decafe](https://github.com/c0decafe) - -* Attempt to remove temporary file after installation. - [#331](https://github.com/lovell/sharp/issues/331) - [@dtoubelis](https://github.com/dtoubelis) - -### v0.12.1 - 12th December 2015 - -* Allow use of SIMD vector instructions (via liborc) to be toggled on/off. - [#172](https://github.com/lovell/sharp/issues/172) - [@bkw](https://github.com/bkw) - [@puzrin](https://github.com/puzrin) - -* Ensure embedded ICC profiles output with perceptual intent. - [#321](https://github.com/lovell/sharp/issues/321) - [@vlapo](https://github.com/vlapo) - -* Use the NPM-configured HTTPS proxy, if any, for binary downloads. - -### v0.12.0 - 23rd November 2015 - -* Bundle pre-compiled libvips and its dependencies for 64-bit Linux and Windows. - [#42](https://github.com/lovell/sharp/issues/42) - -* Take advantage of libvips v8.1.0+ features. - [#152](https://github.com/lovell/sharp/issues/152) - -* Add support for 64-bit Windows. Drop support for 32-bit Windows. - [#224](https://github.com/lovell/sharp/issues/224) - [@sabrehagen](https://github.com/sabrehagen) - -* Switch default interpolator to bicubic. - [#289](https://github.com/lovell/sharp/issues/289) - [@mahnunchik](https://github.com/mahnunchik) - -* Pre-extract rotatation should not swap width/height. - [#296](https://github.com/lovell/sharp/issues/296) - [@asilvas](https://github.com/asilvas) - -* Ensure 16-bit+alpha input images are (un)premultiplied correctly. - [#301](https://github.com/lovell/sharp/issues/301) - [@izaakschroeder](https://github.com/izaakschroeder) - -* Add `threshold` operation. - [#303](https://github.com/lovell/sharp/pull/303) - [@dacarley](https://github.com/dacarley) - -* Add `negate` operation. - [#306](https://github.com/lovell/sharp/pull/306) - [@dacarley](https://github.com/dacarley) - -* Support `options` Object with existing `extract` operation. - [#309](https://github.com/lovell/sharp/pull/309) - [@papandreou](https://github.com/papandreou) - -## v0.11 - "*knife*" - -### v0.11.4 - 5th November 2015 - -* Add corners, e.g. `northeast`, to existing `gravity` option. - [#291](https://github.com/lovell/sharp/pull/291) - [@brandonaaron](https://github.com/brandonaaron) - -* Ensure correct auto-rotation for EXIF Orientation values 2 and 4. - [#288](https://github.com/lovell/sharp/pull/288) - [@brandonaaron](https://github.com/brandonaaron) - -* Make static linking possible via `--runtime_link` install option. - [#287](https://github.com/lovell/sharp/pull/287) - [@vlapo](https://github.com/vlapo) - -### v0.11.3 - 8th September 2015 - -* Intrepret blurSigma, sharpenFlat, and sharpenJagged as double precision. - [#263](https://github.com/lovell/sharp/pull/263) - [@chrisriley](https://github.com/chrisriley) - -### v0.11.2 - 28th August 2015 - -* Allow crop gravity to be provided as a String. - [#255](https://github.com/lovell/sharp/pull/255) - [@papandreou](https://github.com/papandreou) -* Add support for io.js v3 and Node v4. - [#246](https://github.com/lovell/sharp/issues/246) - -### v0.11.1 - 12th August 2015 - -* Silence MSVC warning: "C4530: C++ exception handler used, but unwind semantics are not enabled". - [#244](https://github.com/lovell/sharp/pull/244) - [@TheThing](https://github.com/TheThing) - -* Suppress gamma correction for input image with alpha transparency. - [#249](https://github.com/lovell/sharp/issues/249) - [@compeak](https://github.com/compeak) - -### v0.11.0 - 15th July 2015 - -* Allow alpha transparency compositing via new `overlayWith` method. - [#97](https://github.com/lovell/sharp/issues/97) - [@gasi](https://github.com/gasi) - -* Expose raw ICC profile data as a Buffer when using `metadata`. - [#129](https://github.com/lovell/sharp/issues/129) - [@homerjam](https://github.com/homerjam) - -* Allow image header updates via a parameter passed to existing `withMetadata` method. - Provide initial support for EXIF `Orientation` tag, - which if present is now removed when using `rotate`, `flip` or `flop`. - [#189](https://github.com/lovell/sharp/issues/189) - [@h2non](https://github.com/h2non) - -* Tighten constructor parameter checks. - [#221](https://github.com/lovell/sharp/issues/221) - [@mikemorris](https://github.com/mikemorris) - -* Allow one input Stream to be shared with two or more output Streams via new `clone` method. - [#235](https://github.com/lovell/sharp/issues/235) - [@jaubourg](https://github.com/jaubourg) - -* Use `round` instead of `floor` when auto-scaling dimensions to avoid floating-point rounding errors. - [#238](https://github.com/lovell/sharp/issues/238) - [@richardadjogah](https://github.com/richardadjogah) - -## v0.10 - "*judgment*" - -### v0.10.1 - 1st June 2015 - -* Allow embed of image with alpha transparency onto non-transparent background. - [#204](https://github.com/lovell/sharp/issues/204) - [@mikemliu](https://github.com/mikemliu) - -* Include C standard library for `atoi` as Xcode 6.3 appears to no longer do this. - [#228](https://github.com/lovell/sharp/issues/228) - [@doggan](https://github.com/doggan) - -### v0.10.0 - 23rd April 2015 - -* Add support for Windows (x86). - [#19](https://github.com/lovell/sharp/issues/19) - [@DullReferenceException](https://github.com/DullReferenceException) - [@itsananderson](https://github.com/itsananderson) - -* Add support for Openslide input and DeepZoom output. - [#146](https://github.com/lovell/sharp/issues/146) - [@mvictoras](https://github.com/mvictoras) - -* Allow arbitrary aspect ratios when resizing images via new `ignoreAspectRatio` method. - [#192](https://github.com/lovell/sharp/issues/192) - [@skedastik](https://github.com/skedastik) - -* Enhance output image contrast by stretching its luminance to cover the full dynamic range via new `normalize` method. - [#194](https://github.com/lovell/sharp/issues/194) - [@bkw](https://github.com/bkw) - [@codingforce](https://github.com/codingforce) diff --git a/docs/src/content/docs/changelog/_meta.yml b/docs/src/content/docs/changelog/_meta.yml new file mode 100644 index 000000000..5dd257241 --- /dev/null +++ b/docs/src/content/docs/changelog/_meta.yml @@ -0,0 +1 @@ +sort: reverse-slug diff --git a/docs/src/content/docs/changelog/v0.10.0.md b/docs/src/content/docs/changelog/v0.10.0.md new file mode 100644 index 000000000..aae2ca0ee --- /dev/null +++ b/docs/src/content/docs/changelog/v0.10.0.md @@ -0,0 +1,22 @@ +--- +title: v0.10.0 - 23rd April 2015 +slug: changelog/v0.10.0 +--- + +* Add support for Windows (x86). + [#19](https://github.com/lovell/sharp/issues/19) + [@DullReferenceException](https://github.com/DullReferenceException) + [@itsananderson](https://github.com/itsananderson) + +* Add support for Openslide input and DeepZoom output. + [#146](https://github.com/lovell/sharp/issues/146) + [@mvictoras](https://github.com/mvictoras) + +* Allow arbitrary aspect ratios when resizing images via new `ignoreAspectRatio` method. + [#192](https://github.com/lovell/sharp/issues/192) + [@skedastik](https://github.com/skedastik) + +* Enhance output image contrast by stretching its luminance to cover the full dynamic range via new `normalize` method. + [#194](https://github.com/lovell/sharp/issues/194) + [@bkw](https://github.com/bkw) + [@codingforce](https://github.com/codingforce) diff --git a/docs/src/content/docs/changelog/v0.10.1.md b/docs/src/content/docs/changelog/v0.10.1.md new file mode 100644 index 000000000..6f0336861 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.10.1.md @@ -0,0 +1,12 @@ +--- +title: v0.10.1 - 1st June 2015 +slug: changelog/v0.10.1 +--- + +* Allow embed of image with alpha transparency onto non-transparent background. + [#204](https://github.com/lovell/sharp/issues/204) + [@mikemliu](https://github.com/mikemliu) + +* Include C standard library for `atoi` as Xcode 6.3 appears to no longer do this. + [#228](https://github.com/lovell/sharp/issues/228) + [@doggan](https://github.com/doggan) diff --git a/docs/src/content/docs/changelog/v0.11.0.md b/docs/src/content/docs/changelog/v0.11.0.md new file mode 100644 index 000000000..2b07a93a5 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.11.0.md @@ -0,0 +1,30 @@ +--- +title: v0.11.0 - 15th July 2015 +slug: changelog/v0.11.0 +--- + +* Allow alpha transparency compositing via new `overlayWith` method. + [#97](https://github.com/lovell/sharp/issues/97) + [@gasi](https://github.com/gasi) + +* Expose raw ICC profile data as a Buffer when using `metadata`. + [#129](https://github.com/lovell/sharp/issues/129) + [@homerjam](https://github.com/homerjam) + +* Allow image header updates via a parameter passed to existing `withMetadata` method. + Provide initial support for EXIF `Orientation` tag, + which if present is now removed when using `rotate`, `flip` or `flop`. + [#189](https://github.com/lovell/sharp/issues/189) + [@h2non](https://github.com/h2non) + +* Tighten constructor parameter checks. + [#221](https://github.com/lovell/sharp/issues/221) + [@mikemorris](https://github.com/mikemorris) + +* Allow one input Stream to be shared with two or more output Streams via new `clone` method. + [#235](https://github.com/lovell/sharp/issues/235) + [@jaubourg](https://github.com/jaubourg) + +* Use `round` instead of `floor` when auto-scaling dimensions to avoid floating-point rounding errors. + [#238](https://github.com/lovell/sharp/issues/238) + [@richardadjogah](https://github.com/richardadjogah) diff --git a/docs/src/content/docs/changelog/v0.11.1.md b/docs/src/content/docs/changelog/v0.11.1.md new file mode 100644 index 000000000..44bdfc925 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.11.1.md @@ -0,0 +1,12 @@ +--- +title: v0.11.1 - 12th August 2015 +slug: changelog/v0.11.1 +--- + +* Silence MSVC warning: "C4530: C++ exception handler used, but unwind semantics are not enabled". + [#244](https://github.com/lovell/sharp/pull/244) + [@TheThing](https://github.com/TheThing) + +* Suppress gamma correction for input image with alpha transparency. + [#249](https://github.com/lovell/sharp/issues/249) + [@compeak](https://github.com/compeak) diff --git a/docs/src/content/docs/changelog/v0.11.2.md b/docs/src/content/docs/changelog/v0.11.2.md new file mode 100644 index 000000000..9990b05f7 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.11.2.md @@ -0,0 +1,10 @@ +--- +title: v0.11.2 - 28th August 2015 +slug: changelog/v0.11.2 +--- + +* Allow crop gravity to be provided as a String. + [#255](https://github.com/lovell/sharp/pull/255) + [@papandreou](https://github.com/papandreou) +* Add support for io.js v3 and Node v4. + [#246](https://github.com/lovell/sharp/issues/246) diff --git a/docs/src/content/docs/changelog/v0.11.3.md b/docs/src/content/docs/changelog/v0.11.3.md new file mode 100644 index 000000000..a062d1b8b --- /dev/null +++ b/docs/src/content/docs/changelog/v0.11.3.md @@ -0,0 +1,8 @@ +--- +title: v0.11.3 - 8th September 2015 +slug: changelog/v0.11.3 +--- + +* Intrepret blurSigma, sharpenFlat, and sharpenJagged as double precision. + [#263](https://github.com/lovell/sharp/pull/263) + [@chrisriley](https://github.com/chrisriley) diff --git a/docs/src/content/docs/changelog/v0.11.4.md b/docs/src/content/docs/changelog/v0.11.4.md new file mode 100644 index 000000000..f8cba2cd6 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.11.4.md @@ -0,0 +1,16 @@ +--- +title: v0.11.4 - 5th November 2015 +slug: changelog/v0.11.4 +--- + +* Add corners, e.g. `northeast`, to existing `gravity` option. + [#291](https://github.com/lovell/sharp/pull/291) + [@brandonaaron](https://github.com/brandonaaron) + +* Ensure correct auto-rotation for EXIF Orientation values 2 and 4. + [#288](https://github.com/lovell/sharp/pull/288) + [@brandonaaron](https://github.com/brandonaaron) + +* Make static linking possible via `--runtime_link` install option. + [#287](https://github.com/lovell/sharp/pull/287) + [@vlapo](https://github.com/vlapo) diff --git a/docs/src/content/docs/changelog/v0.12.0.md b/docs/src/content/docs/changelog/v0.12.0.md new file mode 100644 index 000000000..c081be9de --- /dev/null +++ b/docs/src/content/docs/changelog/v0.12.0.md @@ -0,0 +1,38 @@ +--- +title: v0.12.0 - 23rd November 2015 +slug: changelog/v0.12.0 +--- + +* Bundle pre-compiled libvips and its dependencies for 64-bit Linux and Windows. + [#42](https://github.com/lovell/sharp/issues/42) + +* Take advantage of libvips v8.1.0+ features. + [#152](https://github.com/lovell/sharp/issues/152) + +* Add support for 64-bit Windows. Drop support for 32-bit Windows. + [#224](https://github.com/lovell/sharp/issues/224) + [@sabrehagen](https://github.com/sabrehagen) + +* Switch default interpolator to bicubic. + [#289](https://github.com/lovell/sharp/issues/289) + [@mahnunchik](https://github.com/mahnunchik) + +* Pre-extract rotatation should not swap width/height. + [#296](https://github.com/lovell/sharp/issues/296) + [@asilvas](https://github.com/asilvas) + +* Ensure 16-bit+alpha input images are (un)premultiplied correctly. + [#301](https://github.com/lovell/sharp/issues/301) + [@izaakschroeder](https://github.com/izaakschroeder) + +* Add `threshold` operation. + [#303](https://github.com/lovell/sharp/pull/303) + [@dacarley](https://github.com/dacarley) + +* Add `negate` operation. + [#306](https://github.com/lovell/sharp/pull/306) + [@dacarley](https://github.com/dacarley) + +* Support `options` Object with existing `extract` operation. + [#309](https://github.com/lovell/sharp/pull/309) + [@papandreou](https://github.com/papandreou) diff --git a/docs/src/content/docs/changelog/v0.12.1.md b/docs/src/content/docs/changelog/v0.12.1.md new file mode 100644 index 000000000..61fb46a80 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.12.1.md @@ -0,0 +1,15 @@ +--- +title: v0.12.1 - 12th December 2015 +slug: changelog/v0.12.1 +--- + +* Allow use of SIMD vector instructions (via liborc) to be toggled on/off. + [#172](https://github.com/lovell/sharp/issues/172) + [@bkw](https://github.com/bkw) + [@puzrin](https://github.com/puzrin) + +* Ensure embedded ICC profiles output with perceptual intent. + [#321](https://github.com/lovell/sharp/issues/321) + [@vlapo](https://github.com/vlapo) + +* Use the NPM-configured HTTPS proxy, if any, for binary downloads. diff --git a/docs/src/content/docs/changelog/v0.12.2.md b/docs/src/content/docs/changelog/v0.12.2.md new file mode 100644 index 000000000..91dd927de --- /dev/null +++ b/docs/src/content/docs/changelog/v0.12.2.md @@ -0,0 +1,20 @@ +--- +title: v0.12.2 - 16th January 2016 +slug: changelog/v0.12.2 +--- + +* Upgrade libvips to v8.2.0 for improved vips_shrink. + +* Add pre-compiled libvips for ARMv6+ CPUs. + +* Ensure 16-bit input images work with embed option. + [#325](https://github.com/lovell/sharp/issues/325) + [@janaz](https://github.com/janaz) + +* Allow compilation with gmake to provide FreeBSD support. + [#326](https://github.com/lovell/sharp/issues/326) + [@c0decafe](https://github.com/c0decafe) + +* Attempt to remove temporary file after installation. + [#331](https://github.com/lovell/sharp/issues/331) + [@dtoubelis](https://github.com/dtoubelis) diff --git a/docs/src/content/docs/changelog/v0.13.0.md b/docs/src/content/docs/changelog/v0.13.0.md new file mode 100644 index 000000000..f1c989a6b --- /dev/null +++ b/docs/src/content/docs/changelog/v0.13.0.md @@ -0,0 +1,47 @@ +--- +title: v0.13.0 - 15th February 2016 +slug: changelog/v0.13.0 +--- + +* Improve vector image support by allowing control of density/DPI. + Switch pre-built libs from Imagemagick to Graphicsmagick. + [#110](https://github.com/lovell/sharp/issues/110) + [@bradisbell](https://github.com/bradisbell) + +* Add support for raw, uncompressed pixel Buffer/Stream input. + [#220](https://github.com/lovell/sharp/issues/220) + [@mikemorris](https://github.com/mikemorris) + +* Switch from libvips' C to C++ bindings, requires upgrade to v8.2.2. + [#299](https://github.com/lovell/sharp/issues/299) + +* Control number of open files in libvips' cache; breaks existing `cache` behaviour. + [#315](https://github.com/lovell/sharp/issues/315) + [@impomezia](https://github.com/impomezia) + +* Ensure 16-bit input images can be normalised and embedded onto transparent backgrounds. + [#339](https://github.com/lovell/sharp/issues/339) + [#340](https://github.com/lovell/sharp/issues/340) + [@janaz](https://github.com/janaz) + +* Ensure selected format takes precedence over any unknown output filename extension. + [#344](https://github.com/lovell/sharp/issues/344) + [@ubaltaci](https://github.com/ubaltaci) + +* Add support for libvips' PBM, PGM, PPM and FITS image format loaders. + [#347](https://github.com/lovell/sharp/issues/347) + [@oaleynik](https://github.com/oaleynik) + +* Ensure default crop gravity is center/centre. + [#351](https://github.com/lovell/sharp/pull/351) + [@joelmukuthu](https://github.com/joelmukuthu) + +* Improve support for musl libc systems e.g. Alpine Linux. + [#354](https://github.com/lovell/sharp/issues/354) + [#359](https://github.com/lovell/sharp/pull/359) + [@download13](https://github.com/download13) + [@wjordan](https://github.com/wjordan) + +* Small optimisation when reducing by an integral factor to favour shrink over affine. + +* Add support for gamma correction of images with an alpha channel. diff --git a/docs/src/content/docs/changelog/v0.13.1.md b/docs/src/content/docs/changelog/v0.13.1.md new file mode 100644 index 000000000..cbaf11ec5 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.13.1.md @@ -0,0 +1,8 @@ +--- +title: v0.13.1 - 27th February 2016 +slug: changelog/v0.13.1 +--- + +* Fix embedding onto transparent backgrounds; regression introduced in v0.13.0. + [#366](https://github.com/lovell/sharp/issues/366) + [@diegocsandrim](https://github.com/diegocsandrim) diff --git a/docs/src/content/docs/changelog/v0.14.0.md b/docs/src/content/docs/changelog/v0.14.0.md new file mode 100644 index 000000000..a23f2e7f0 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.14.0.md @@ -0,0 +1,39 @@ +--- +title: v0.14.0 - 2nd April 2016 +slug: changelog/v0.14.0 +--- + +* Add ability to extend (pad) the edges of an image. + [#128](https://github.com/lovell/sharp/issues/128) + [@blowsie](https://github.com/blowsie) + +* Add support for Zoomify and Google tile layouts. Breaks existing tile API. + [#223](https://github.com/lovell/sharp/issues/223) + [@bdunnette](https://github.com/bdunnette) + +* Improvements to overlayWith: differing sizes/formats, gravity, buffer input. + [#239](https://github.com/lovell/sharp/issues/239) + [@chrisriley](https://github.com/chrisriley) + +* Add entropy-based crop strategy to remove least interesting edges. + [#295](https://github.com/lovell/sharp/issues/295) + [@rightaway](https://github.com/rightaway) + +* Expose density metadata; set density of images from vector input. + [#338](https://github.com/lovell/sharp/issues/338) + [@lookfirst](https://github.com/lookfirst) + +* Emit post-processing 'info' event for Stream output. + [#367](https://github.com/lovell/sharp/issues/367) + [@salzhrani](https://github.com/salzhrani) + +* Ensure output image EXIF Orientation values are within 1-8 range. + [#385](https://github.com/lovell/sharp/pull/385) + [@jtobinisaniceguy](https://github.com/jtobinisaniceguy) + +* Ensure ratios are not swapped when rotating 90/270 and ignoring aspect. + [#387](https://github.com/lovell/sharp/issues/387) + [@kleisauke](https://github.com/kleisauke) + +* Remove deprecated style of calling extract API. Breaks calls using positional arguments. + [#276](https://github.com/lovell/sharp/issues/276) diff --git a/docs/src/content/docs/changelog/v0.14.1.md b/docs/src/content/docs/changelog/v0.14.1.md new file mode 100644 index 000000000..85e88c8b1 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.14.1.md @@ -0,0 +1,26 @@ +--- +title: v0.14.1 - 16th April 2016 +slug: changelog/v0.14.1 +--- + +* Allow removal of limitation on input pixel count via limitInputPixels. Use with care. + [#250](https://github.com/lovell/sharp/issues/250) + [#316](https://github.com/lovell/sharp/pull/316) + [@anandthakker](https://github.com/anandthakker) + [@kentongray](https://github.com/kentongray) + +* Use final output image for metadata passed to callback. + [#399](https://github.com/lovell/sharp/pull/399) + [@salzhrani](https://github.com/salzhrani) + +* Add support for writing tiled images to a zip container. + [#402](https://github.com/lovell/sharp/pull/402) + [@felixbuenemann](https://github.com/felixbuenemann) + +* Allow use of embed with 1 and 2 channel images. + [#411](https://github.com/lovell/sharp/issues/411) + [@janaz](https://github.com/janaz) + +* Improve Electron compatibility by allowing node-gyp rebuilds without npm. + [#412](https://github.com/lovell/sharp/issues/412) + [@nouh](https://github.com/nouh) diff --git a/docs/src/content/docs/changelog/v0.15.0.md b/docs/src/content/docs/changelog/v0.15.0.md new file mode 100644 index 000000000..ed7807f98 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.15.0.md @@ -0,0 +1,20 @@ +--- +title: v0.15.0 - 21st May 2016 +slug: changelog/v0.15.0 +--- + +* Use libvips' new Lanczos 3 kernel as default for image reduction. + Deprecate interpolateWith method, now provided as a resize option. + [#310](https://github.com/lovell/sharp/issues/310) + [@jcupitt](https://github.com/jcupitt) + +* Take advantage of libvips v8.3 features. + Add support for libvips' new GIF and SVG loaders. + Pre-built binaries now include giflib and librsvg, exclude *magick. + Use shrink-on-load for WebP input. + Break existing sharpen API to accept sigma and improve precision. + [#369](https://github.com/lovell/sharp/issues/369) + +* Remove unnecessary (un)premultiply operations when not resizing/compositing. + [#413](https://github.com/lovell/sharp/issues/413) + [@jardakotesovec](https://github.com/jardakotesovec) diff --git a/docs/src/content/docs/changelog/v0.15.1.md b/docs/src/content/docs/changelog/v0.15.1.md new file mode 100644 index 000000000..4cfdfba7d --- /dev/null +++ b/docs/src/content/docs/changelog/v0.15.1.md @@ -0,0 +1,68 @@ +--- +title: v0.15.1 - 12th July 2016 +slug: changelog/v0.15.1 +--- + +* Concat Stream-based input in single operation for ~+3% perf and less GC. + [#429](https://github.com/lovell/sharp/issues/429) + [@papandreou](https://github.com/papandreou) + +* Add alpha channel, if required, before extend operation. + [#439](https://github.com/lovell/sharp/pull/439) + [@frulo](https://github.com/frulo) + +* Allow overlay image to be repeated across entire image via tile option. + [#443](https://github.com/lovell/sharp/pull/443) + [@lemnisk8](https://github.com/lemnisk8) + +* Add cutout option to overlayWith feature, applies only the alpha channel of the overlay image. + [#448](https://github.com/lovell/sharp/pull/448) + [@kleisauke](https://github.com/kleisauke) + +* Ensure scaling factors are calculated independently to prevent rounding errors. + [#452](https://github.com/lovell/sharp/issues/452) + [@puzrin](https://github.com/puzrin) + +* Add --sharp-cxx11 flag to compile with gcc's new C++11 ABI. + [#456](https://github.com/lovell/sharp/pull/456) + [@kapouer](https://github.com/kapouer) + +* Add top/left offset support to overlayWith operation. + [#473](https://github.com/lovell/sharp/pull/473) + [@rnanwani](https://github.com/rnanwani) + +* Add convolve operation for kernel-based convolution. + [#479](https://github.com/lovell/sharp/pull/479) + [@mhirsch](https://github.com/mhirsch) + +* Add greyscale option to threshold operation for colourspace conversion control. + [#480](https://github.com/lovell/sharp/pull/480) + [@mhirsch](https://github.com/mhirsch) + +* Ensure ICC profiles are licenced for distribution. + [#486](https://github.com/lovell/sharp/issues/486) + [@kapouer](https://github.com/kapouer) + +* Allow images with an alpha channel to work with LAB-colourspace based sharpen. + [#490](https://github.com/lovell/sharp/issues/490) + [@jwagner](https://github.com/jwagner) + +* Add trim operation to remove "boring" edges. + [#492](https://github.com/lovell/sharp/pull/492) + [@kleisauke](https://github.com/kleisauke) + +* Add bandbool feature for channel-wise boolean operations. + [#496](https://github.com/lovell/sharp/pull/496) + [@mhirsch](https://github.com/mhirsch) + +* Add extractChannel operation to extract a channel from an image. + [#497](https://github.com/lovell/sharp/pull/497) + [@mhirsch](https://github.com/mhirsch) + +* Add ability to read and write native libvips .v files. + [#500](https://github.com/lovell/sharp/pull/500) + [@mhirsch](https://github.com/mhirsch) + +* Add boolean feature for bitwise image operations. + [#501](https://github.com/lovell/sharp/pull/501) + [@mhirsch](https://github.com/mhirsch) diff --git a/docs/src/content/docs/changelog/v0.16.0.md b/docs/src/content/docs/changelog/v0.16.0.md new file mode 100644 index 000000000..b6af330fd --- /dev/null +++ b/docs/src/content/docs/changelog/v0.16.0.md @@ -0,0 +1,42 @@ +--- +title: v0.16.0 - 18th August 2016 +slug: changelog/v0.16.0 +--- + +* Add pre-compiled libvips for OS X, ARMv7 and ARMv8. + [#312](https://github.com/lovell/sharp/issues/312) + +* Ensure boolean, bandbool, extractChannel ops occur before sRGB conversion. + [#504](https://github.com/lovell/sharp/pull/504) + [@mhirsch](https://github.com/mhirsch) + +* Recalculate factors after WebP shrink-on-load to avoid round-to-zero errors. + [#508](https://github.com/lovell/sharp/issues/508) + [@asilvas](https://github.com/asilvas) + +* Prevent boolean errors during extract operation. + [#511](https://github.com/lovell/sharp/pull/511) + [@mhirsch](https://github.com/mhirsch) + +* Add joinChannel and toColourspace/toColorspace operations. + [#513](https://github.com/lovell/sharp/pull/513) + [@mhirsch](https://github.com/mhirsch) + +* Add support for raw pixel data with boolean and withOverlay operations. + [#516](https://github.com/lovell/sharp/pull/516) + [@mhirsch](https://github.com/mhirsch) + +* Prevent bandbool creating a single channel sRGB image. + [#519](https://github.com/lovell/sharp/pull/519) + [@mhirsch](https://github.com/mhirsch) + +* Ensure ICC profiles are removed from PNG output unless withMetadata used. + [#521](https://github.com/lovell/sharp/issues/521) + [@ChrisPinewood](https://github.com/ChrisPinewood) + +* Add alpha channels, if missing, to overlayWith images. + [#540](https://github.com/lovell/sharp/pull/540) + [@cmtt](https://github.com/cmtt) + +* Remove deprecated interpolateWith method - use resize(w, h, { interpolator: ... }) + [#310](https://github.com/lovell/sharp/issues/310) diff --git a/docs/src/content/docs/changelog/v0.16.1.md b/docs/src/content/docs/changelog/v0.16.1.md new file mode 100644 index 000000000..c49d28981 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.16.1.md @@ -0,0 +1,21 @@ +--- +title: v0.16.1 - 13th October 2016 +slug: changelog/v0.16.1 +--- + +* C++11 ABI version is now auto-detected, remove sharp-cxx11 installation flag. + +* Add experimental 'attention' crop strategy. + [#295](https://github.com/lovell/sharp/issues/295) + +* Include .node extension for Meteor's require() implementation. + [#537](https://github.com/lovell/sharp/issues/537) + [@isjackwild](https://github.com/isjackwild) + +* Ensure convolution kernel scale is clamped to a minimum value of 1. + [#561](https://github.com/lovell/sharp/issues/561) + [@abagshaw](https://github.com/abagshaw) + +* Correct calculation of y-axis placement when overlaying image at a fixed point. + [#566](https://github.com/lovell/sharp/issues/566) + [@Nateowami](https://github.com/Nateowami) diff --git a/docs/src/content/docs/changelog/v0.16.2.md b/docs/src/content/docs/changelog/v0.16.2.md new file mode 100644 index 000000000..8c3976c64 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.16.2.md @@ -0,0 +1,8 @@ +--- +title: v0.16.2 - 22nd October 2016 +slug: changelog/v0.16.2 +--- + +* Restrict readelf usage to Linux only when detecting global libvips version. + [#602](https://github.com/lovell/sharp/issues/602) + [@caoko](https://github.com/caoko) diff --git a/docs/src/content/docs/changelog/v0.17.0.md b/docs/src/content/docs/changelog/v0.17.0.md new file mode 100644 index 000000000..4ec1f1856 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.17.0.md @@ -0,0 +1,39 @@ +--- +title: v0.17.0 - 11th December 2016 +slug: changelog/v0.17.0 +--- + +* Drop support for versions of Node prior to v4. + +* Deprecate the following output format "option" functions: + quality, progressive, compressionLevel, withoutAdaptiveFiltering, + withoutChromaSubsampling, trellisQuantisation, trellisQuantization, + overshootDeringing, optimiseScans and optimizeScans. + Access to these is now via output format functions, for example `quality(n)` + is now `jpeg({quality: n})` and/or `webp({quality: n})`. + +* Autoconvert GIF and SVG input to PNG output if no other format is specified. + +* Expose libvips' "centre" resize option to mimic \*magick's +0.5px convention. + [#568](https://github.com/lovell/sharp/issues/568) + +* Ensure support for embedded base64 PNG and JPEG images within an SVG. + [#601](https://github.com/lovell/sharp/issues/601) + [@dynamite-ready](https://github.com/dynamite-ready) + +* Ensure premultiply operation occurs before box filter shrink. + [#605](https://github.com/lovell/sharp/issues/605) + [@CmdrShepardsPie](https://github.com/CmdrShepardsPie) + [@teroparvinen](https://github.com/teroparvinen) + +* Add support for PNG and WebP tile-based output formats (in addition to JPEG). + [#622](https://github.com/lovell/sharp/pull/622) + [@ppaskaris](https://github.com/ppaskaris) + +* Allow use of extend with greyscale input. + [#623](https://github.com/lovell/sharp/pull/623) + [@ppaskaris](https://github.com/ppaskaris) + +* Allow non-RGB input to embed/extend onto background with an alpha channel. + [#646](https://github.com/lovell/sharp/issues/646) + [@DaGaMs](https://github.com/DaGaMs) diff --git a/docs/src/content/docs/changelog/v0.17.1.md b/docs/src/content/docs/changelog/v0.17.1.md new file mode 100644 index 000000000..28cf12167 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.17.1.md @@ -0,0 +1,15 @@ +--- +title: v0.17.1 - 15th January 2017 +slug: changelog/v0.17.1 +--- + +* Improve error messages for invalid parameters. + [@spikeon](https://github.com/spikeon) + [#644](https://github.com/lovell/sharp/pull/644) + +* Simplify expression for finding vips-cpp libdir. + [#656](https://github.com/lovell/sharp/pull/656) + +* Allow HTTPS-over-HTTP proxy when downloading pre-compiled dependencies. + [@wangzhiwei1888](https://github.com/wangzhiwei1888) + [#679](https://github.com/lovell/sharp/issues/679) diff --git a/docs/src/content/docs/changelog/v0.17.2.md b/docs/src/content/docs/changelog/v0.17.2.md new file mode 100644 index 000000000..02859307e --- /dev/null +++ b/docs/src/content/docs/changelog/v0.17.2.md @@ -0,0 +1,12 @@ +--- +title: v0.17.2 - 11th February 2017 +slug: changelog/v0.17.2 +--- + +* Ensure Readable side of Stream can start flowing after Writable side has finished. + [#671](https://github.com/lovell/sharp/issues/671) + [@danhaller](https://github.com/danhaller) + +* Expose WebP alpha quality, lossless and near-lossless output options. + [#685](https://github.com/lovell/sharp/pull/685) + [@rnanwani](https://github.com/rnanwani) diff --git a/docs/src/content/docs/changelog/v0.17.3.md b/docs/src/content/docs/changelog/v0.17.3.md new file mode 100644 index 000000000..0bc48d942 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.17.3.md @@ -0,0 +1,20 @@ +--- +title: v0.17.3 - 1st April 2017 +slug: changelog/v0.17.3 +--- + +* Allow toBuffer to optionally resolve a Promise with both info and data. + [#143](https://github.com/lovell/sharp/issues/143) + [@salzhrani](https://github.com/salzhrani) + +* Create blank image of given width, height, channels and background. + [#470](https://github.com/lovell/sharp/issues/470) + [@pjarts](https://github.com/pjarts) + +* Add support for the "nearest" kernel for image reductions. + [#732](https://github.com/lovell/sharp/pull/732) + [@alice0meta](https://github.com/alice0meta) + +* Add support for TIFF compression and predictor options. + [#738](https://github.com/lovell/sharp/pull/738) + [@kristojorg](https://github.com/kristojorg) diff --git a/docs/src/content/docs/changelog/v0.18.0.md b/docs/src/content/docs/changelog/v0.18.0.md new file mode 100644 index 000000000..d8afbdd04 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.18.0.md @@ -0,0 +1,60 @@ +--- +title: v0.18.0 - 30th May 2017 +slug: changelog/v0.18.0 +--- + +* Remove the previously-deprecated output format "option" functions: + quality, progressive, compressionLevel, withoutAdaptiveFiltering, + withoutChromaSubsampling, trellisQuantisation, trellisQuantization, + overshootDeringing, optimiseScans and optimizeScans. + +* Ensure maximum output dimensions are based on the format to be used. + [#176](https://github.com/lovell/sharp/issues/176) + [@stephanebachelier](https://github.com/stephanebachelier) + +* Avoid costly (un)premultiply when using overlayWith without alpha channel. + [#573](https://github.com/lovell/sharp/issues/573) + [@strarsis](https://github.com/strarsis) + +* Include pixel depth (e.g. "uchar") when reading metadata. + [#577](https://github.com/lovell/sharp/issues/577) + [@moedusa](https://github.com/moedusa) + +* Add support for Buffer and Stream-based TIFF output. + [#587](https://github.com/lovell/sharp/issues/587) + [@strarsis](https://github.com/strarsis) + +* Expose warnings from libvips via NODE_DEBUG=sharp environment variable. + [#607](https://github.com/lovell/sharp/issues/607) + [@puzrin](https://github.com/puzrin) + +* Switch to the libvips implementation of "attention" and "entropy" crop strategies. + [#727](https://github.com/lovell/sharp/issues/727) + +* Improve performance and accuracy of nearest neighbour integral upsampling. + [#752](https://github.com/lovell/sharp/issues/752) + [@MrIbby](https://github.com/MrIbby) + +* Constructor single argument API: allow plain object, reject null/undefined. + [#768](https://github.com/lovell/sharp/issues/768) + [@kub1x](https://github.com/kub1x) + +* Ensure ARM64 pre-built binaries use correct C++11 ABI version. + [#772](https://github.com/lovell/sharp/issues/772) + [@ajiratech2](https://github.com/ajiratech2) + +* Prevent aliasing by using dynamic values for shrink(-on-load). + [#781](https://github.com/lovell/sharp/issues/781) + [@kleisauke](https://github.com/kleisauke) + +* Expose libvips' "squash" parameter to enable 1-bit TIFF output. + [#783](https://github.com/lovell/sharp/pull/783) + [@YvesBos](https://github.com/YvesBos) + +* Add support for rotation using any multiple of +/-90 degrees. + [#791](https://github.com/lovell/sharp/pull/791) + [@ncoden](https://github.com/ncoden) + +* Add "jpg" alias to toFormat as shortened form of "jpeg". + [#814](https://github.com/lovell/sharp/pull/814) + [@jingsam](https://github.com/jingsam) diff --git a/docs/src/content/docs/changelog/v0.18.1.md b/docs/src/content/docs/changelog/v0.18.1.md new file mode 100644 index 000000000..3121a9cf3 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.18.1.md @@ -0,0 +1,8 @@ +--- +title: v0.18.1 - 30th May 2017 +slug: changelog/v0.18.1 +--- + +* Remove regression from #781 that could cause incorrect shrink calculation. + [#831](https://github.com/lovell/sharp/issues/831) + [@suprMax](https://github.com/suprMax) diff --git a/docs/src/content/docs/changelog/v0.18.2.md b/docs/src/content/docs/changelog/v0.18.2.md new file mode 100644 index 000000000..2eabf8374 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.18.2.md @@ -0,0 +1,19 @@ +--- +title: v0.18.2 - 1st July 2017 +slug: changelog/v0.18.2 +--- + +* Expose libvips' xres and yres properties for TIFF output. + [#828](https://github.com/lovell/sharp/pull/828) + [@YvesBos](https://github.com/YvesBos) + +* Ensure flip and flop operations work with auto-rotate. + [#837](https://github.com/lovell/sharp/issues/837) + [@rexxars](https://github.com/rexxars) + +* Allow binary download URL override via SHARP_DIST_BASE_URL env variable. + [#841](https://github.com/lovell/sharp/issues/841) + +* Add support for Solus Linux. + [#857](https://github.com/lovell/sharp/pull/857) + [@ekremkaraca](https://github.com/ekremkaraca) diff --git a/docs/src/content/docs/changelog/v0.18.3.md b/docs/src/content/docs/changelog/v0.18.3.md new file mode 100644 index 000000000..ea66e8112 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.18.3.md @@ -0,0 +1,12 @@ +--- +title: v0.18.3 - 13th September 2017 +slug: changelog/v0.18.3 +--- + +* Skip shrink-on-load when trimming. + [#888](https://github.com/lovell/sharp/pull/888) + [@kleisauke](https://github.com/kleisauke) + +* Migrate from got to simple-get for basic auth support. + [#945](https://github.com/lovell/sharp/pull/945) + [@pbomb](https://github.com/pbomb) diff --git a/docs/src/content/docs/changelog/v0.18.4.md b/docs/src/content/docs/changelog/v0.18.4.md new file mode 100644 index 000000000..002e06c26 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.18.4.md @@ -0,0 +1,8 @@ +--- +title: v0.18.4 - 18th September 2017 +slug: changelog/v0.18.4 +--- + +* Ensure input Buffer really is marked as Persistent, prevents mark-sweep GC. + [#950](https://github.com/lovell/sharp/issues/950) + [@lfdoherty](https://github.com/lfdoherty) diff --git a/docs/src/content/docs/changelog/v0.19.0.md b/docs/src/content/docs/changelog/v0.19.0.md new file mode 100644 index 000000000..d9ecfefcb --- /dev/null +++ b/docs/src/content/docs/changelog/v0.19.0.md @@ -0,0 +1,46 @@ +--- +title: v0.19.0 - 11th January 2018 +slug: changelog/v0.19.0 +--- + +* Expose offset coordinates of strategy-based crop. + [#868](https://github.com/lovell/sharp/issues/868) + [@mirohristov-com](https://github.com/mirohristov-com) + +* PNG output now defaults to adaptiveFiltering=false, compressionLevel=9 + [#872](https://github.com/lovell/sharp/issues/872) + [@wmertens](https://github.com/wmertens) + +* Add stats feature for pixel-derived image statistics. + [#915](https://github.com/lovell/sharp/pull/915) + [@rnanwani](https://github.com/rnanwani) + +* Add failOnError option to fail-fast on bad input image data. + [#976](https://github.com/lovell/sharp/pull/976) + [@mceachen](https://github.com/mceachen) + +* Resize: switch to libvips' implementation, make fastShrinkOnLoad optional, remove interpolator and centreSampling options. + [#977](https://github.com/lovell/sharp/pull/977) + [@jardakotesovec](https://github.com/jardakotesovec) + +* Attach finish event listener to a clone only for Stream-based input. + [#995](https://github.com/lovell/sharp/issues/995) + [@whmountains](https://github.com/whmountains) + +* Add tilecache before smartcrop to avoid over-computation of previous operations. + [#1028](https://github.com/lovell/sharp/issues/1028) + [@coffeebite](https://github.com/coffeebite) + +* Prevent toFile extension taking precedence over requested format. + [#1037](https://github.com/lovell/sharp/issues/1037) + [@tomgallagher](https://github.com/tomgallagher) + +* Add support for gravity option to existing embed feature. + [#1038](https://github.com/lovell/sharp/pull/1038) + [@AzureByte](https://github.com/AzureByte) + +* Expose IPTC and XMP metadata when available. + [#1079](https://github.com/lovell/sharp/pull/1079) + [@oaleynik](https://github.com/oaleynik) + +* TIFF output: switch default predictor from 'none' to 'horizontal' to match libvips' behaviour. diff --git a/docs/src/content/docs/changelog/v0.19.1.md b/docs/src/content/docs/changelog/v0.19.1.md new file mode 100644 index 000000000..deeea20d1 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.19.1.md @@ -0,0 +1,16 @@ +--- +title: v0.19.1 - 24th February 2018 +slug: changelog/v0.19.1 +--- + +* Expose libvips' linear transform feature. + [#1024](https://github.com/lovell/sharp/pull/1024) + [@3epnm](https://github.com/3epnm) + +* Expose angle option for tile-based output. + [#1121](https://github.com/lovell/sharp/pull/1121) + [@BiancoA](https://github.com/BiancoA) + +* Prevent crop operation when image already at or below target dimensions. + [#1134](https://github.com/lovell/sharp/issues/1134) + [@pieh](https://github.com/pieh) diff --git a/docs/src/content/docs/changelog/v0.20.0.md b/docs/src/content/docs/changelog/v0.20.0.md new file mode 100644 index 000000000..1f0bf56a2 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.20.0.md @@ -0,0 +1,7 @@ +--- +title: v0.20.0 - 5th March 2018 +slug: changelog/v0.20.0 +--- + +* Add support for prebuilt sharp binaries on common platforms. + [#186](https://github.com/lovell/sharp/issues/186) diff --git a/docs/src/content/docs/changelog/v0.20.1.md b/docs/src/content/docs/changelog/v0.20.1.md new file mode 100644 index 000000000..f4af4314c --- /dev/null +++ b/docs/src/content/docs/changelog/v0.20.1.md @@ -0,0 +1,15 @@ +--- +title: v0.20.1 - 17th March 2018 +slug: changelog/v0.20.1 +--- + +* Improve installation experience when a globally-installed libvips below the minimum required version is found. + [#1148](https://github.com/lovell/sharp/issues/1148) + +* Prevent smartcrop error when cumulative rounding is below target size. + [#1154](https://github.com/lovell/sharp/issues/1154) + [@ralrom](https://github.com/ralrom) + +* Expose libvips' median filter operation. + [#1161](https://github.com/lovell/sharp/pull/1161) + [@BiancoA](https://github.com/BiancoA) diff --git a/docs/src/content/docs/changelog/v0.20.2.md b/docs/src/content/docs/changelog/v0.20.2.md new file mode 100644 index 000000000..202d5c339 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.20.2.md @@ -0,0 +1,20 @@ +--- +title: v0.20.2 - 28th April 2018 +slug: changelog/v0.20.2 +--- + +* Add tint operation to set image chroma. + [#825](https://github.com/lovell/sharp/pull/825) + [@rikh42](https://github.com/rikh42) + +* Add environment variable to ignore globally-installed libvips. + [#1165](https://github.com/lovell/sharp/pull/1165) + [@oncletom](https://github.com/oncletom) + +* Add support for page selection with multi-page input (GIF/TIFF). + [#1204](https://github.com/lovell/sharp/pull/1204) + [@woolite64](https://github.com/woolite64) + +* Add support for Group4 (CCITTFAX4) compression with TIFF output. + [#1208](https://github.com/lovell/sharp/pull/1208) + [@woolite64](https://github.com/woolite64) diff --git a/docs/src/content/docs/changelog/v0.20.3.md b/docs/src/content/docs/changelog/v0.20.3.md new file mode 100644 index 000000000..b00c64910 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.20.3.md @@ -0,0 +1,8 @@ +--- +title: v0.20.3 - 29th May 2018 +slug: changelog/v0.20.3 +--- + +* Fix tint operation by ensuring LAB interpretation and allowing negative values. + [#1235](https://github.com/lovell/sharp/issues/1235) + [@wezside](https://github.com/wezside) diff --git a/docs/src/content/docs/changelog/v0.20.4.md b/docs/src/content/docs/changelog/v0.20.4.md new file mode 100644 index 000000000..a9580dea3 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.20.4.md @@ -0,0 +1,12 @@ +--- +title: v0.20.4 - 20th June 2018 +slug: changelog/v0.20.4 +--- + +* Prevent possible rounding error when using shrink-on-load and 90/270 degree rotation. + [#1241](https://github.com/lovell/sharp/issues/1241) + [@anahit42](https://github.com/anahit42) + +* Ensure extractChannel sets correct single-channel colour space interpretation. + [#1257](https://github.com/lovell/sharp/issues/1257) + [@jeremychone](https://github.com/jeremychone) diff --git a/docs/src/content/docs/changelog/v0.20.5.md b/docs/src/content/docs/changelog/v0.20.5.md new file mode 100644 index 000000000..07f166149 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.20.5.md @@ -0,0 +1,8 @@ +--- +title: v0.20.5 - 27th June 2018 +slug: changelog/v0.20.5 +--- + +* Expose libjpeg optimize_coding flag. + [#1265](https://github.com/lovell/sharp/pull/1265) + [@tomlokhorst](https://github.com/tomlokhorst) diff --git a/docs/src/content/docs/changelog/v0.20.6.md b/docs/src/content/docs/changelog/v0.20.6.md new file mode 100644 index 000000000..284a67a27 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.20.6.md @@ -0,0 +1,33 @@ +--- +title: v0.20.6 - 20th August 2018 +slug: changelog/v0.20.6 +--- + +* Add removeAlpha operation to remove alpha channel, if any. + [#1248](https://github.com/lovell/sharp/issues/1248) + +* Expose mozjpeg quant_table flag. + [#1285](https://github.com/lovell/sharp/pull/1285) + [@rexxars](https://github.com/rexxars) + +* Allow full WebP alphaQuality range of 0-100. + [#1290](https://github.com/lovell/sharp/pull/1290) + [@sylvaindumont](https://github.com/sylvaindumont) + +* Cache libvips binaries to reduce re-install time. + [#1301](https://github.com/lovell/sharp/issues/1301) + +* Ensure vendor platform mismatch throws error at install time. + [#1303](https://github.com/lovell/sharp/issues/1303) + +* Improve install time error messages for FreeBSD users. + [#1310](https://github.com/lovell/sharp/issues/1310) + +* Ensure extractChannel works with 16-bit images. + [#1330](https://github.com/lovell/sharp/issues/1330) + +* Expose depth option for tile-based output. + [#1342](https://github.com/lovell/sharp/pull/1342) + [@alundavies](https://github.com/alundavies) + +* Add experimental entropy field to stats response. diff --git a/docs/src/content/docs/changelog/v0.20.7.md b/docs/src/content/docs/changelog/v0.20.7.md new file mode 100644 index 000000000..e9503a29d --- /dev/null +++ b/docs/src/content/docs/changelog/v0.20.7.md @@ -0,0 +1,7 @@ +--- +title: v0.20.7 - 21st August 2018 +slug: changelog/v0.20.7 +--- + +* Use copy+unlink if rename operation fails during installation. + [#1345](https://github.com/lovell/sharp/issues/1345) diff --git a/docs/src/content/docs/changelog/v0.20.8.md b/docs/src/content/docs/changelog/v0.20.8.md new file mode 100644 index 000000000..8ab9a062a --- /dev/null +++ b/docs/src/content/docs/changelog/v0.20.8.md @@ -0,0 +1,12 @@ +--- +title: v0.20.8 - 5th September 2018 +slug: changelog/v0.20.8 +--- + +* Avoid race conditions when creating directories during installation. + [#1358](https://github.com/lovell/sharp/pull/1358) + [@ajhool](https://github.com/ajhool) + +* Accept floating point values for input density parameter. + [#1362](https://github.com/lovell/sharp/pull/1362) + [@aeirola](https://github.com/aeirola) diff --git a/docs/src/content/docs/changelog/v0.21.0.md b/docs/src/content/docs/changelog/v0.21.0.md new file mode 100644 index 000000000..762cc65a4 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.21.0.md @@ -0,0 +1,39 @@ +--- +title: v0.21.0 - 4th October 2018 +slug: changelog/v0.21.0 +--- + +* Deprecate the following resize-related functions: + `crop`, `embed`, `ignoreAspectRatio`, `max`, `min` and `withoutEnlargement`. + Access to these is now via options passed to the `resize` function. + For example: + `embed('north')` is now `resize(width, height, { fit: 'contain', position: 'north' })`, + `crop('attention')` is now `resize(width, height, { fit: 'cover', position: 'attention' })`, + `max().withoutEnlargement()` is now `resize(width, height, { fit: 'inside', withoutEnlargement: true })`. + [#1135](https://github.com/lovell/sharp/issues/1135) + +* Deprecate the `background` function. + Per-operation `background` options added to `resize`, `extend` and `flatten` operations. + [#1392](https://github.com/lovell/sharp/issues/1392) + +* Add `size` to `metadata` response (Stream and Buffer input only). + [#695](https://github.com/lovell/sharp/issues/695) + +* Switch from custom trim operation to `vips_find_trim`. + [#914](https://github.com/lovell/sharp/issues/914) + +* Add `chromaSubsampling` and `isProgressive` properties to `metadata` response. + [#1186](https://github.com/lovell/sharp/issues/1186) + +* Drop Node 4 support. + [#1212](https://github.com/lovell/sharp/issues/1212) + +* Enable SIMD convolution by default. + [#1213](https://github.com/lovell/sharp/issues/1213) + +* Add experimental prebuilt binaries for musl-based Linux. + [#1379](https://github.com/lovell/sharp/issues/1379) + +* Add support for arbitrary rotation angle via vips_rotate. + [#1385](https://github.com/lovell/sharp/pull/1385) + [@freezy](https://github.com/freezy) diff --git a/docs/src/content/docs/changelog/v0.21.1.md b/docs/src/content/docs/changelog/v0.21.1.md new file mode 100644 index 000000000..bb685ef2b --- /dev/null +++ b/docs/src/content/docs/changelog/v0.21.1.md @@ -0,0 +1,31 @@ +--- +title: v0.21.1 - 7th December 2018 +slug: changelog/v0.21.1 +--- + +* Install: support `sharp_dist_base_url` npm config, like existing `SHARP_DIST_BASE_URL`. + [#1422](https://github.com/lovell/sharp/pull/1422) + [@SethWen](https://github.com/SethWen) + +* Ensure `channel` metadata is correct for raw, greyscale output. + [#1425](https://github.com/lovell/sharp/issues/1425) + +* Add support for the "mitchell" kernel for image reductions. + [#1438](https://github.com/lovell/sharp/pull/1438) + [@Daiz](https://github.com/Daiz) + +* Allow separate parameters for gamma encoding and decoding. + [#1439](https://github.com/lovell/sharp/pull/1439) + [@Daiz](https://github.com/Daiz) + +* Build prototype with `Object.assign` to allow minification. + [#1475](https://github.com/lovell/sharp/pull/1475) + [@jaubourg](https://github.com/jaubourg) + +* Expose libvips' recombination matrix operation. + [#1477](https://github.com/lovell/sharp/pull/1477) + [@fromkeith](https://github.com/fromkeith) + +* Expose libvips' pyramid/tile options for TIFF output. + [#1483](https://github.com/lovell/sharp/pull/1483) + [@mbklein](https://github.com/mbklein) diff --git a/docs/src/content/docs/changelog/v0.21.2.md b/docs/src/content/docs/changelog/v0.21.2.md new file mode 100644 index 000000000..be7f6758d --- /dev/null +++ b/docs/src/content/docs/changelog/v0.21.2.md @@ -0,0 +1,27 @@ +--- +title: v0.21.2 - 13th January 2019 +slug: changelog/v0.21.2 +--- + +* Ensure all metadata is removed from PNG output unless `withMetadata` used. + +* Ensure shortest edge is at least one pixel after resizing. + [#1003](https://github.com/lovell/sharp/issues/1003) + +* Add `ensureAlpha` operation to add an alpha channel, if missing. + [#1153](https://github.com/lovell/sharp/issues/1153) + +* Expose `pages` and `pageHeight` metadata for multi-page input images. + [#1205](https://github.com/lovell/sharp/issues/1205) + +* Expose PNG output options requiring libimagequant. + [#1484](https://github.com/lovell/sharp/issues/1484) + +* Expose underlying error message for invalid input. + [#1505](https://github.com/lovell/sharp/issues/1505) + +* Prevent mutatation of options passed to `jpeg`. + [#1516](https://github.com/lovell/sharp/issues/1516) + +* Ensure forced output format applied correctly when output chaining. + [#1528](https://github.com/lovell/sharp/issues/1528) diff --git a/docs/src/content/docs/changelog/v0.21.3.md b/docs/src/content/docs/changelog/v0.21.3.md new file mode 100644 index 000000000..1cde28c63 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.21.3.md @@ -0,0 +1,9 @@ +--- +title: v0.21.3 - 19th January 2019 +slug: changelog/v0.21.3 +--- + +* Input image decoding now fails fast, set `failOnError` to change this behaviour. + +* Failed filesystem-based input now separates missing file and invalid format errors. + [#1542](https://github.com/lovell/sharp/issues/1542) diff --git a/docs/src/content/docs/changelog/v0.22.0.md b/docs/src/content/docs/changelog/v0.22.0.md new file mode 100644 index 000000000..797c743bc --- /dev/null +++ b/docs/src/content/docs/changelog/v0.22.0.md @@ -0,0 +1,20 @@ +--- +title: v0.22.0 - 18th March 2019 +slug: changelog/v0.22.0 +--- + +* Remove functions previously deprecated in v0.21.0: + `background`, `crop`, `embed`, `ignoreAspectRatio`, `max`, `min` and `withoutEnlargement`. + +* Add `composite` operation supporting multiple images and blend modes; deprecate `overlayWith`. + [#728](https://github.com/lovell/sharp/issues/728) + +* Add support for `pages` input option for multi-page input. + [#1566](https://github.com/lovell/sharp/issues/1566) + +* Allow Stream-based input of raw pixel data. + [#1579](https://github.com/lovell/sharp/issues/1579) + +* Add support for `page` input option to GIF and PDF. + [#1595](https://github.com/lovell/sharp/pull/1595) + [@ramiel](https://github.com/ramiel) diff --git a/docs/src/content/docs/changelog/v0.22.1.md b/docs/src/content/docs/changelog/v0.22.1.md new file mode 100644 index 000000000..cf8e3d464 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.22.1.md @@ -0,0 +1,15 @@ +--- +title: v0.22.1 - 25th April 2019 +slug: changelog/v0.22.1 +--- + +* Add `modulate` operation for brightness, saturation and hue. + [#1601](https://github.com/lovell/sharp/pull/1601) + [@Goues](https://github.com/Goues) + +* Improve help messaging should `require("sharp")` fail. + [#1638](https://github.com/lovell/sharp/pull/1638) + [@sidharthachatterjee](https://github.com/sidharthachatterjee) + +* Add support for Node 12. + [#1668](https://github.com/lovell/sharp/issues/1668) diff --git a/docs/src/content/docs/changelog/v0.23.0.md b/docs/src/content/docs/changelog/v0.23.0.md new file mode 100644 index 000000000..24b18827c --- /dev/null +++ b/docs/src/content/docs/changelog/v0.23.0.md @@ -0,0 +1,32 @@ +--- +title: v0.23.0 - 29th July 2019 +slug: changelog/v0.23.0 +--- + +* Remove `overlayWith` previously deprecated in v0.22.0. + +* Add experimental support for HEIF images. Requires libvips compiled with libheif. + [#1105](https://github.com/lovell/sharp/issues/1105) + +* Expose libwebp `smartSubsample` and `reductionEffort` options. + [#1545](https://github.com/lovell/sharp/issues/1545) + +* Add experimental support for Worker Threads. + [#1558](https://github.com/lovell/sharp/issues/1558) + +* Use libvips' built-in CMYK and sRGB profiles when required. + [#1619](https://github.com/lovell/sharp/issues/1619) + +* Drop support for Node.js versions 6 and 11. + [#1674](https://github.com/lovell/sharp/issues/1674) + +* Expose `skipBlanks` option for tile-based output. + [#1687](https://github.com/lovell/sharp/pull/1687) + [@RaboliotTheGrey](https://github.com/RaboliotTheGrey) + +* Allow use of `failOnError` option with Stream-based input. + [#1691](https://github.com/lovell/sharp/issues/1691) + +* Fix rotate/extract ordering for non-90 angles. + [#1755](https://github.com/lovell/sharp/pull/1755) + [@iovdin](https://github.com/iovdin) diff --git a/docs/src/content/docs/changelog/v0.23.1.md b/docs/src/content/docs/changelog/v0.23.1.md new file mode 100644 index 000000000..c180d9952 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.23.1.md @@ -0,0 +1,24 @@ +--- +title: v0.23.1 - 26th September 2019 +slug: changelog/v0.23.1 +--- + +* Ensure `sharp.format.vips` is present and correct (filesystem only). + [#1813](https://github.com/lovell/sharp/issues/1813) + +* Ensure invalid `width` and `height` provided as options to `resize` throw. + [#1817](https://github.com/lovell/sharp/issues/1817) + +* Allow use of 'heic' and 'heif' identifiers with `toFormat`. + [#1834](https://github.com/lovell/sharp/pull/1834) + [@jaubourg](https://github.com/jaubourg) + +* Add `premultiplied` option to `composite` operation. + [#1835](https://github.com/lovell/sharp/pull/1835) + [@Andargor](https://github.com/Andargor) + +* Allow instance reuse with differing `toBuffer` options. + [#1860](https://github.com/lovell/sharp/pull/1860) + [@RaboliotTheGrey](https://github.com/RaboliotTheGrey) + +* Ensure image is at least 3x3 pixels before attempting trim operation. diff --git a/docs/src/content/docs/changelog/v0.23.2.md b/docs/src/content/docs/changelog/v0.23.2.md new file mode 100644 index 000000000..1eb59491d --- /dev/null +++ b/docs/src/content/docs/changelog/v0.23.2.md @@ -0,0 +1,12 @@ +--- +title: v0.23.2 - 28th October 2019 +slug: changelog/v0.23.2 +--- + +* Add `background` option to tile output operation. + [#1924](https://github.com/lovell/sharp/pull/1924) + [@neave](https://github.com/neave) + +* Add support for Node.js 13. + [#1932](https://github.com/lovell/sharp/pull/1932) + [@MayhemYDG](https://github.com/MayhemYDG) diff --git a/docs/src/content/docs/changelog/v0.23.3.md b/docs/src/content/docs/changelog/v0.23.3.md new file mode 100644 index 000000000..4c19795a5 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.23.3.md @@ -0,0 +1,18 @@ +--- +title: v0.23.3 - 17th November 2019 +slug: changelog/v0.23.3 +--- + +* Ensure `trim` operation supports images contained in the alpha channel. + [#1597](https://github.com/lovell/sharp/issues/1597) + +* Ensure tile `overlap` option works as expected. + [#1921](https://github.com/lovell/sharp/pull/1921) + [@rustyguts](https://github.com/rustyguts) + +* Allow compilation on FreeBSD and variants (broken since v0.23.0) + [#1952](https://github.com/lovell/sharp/pull/1952) + [@pouya-eghbali](https://github.com/pouya-eghbali) + +* Ensure `modulate` and other colour-based operations can co-exist. + [#1958](https://github.com/lovell/sharp/issues/1958) diff --git a/docs/src/content/docs/changelog/v0.23.4.md b/docs/src/content/docs/changelog/v0.23.4.md new file mode 100644 index 000000000..3d8bfed73 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.23.4.md @@ -0,0 +1,12 @@ +--- +title: v0.23.4 - 5th December 2019 +slug: changelog/v0.23.4 +--- + +* Handle zero-length Buffer objects when using Node.js v13.2.0+. + +* Expose raw TIFFTAG_PHOTOSHOP metadata. + [#1600](https://github.com/lovell/sharp/issues/1600) + +* Improve thread safety by using copy-on-write when updating metadata. + [#1986](https://github.com/lovell/sharp/issues/1986) diff --git a/docs/src/content/docs/changelog/v0.24.0.md b/docs/src/content/docs/changelog/v0.24.0.md new file mode 100644 index 000000000..378dad771 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.24.0.md @@ -0,0 +1,28 @@ +--- +title: v0.24.0 - 16th January 2020 +slug: changelog/v0.24.0 +--- + +* Drop support for Node.js 8. + [#1910](https://github.com/lovell/sharp/issues/1910) + +* Drop support for undefined input where options also provided. + [#1768](https://github.com/lovell/sharp/issues/1768) + +* Move `limitInputPixels` and `sequentialRead` to input options, deprecating functions of the same name. + +* Expose `delay` and `loop` metadata for animated images. + [#1905](https://github.com/lovell/sharp/issues/1905) + +* Ensure correct colour output for 16-bit, 2-channel PNG input with ICC profile. + [#2013](https://github.com/lovell/sharp/issues/2013) + +* Prevent use of sequentialRead for rotate operations. + [#2016](https://github.com/lovell/sharp/issues/2016) + +* Correctly bind max width and height values when using withoutEnlargement. + [#2024](https://github.com/lovell/sharp/pull/2024) + [@BrychanOdlum](https://github.com/BrychanOdlum) + +* Add support for input with 16-bit RGB profile. + [#2037](https://github.com/lovell/sharp/issues/2037) diff --git a/docs/src/content/docs/changelog/v0.24.1.md b/docs/src/content/docs/changelog/v0.24.1.md new file mode 100644 index 000000000..2155c2005 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.24.1.md @@ -0,0 +1,10 @@ +--- +title: v0.24.1 - 15th February 2020 +slug: changelog/v0.24.1 +--- + +* Prevent use of sequentialRead for EXIF-based rotate operation. + [#2042](https://github.com/lovell/sharp/issues/2042) + +* Ensure RGBA LZW TIFF returns correct channel count. + [#2064](https://github.com/lovell/sharp/issues/2064) diff --git a/docs/src/content/docs/changelog/v0.25.0.md b/docs/src/content/docs/changelog/v0.25.0.md new file mode 100644 index 000000000..b42978a98 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.25.0.md @@ -0,0 +1,18 @@ +--- +title: v0.25.0 - 7th March 2020 +slug: changelog/v0.25.0 +--- + +* Remove `limitInputPixels` and `sequentialRead` previously deprecated in v0.24.0. + +* Migrate internals to N-API. + [#1282](https://github.com/lovell/sharp/issues/1282) + +* Add support for 32-bit Windows. + [#2088](https://github.com/lovell/sharp/issues/2088) + +* Ensure correct ordering of rotate-then-trim operations. + [#2087](https://github.com/lovell/sharp/issues/2087) + +* Ensure composite accepts `limitInputPixels` and `sequentialRead` input options. + [#2099](https://github.com/lovell/sharp/issues/2099) diff --git a/docs/src/content/docs/changelog/v0.25.1.md b/docs/src/content/docs/changelog/v0.25.1.md new file mode 100644 index 000000000..af0fe39d4 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.25.1.md @@ -0,0 +1,7 @@ +--- +title: v0.25.1 - 7th March 2020 +slug: changelog/v0.25.1 +--- + +* Ensure prebuilt binaries are fetched based on N-API version. + [#2117](https://github.com/lovell/sharp/issues/2117) diff --git a/docs/src/content/docs/changelog/v0.25.2.md b/docs/src/content/docs/changelog/v0.25.2.md new file mode 100644 index 000000000..298db561a --- /dev/null +++ b/docs/src/content/docs/changelog/v0.25.2.md @@ -0,0 +1,19 @@ +--- +title: v0.25.2 - 20th March 2020 +slug: changelog/v0.25.2 +--- + +* Provide prebuilt binaries for Linux ARM64v8. + +* Add IIIF layout support to tile-based output. + [#2098](https://github.com/lovell/sharp/pull/2098) + [@edsilv](https://github.com/edsilv) + +* Ensure input options are consistently and correctly detected. + [#2118](https://github.com/lovell/sharp/issues/2118) + +* Ensure N-API prebuilt binaries work on RHEL7 and its derivatives. + [#2119](https://github.com/lovell/sharp/issues/2119) + +* Ensure AsyncWorker options are persisted. + [#2130](https://github.com/lovell/sharp/issues/2130) diff --git a/docs/src/content/docs/changelog/v0.25.3.md b/docs/src/content/docs/changelog/v0.25.3.md new file mode 100644 index 000000000..0a1a76038 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.25.3.md @@ -0,0 +1,14 @@ +--- +title: v0.25.3 - 17th May 2020 +slug: changelog/v0.25.3 +--- + +* Ensure libvips is initialised only once, improves worker thread safety. + [#2143](https://github.com/lovell/sharp/issues/2143) + +* Ensure npm platform flag is respected when copying DLLs. + [#2188](https://github.com/lovell/sharp/pull/2188) + [@dimadeveatii](https://github.com/dimadeveatii) + +* Allow SVG input with large inline images to be parsed. + [#2195](https://github.com/lovell/sharp/issues/2195) diff --git a/docs/src/content/docs/changelog/v0.25.4.md b/docs/src/content/docs/changelog/v0.25.4.md new file mode 100644 index 000000000..6bd4deb59 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.25.4.md @@ -0,0 +1,25 @@ +--- +title: v0.25.4 - 12th June 2020 +slug: changelog/v0.25.4 +--- + +* Allow libvips binary location override where version is appended. + [#2217](https://github.com/lovell/sharp/pull/2217) + [@malice00](https://github.com/malice00) + +* Enable PNG palette when setting quality, colours, colors or dither. + [#2226](https://github.com/lovell/sharp/pull/2226) + [@romaleev](https://github.com/romaleev) + +* Add `level` constructor option to use a specific level of a multi-level image. + Expose `levels` metadata for multi-level images. + [#2222](https://github.com/lovell/sharp/issues/2222) + +* Add support for named `alpha` channel to `extractChannel` operation. + [#2138](https://github.com/lovell/sharp/issues/2138) + +* Add experimental `sharpness` calculation to `stats()` response. + [#2251](https://github.com/lovell/sharp/issues/2251) + +* Emit `warning` event for non-critical processing problems. + [#2032](https://github.com/lovell/sharp/issues/2032) diff --git a/docs/src/content/docs/changelog/v0.26.0.md b/docs/src/content/docs/changelog/v0.26.0.md new file mode 100644 index 000000000..6fedd7e35 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.26.0.md @@ -0,0 +1,33 @@ +--- +title: v0.26.0 - 25th August 2020 +slug: changelog/v0.26.0 +--- + +* Prebuilt libvips binaries are now statically-linked and Brotli-compressed, requiring Node.js 10.16.0+. + +* TIFF output `squash` is replaced by `bitdepth` to reduce to 1, 2 or 4 bit. + +* JPEG output `quality` >= 90 no longer automatically sets `chromaSubsampling` to `4:4:4`. + +* Add most `dominant` colour to image `stats`. + [#640](https://github.com/lovell/sharp/issues/640) + +* Add support for animated GIF (requires \*magick) and WebP output. + [#2012](https://github.com/lovell/sharp/pull/2012) + [@deftomat](https://github.com/deftomat) + +* Add support for libvips ImageMagick v7 loaders. + [#2258](https://github.com/lovell/sharp/pull/2258) + [@vouillon](https://github.com/vouillon) + +* Allow multi-page input via \*magick. + [#2259](https://github.com/lovell/sharp/pull/2259) + [@vouillon](https://github.com/vouillon) + +* Add support to `withMetadata` for custom ICC profile. + [#2271](https://github.com/lovell/sharp/pull/2271) + [@roborourke](https://github.com/roborourke) + +* Ensure prebuilt binaries for ARM default to v7 when using Electron. + [#2292](https://github.com/lovell/sharp/pull/2292) + [@diegodev3](https://github.com/diegodev3) diff --git a/docs/src/content/docs/changelog/v0.26.1.md b/docs/src/content/docs/changelog/v0.26.1.md new file mode 100644 index 000000000..080b05da3 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.26.1.md @@ -0,0 +1,22 @@ +--- +title: v0.26.1 - 20th September 2020 +slug: changelog/v0.26.1 +--- + +* Ensure correct pageHeight when verifying multi-page image dimensions. + [#2343](https://github.com/lovell/sharp/pull/2343) + [@derom](https://github.com/derom) + +* Allow input density range up to 100000 DPI. + [#2348](https://github.com/lovell/sharp/pull/2348) + [@stefanprobst](https://github.com/stefanprobst) + +* Ensure animation-related properties can be set for Stream-based input. + [#2369](https://github.com/lovell/sharp/pull/2369) + [@AcrylicShrimp](https://github.com/AcrylicShrimp) + +* Ensure `stats` can be calculated for 1x1 input. + [#2372](https://github.com/lovell/sharp/issues/2372) + +* Ensure animated GIF output is optimised. + [#2376](https://github.com/lovell/sharp/issues/2376) diff --git a/docs/src/content/docs/changelog/v0.26.2.md b/docs/src/content/docs/changelog/v0.26.2.md new file mode 100644 index 000000000..2031300a2 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.26.2.md @@ -0,0 +1,15 @@ +--- +title: v0.26.2 - 14th October 2020 +slug: changelog/v0.26.2 +--- + +* Add support for EXR input. Requires libvips compiled with OpenEXR. + [#698](https://github.com/lovell/sharp/issues/698) + +* Ensure support for yarn v2. + [#2379](https://github.com/lovell/sharp/pull/2379) + [@jalovatt](https://github.com/jalovatt) + +* Add centre/center option to tile-based output. + [#2397](https://github.com/lovell/sharp/pull/2397) + [@beig](https://github.com/beig) diff --git a/docs/src/content/docs/changelog/v0.26.3.md b/docs/src/content/docs/changelog/v0.26.3.md new file mode 100644 index 000000000..a12a54480 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.26.3.md @@ -0,0 +1,12 @@ +--- +title: v0.26.3 - 16th November 2020 +slug: changelog/v0.26.3 +--- + +* Expose libvips' affine operation. + [#2336](https://github.com/lovell/sharp/pull/2336) + [@guillevc](https://github.com/guillevc) + +* Fallback to tar.gz for prebuilt libvips when Brotli not available. + [#2412](https://github.com/lovell/sharp/pull/2412) + [@ascorbic](https://github.com/ascorbic) diff --git a/docs/src/content/docs/changelog/v0.27.0.md b/docs/src/content/docs/changelog/v0.27.0.md new file mode 100644 index 000000000..d21378479 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.27.0.md @@ -0,0 +1,15 @@ +--- +title: v0.27.0 - 22nd December 2020 +slug: changelog/v0.27.0 +--- + +* Add support for AVIF to prebuilt binaries. + +* Remove experimental status from `heif` output, defaults are now AVIF-centric. + +* Allow negative top/left offsets for composite operation. + [#2391](https://github.com/lovell/sharp/pull/2391) + [@CurosMJ](https://github.com/CurosMJ) + +* Ensure all platforms use fontconfig for font rendering. + [#2399](https://github.com/lovell/sharp/issues/2399) diff --git a/docs/src/content/docs/changelog/v0.27.1.md b/docs/src/content/docs/changelog/v0.27.1.md new file mode 100644 index 000000000..09b24da60 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.27.1.md @@ -0,0 +1,19 @@ +--- +title: v0.27.1 - 27th January 2021 +slug: changelog/v0.27.1 +--- + +* Ensure TIFF is cast when using float predictor. + [#2502](https://github.com/lovell/sharp/pull/2502) + [@randyridge](https://github.com/randyridge) + +* Add support for Uint8Array and Uint8ClampedArray input. + [#2511](https://github.com/lovell/sharp/pull/2511) + [@leon](https://github.com/leon) + +* Revert: ensure all platforms use fontconfig for font rendering. + [#2515](https://github.com/lovell/sharp/issues/2515) + +* Expose libvips gaussnoise operation to allow creation of Gaussian noise. + [#2527](https://github.com/lovell/sharp/pull/2527) + [@alza54](https://github.com/alza54) diff --git a/docs/src/content/docs/changelog/v0.27.2.md b/docs/src/content/docs/changelog/v0.27.2.md new file mode 100644 index 000000000..b8eb9c386 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.27.2.md @@ -0,0 +1,20 @@ +--- +title: v0.27.2 - 22nd February 2021 +slug: changelog/v0.27.2 +--- + +* macOS: Prevent use of globally-installed ARM64 libvips with Rosetta x64 emulation. + [#2460](https://github.com/lovell/sharp/issues/2460) + +* Linux (musl): Prevent use of prebuilt linuxmusl-x64 binaries with musl >= 1.2.0. + [#2570](https://github.com/lovell/sharp/issues/2570) + +* Improve 16-bit grey+alpha support by using libvips' `has_alpha` detection. + [#2569](https://github.com/lovell/sharp/issues/2569) + +* Allow the use of non lower case extensions with `toFormat`. + [#2581](https://github.com/lovell/sharp/pull/2581) + [@florian-busch](https://github.com/florian-busch) + +* Allow use of `recomb` operation with single channel input. + [#2584](https://github.com/lovell/sharp/issues/2584) diff --git a/docs/src/content/docs/changelog/v0.28.0.md b/docs/src/content/docs/changelog/v0.28.0.md new file mode 100644 index 000000000..e3a72f815 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.28.0.md @@ -0,0 +1,32 @@ +--- +title: v0.28.0 - 29th March 2021 +slug: changelog/v0.28.0 +--- + +* Prebuilt binaries now include mozjpeg and libimagequant (BSD 2-Clause). + +* Prebuilt binaries limit AVIF support to the most common 8-bit depth. + +* Add `mozjpeg` option to `jpeg` method, sets mozjpeg defaults. + +* Reduce the default PNG `compressionLevel` to the more commonly used 6. + +* Reduce concurrency on glibc-based Linux when using the default memory allocator to help prevent fragmentation. + +* Default missing edge properties of extend operation to zero. + [#2578](https://github.com/lovell/sharp/issues/2578) + +* Ensure composite does not clip top and left offsets. + [#2594](https://github.com/lovell/sharp/pull/2594) + [@SHG42](https://github.com/SHG42) + +* Improve error handling of network failure at install time. + [#2608](https://github.com/lovell/sharp/pull/2608) + [@abradley](https://github.com/abradley) + +* Ensure `@id` attribute can be set for IIIF tile-based output. + [#2612](https://github.com/lovell/sharp/issues/2612) + [@edsilv](https://github.com/edsilv) + +* Ensure composite replicates the correct number of tiles for centred gravities. + [#2626](https://github.com/lovell/sharp/issues/2626) diff --git a/docs/src/content/docs/changelog/v0.28.1.md b/docs/src/content/docs/changelog/v0.28.1.md new file mode 100644 index 000000000..38e11a38a --- /dev/null +++ b/docs/src/content/docs/changelog/v0.28.1.md @@ -0,0 +1,15 @@ +--- +title: v0.28.1 - 5th April 2021 +slug: changelog/v0.28.1 +--- + +* Ensure all installation errors are logged with a more obvious prefix. + +* Allow `withMetadata` to set and update EXIF metadata. + [#650](https://github.com/lovell/sharp/issues/650) + +* Add support for OME-TIFF Sub Image File Directories (subIFD). + [#2557](https://github.com/lovell/sharp/issues/2557) + +* Allow `ensureAlpha` to set the alpha transparency level. + [#2634](https://github.com/lovell/sharp/issues/2634) diff --git a/docs/src/content/docs/changelog/v0.28.2.md b/docs/src/content/docs/changelog/v0.28.2.md new file mode 100644 index 000000000..9f067c44f --- /dev/null +++ b/docs/src/content/docs/changelog/v0.28.2.md @@ -0,0 +1,26 @@ +--- +title: v0.28.2 - 10th May 2021 +slug: changelog/v0.28.2 +--- + +* Allow `withMetadata` to set `density`. + [#967](https://github.com/lovell/sharp/issues/967) + +* Skip shrink-on-load where one dimension <4px. + [#2653](https://github.com/lovell/sharp/issues/2653) + +* Allow escaped proxy credentials. + [#2664](https://github.com/lovell/sharp/pull/2664) + [@msalettes](https://github.com/msalettes) + +* Add `premultiplied` flag for raw pixel data input. + [#2685](https://github.com/lovell/sharp/pull/2685) + [@mnutt](https://github.com/mnutt) + +* Detect empty input and throw a helpful error. + [#2687](https://github.com/lovell/sharp/pull/2687) + [@JakobJingleheimer](https://github.com/JakobJingleheimer) + +* Add install-time flag to skip version compatibility checks. + [#2692](https://github.com/lovell/sharp/pull/2692) + [@xemle](https://github.com/xemle) diff --git a/docs/src/content/docs/changelog/v0.28.3.md b/docs/src/content/docs/changelog/v0.28.3.md new file mode 100644 index 000000000..dff933269 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.28.3.md @@ -0,0 +1,13 @@ +--- +title: v0.28.3 - 24th May 2021 +slug: changelog/v0.28.3 +--- + +* Ensure presence of libvips, vendored or global, before invoking node-gyp. + +* Skip shrink-on-load for multi-page WebP. + [#2714](https://github.com/lovell/sharp/issues/2714) + +* Add contrast limiting adaptive histogram equalization (CLAHE) operator. + [#2726](https://github.com/lovell/sharp/pull/2726) + [@baparham](https://github.com/baparham) diff --git a/docs/src/content/docs/changelog/v0.29.0.md b/docs/src/content/docs/changelog/v0.29.0.md new file mode 100644 index 000000000..087545991 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.29.0.md @@ -0,0 +1,35 @@ +--- +title: v0.29.0 - 17th August 2021 +slug: changelog/v0.29.0 +--- + +* Drop support for Node.js 10, now requires Node.js >= 12.13.0. + +* Add `background` property to PNG and GIF image metadata. + +* Add `compression` property to HEIF image metadata. + [#2504](https://github.com/lovell/sharp/issues/2504) + +* AVIF encoding now defaults to `4:4:4` chroma subsampling. + [#2562](https://github.com/lovell/sharp/issues/2562) + +* Allow multiple platform-arch binaries in same `node_modules` installation tree. + [#2575](https://github.com/lovell/sharp/issues/2575) + +* Default to single-channel `b-w` space when `extractChannel` is used. + [#2658](https://github.com/lovell/sharp/issues/2658) + +* Allow installation directory to contain spaces (regression in v0.26.0). + [#2777](https://github.com/lovell/sharp/issues/2777) + +* Add `pipelineColourspace` operator to set the processing space. + [#2704](https://github.com/lovell/sharp/pull/2704) + [@Daiz](https://github.com/Daiz) + +* Allow bit depth to be set when using raw input and output. + [#2762](https://github.com/lovell/sharp/pull/2762) + [@mart-jansink](https://github.com/mart-jansink) + +* Allow `negate` to act only on non-alpha channels. + [#2808](https://github.com/lovell/sharp/pull/2808) + [@rexxars](https://github.com/rexxars) diff --git a/docs/src/content/docs/changelog/v0.29.1.md b/docs/src/content/docs/changelog/v0.29.1.md new file mode 100644 index 000000000..58809cbf4 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.29.1.md @@ -0,0 +1,30 @@ +--- +title: v0.29.1 - 7th September 2021 +slug: changelog/v0.29.1 +--- + +* Add `lightness` option to `modulate` operation. + [#2846](https://github.com/lovell/sharp/pull/2846) + +* Ensure correct PNG bitdepth is set based on number of colours. + [#2855](https://github.com/lovell/sharp/issues/2855) + +* Ensure background is always premultiplied when compositing. + [#2858](https://github.com/lovell/sharp/issues/2858) + +* Ensure images with P3 profiles retain full gamut. + [#2862](https://github.com/lovell/sharp/issues/2862) + +* Add support for libvips compiled with OpenJPEG. + [#2868](https://github.com/lovell/sharp/pull/2868) + +* Remove unsupported animation properties from AVIF output. + [#2870](https://github.com/lovell/sharp/issues/2870) + +* Resolve paths before comparing input/output filenames. + [#2878](https://github.com/lovell/sharp/pull/2878) + [@rexxars](https://github.com/rexxars) + +* Allow use of speed 9 (fastest) for HEIF encoding. + [#2879](https://github.com/lovell/sharp/pull/2879) + [@rexxars](https://github.com/rexxars) diff --git a/docs/src/content/docs/changelog/v0.29.2.md b/docs/src/content/docs/changelog/v0.29.2.md new file mode 100644 index 000000000..0628963f0 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.29.2.md @@ -0,0 +1,22 @@ +--- +title: v0.29.2 - 21st October 2021 +slug: changelog/v0.29.2 +--- + +* Add `timeout` function to limit processing time. + +* Ensure `sharp.versions` is populated from vendored libvips. + +* Remove animation properties from single page images. + [#2890](https://github.com/lovell/sharp/issues/2890) + +* Allow use of 'tif' to select TIFF output. + [#2893](https://github.com/lovell/sharp/pull/2893) + [@erf](https://github.com/erf) + +* Improve error message on Windows for version conflict. + [#2918](https://github.com/lovell/sharp/pull/2918) + [@dkrnl](https://github.com/dkrnl) + +* Throw error rather than exit when invalid binaries detected. + [#2931](https://github.com/lovell/sharp/issues/2931) diff --git a/docs/src/content/docs/changelog/v0.29.3.md b/docs/src/content/docs/changelog/v0.29.3.md new file mode 100644 index 000000000..e344d790e --- /dev/null +++ b/docs/src/content/docs/changelog/v0.29.3.md @@ -0,0 +1,11 @@ +--- +title: v0.29.3 - 14th November 2021 +slug: changelog/v0.29.3 +--- + +* Ensure correct dimensions when containing image resized to 1px. + [#2951](https://github.com/lovell/sharp/issues/2951) + +* Impute TIFF `xres`/`yres` from `density` provided to `withMetadata`. + [#2952](https://github.com/lovell/sharp/pull/2952) + [@mbklein](https://github.com/mbklein) diff --git a/docs/src/content/docs/changelog/v0.30.0.md b/docs/src/content/docs/changelog/v0.30.0.md new file mode 100644 index 000000000..2605fbcaa --- /dev/null +++ b/docs/src/content/docs/changelog/v0.30.0.md @@ -0,0 +1,48 @@ +--- +title: v0.30.0 - 1st February 2022 +slug: changelog/v0.30.0 +--- + +* Add support for GIF output to prebuilt binaries. + +* Reduce minimum Linux ARM64v8 glibc requirement to 2.17. + +* Verify prebuilt binaries with a Subresource Integrity check. + +* Standardise WebP `effort` option name, deprecate `reductionEffort`. + +* Standardise HEIF `effort` option name, deprecate `speed`. + +* Add support for IIIF v3 tile-based output. + +* Expose control over CPU effort for palette-based PNG output. + [#2541](https://github.com/lovell/sharp/issues/2541) + +* Improve animated (multi-page) image resize and extract. + [#2789](https://github.com/lovell/sharp/pull/2789) + [@kleisauke](https://github.com/kleisauke) + +* Expose platform and architecture of vendored binaries as `sharp.vendor`. + [#2928](https://github.com/lovell/sharp/issues/2928) + +* Ensure 16-bit PNG output uses correct bitdepth. + [#2958](https://github.com/lovell/sharp/pull/2958) + [@gforge](https://github.com/gforge) + +* Properly emit close events for duplex streams. + [#2976](https://github.com/lovell/sharp/pull/2976) + [@driannaude](https://github.com/driannaude) + +* Expose `unlimited` option for SVG and PNG input, switches off safety features. + [#2984](https://github.com/lovell/sharp/issues/2984) + +* Add `withoutReduction` option to resize operation. + [#3006](https://github.com/lovell/sharp/pull/3006) + [@christopherbradleybanks](https://github.com/christopherbradleybanks) + +* Add `resolutionUnit` as `tiff` option and expose in metadata. + [#3023](https://github.com/lovell/sharp/pull/3023) + [@ompal-sisodiya](https://github.com/ompal-sisodiya) + +* Ensure rotate-then-extract works with EXIF mirroring. + [#3024](https://github.com/lovell/sharp/issues/3024) diff --git a/docs/src/content/docs/changelog/v0.30.1.md b/docs/src/content/docs/changelog/v0.30.1.md new file mode 100644 index 000000000..06f890da8 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.30.1.md @@ -0,0 +1,19 @@ +--- +title: v0.30.1 - 9th February 2022 +slug: changelog/v0.30.1 +--- + +* Allow use of `toBuffer` and `toFile` on the same instance. + [#3044](https://github.com/lovell/sharp/issues/3044) + +* Skip shrink-on-load for known libjpeg rounding errors. + [#3066](https://github.com/lovell/sharp/issues/3066) + [@kleisauke](https://github.com/kleisauke) + +* Ensure withoutReduction does not interfere with contain/crop/embed. + [#3081](https://github.com/lovell/sharp/pull/3081) + [@kleisauke](https://github.com/kleisauke) + +* Ensure affine interpolator is correctly finalised. + [#3083](https://github.com/lovell/sharp/pull/3083) + [@kleisauke](https://github.com/kleisauke) diff --git a/docs/src/content/docs/changelog/v0.30.2.md b/docs/src/content/docs/changelog/v0.30.2.md new file mode 100644 index 000000000..1b5c7e1c5 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.30.2.md @@ -0,0 +1,17 @@ +--- +title: v0.30.2 - 2nd March 2022 +slug: changelog/v0.30.2 +--- + +* Improve performance and accuracy when compositing multiple images. + [#2286](https://github.com/lovell/sharp/issues/2286) + +* Expand pkgconfig search path for wider BSD support. + [#3106](https://github.com/lovell/sharp/issues/3106) + +* Ensure Windows C++ runtime is linked statically (regression in 0.30.0). + [#3110](https://github.com/lovell/sharp/pull/3110) + [@kleisauke](https://github.com/kleisauke) + +* Temporarily ignore greyscale ICC profiles to workaround lcms bug. + [#3112](https://github.com/lovell/sharp/issues/3112) diff --git a/docs/src/content/docs/changelog/v0.30.3.md b/docs/src/content/docs/changelog/v0.30.3.md new file mode 100644 index 000000000..77a2584a8 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.30.3.md @@ -0,0 +1,13 @@ +--- +title: v0.30.3 - 14th March 2022 +slug: changelog/v0.30.3 +--- + +* Allow `sharpen` options to be provided more consistently as an Object. + [#2561](https://github.com/lovell/sharp/issues/2561) + +* Expose `x1`, `y2` and `y3` parameters of `sharpen` operation. + [#2935](https://github.com/lovell/sharp/issues/2935) + +* Prevent double unpremultiply with some composite blend modes (regression in 0.30.2). + [#3118](https://github.com/lovell/sharp/issues/3118) diff --git a/docs/src/content/docs/changelog/v0.30.4.md b/docs/src/content/docs/changelog/v0.30.4.md new file mode 100644 index 000000000..a4f0040bf --- /dev/null +++ b/docs/src/content/docs/changelog/v0.30.4.md @@ -0,0 +1,20 @@ +--- +title: v0.30.4 - 18th April 2022 +slug: changelog/v0.30.4 +--- + +* Increase control over sensitivity to invalid images via `failOn`, deprecate `failOnError` (equivalent to `failOn: 'warning'`). + +* Ensure `create` input image has correct bit depth and colour space. + [#3139](https://github.com/lovell/sharp/issues/3139) + +* Add support for `TypedArray` input with `byteOffset` and `length`. + [#3146](https://github.com/lovell/sharp/pull/3146) + [@codepage949](https://github.com/codepage949) + +* Improve error message when attempting to render SVG input greater than 32767x32767. + [#3167](https://github.com/lovell/sharp/issues/3167) + +* Add missing file name to 'Input file is missing' error message. + [#3178](https://github.com/lovell/sharp/pull/3178) + [@Brodan](https://github.com/Brodan) diff --git a/docs/src/content/docs/changelog/v0.30.5.md b/docs/src/content/docs/changelog/v0.30.5.md new file mode 100644 index 000000000..406357619 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.30.5.md @@ -0,0 +1,19 @@ +--- +title: v0.30.5 - 23rd May 2022 +slug: changelog/v0.30.5 +--- + +* Install: pass `PKG_CONFIG_PATH` via env rather than substitution. + [@dwisiswant0](https://github.com/dwisiswant0) + +* Add support for `--libc` flag to improve cross-platform installation. + [#3160](https://github.com/lovell/sharp/pull/3160) + [@joonamo](https://github.com/joonamo) + +* Allow installation of prebuilt libvips binaries from filesystem. + [#3196](https://github.com/lovell/sharp/pull/3196) + [@ankurparihar](https://github.com/ankurparihar) + +* Fix rotate-then-extract for EXIF orientation 2. + [#3218](https://github.com/lovell/sharp/pull/3218) + [@jakob0fischl](https://github.com/jakob0fischl) diff --git a/docs/src/content/docs/changelog/v0.30.6.md b/docs/src/content/docs/changelog/v0.30.6.md new file mode 100644 index 000000000..340921040 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.30.6.md @@ -0,0 +1,10 @@ +--- +title: v0.30.6 - 30th May 2022 +slug: changelog/v0.30.6 +--- + +* Allow values for `limitInputPixels` larger than 32-bit. + [#3238](https://github.com/lovell/sharp/issues/3238) + +* Ensure brew-installed `vips` can be detected (regression in 0.30.5). + [#3239](https://github.com/lovell/sharp/issues/3239) diff --git a/docs/src/content/docs/changelog/v0.30.7.md b/docs/src/content/docs/changelog/v0.30.7.md new file mode 100644 index 000000000..fd90d905c --- /dev/null +++ b/docs/src/content/docs/changelog/v0.30.7.md @@ -0,0 +1,15 @@ +--- +title: v0.30.7 - 22nd June 2022 +slug: changelog/v0.30.7 +--- + +* Ensure tiled composition always works with outside resizing. + [#3227](https://github.com/lovell/sharp/issues/3227) + +* Allow WebP encoding effort of 0. + [#3261](https://github.com/lovell/sharp/pull/3261) + [@AlexanderTheGrey](https://github.com/AlexanderTheGrey) + +* Prevent upsampling via libwebp. + [#3267](https://github.com/lovell/sharp/pull/3267) + [@blacha](https://github.com/blacha) diff --git a/docs/src/content/docs/changelog/v0.31.0.md b/docs/src/content/docs/changelog/v0.31.0.md new file mode 100644 index 000000000..1998f9be8 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.31.0.md @@ -0,0 +1,63 @@ +--- +title: v0.31.0 - 5th September 2022 +slug: changelog/v0.31.0 +--- + +* Drop support for Node.js 12, now requires Node.js >= 14.15.0. + +* GIF output now re-uses input palette if possible. Use `reoptimise` option to generate a new palette. + +* Add WebP `minSize` and `mixed` options for greater control over animation frames. + +* Remove previously-deprecated WebP `reductionEffort` and HEIF `speed` options. Use `effort` to control these. + +* The `flip` and `flop` operations will now occur before the `rotate` operation. + +* Improve `normalise` operation with use of histogram. + [#200](https://github.com/lovell/sharp/issues/200) + +* Use combined bounding box of alpha and non-alpha channels for `trim` operation. + [#2166](https://github.com/lovell/sharp/issues/2166) + +* Add Buffer and Stream support to tile-based output. + [#2238](https://github.com/lovell/sharp/issues/2238) + +* Add input `fileSuffix` and output `alias` to `format` information. + [#2642](https://github.com/lovell/sharp/issues/2642) + +* Re-introduce support for greyscale ICC profiles (temporarily removed in 0.30.2). + [#3114](https://github.com/lovell/sharp/issues/3114) + +* Add support for WebP and PackBits `compression` options with TIFF output. + [#3198](https://github.com/lovell/sharp/issues/3198) + +* Ensure OpenSlide and FITS input works with custom libvips. + [#3226](https://github.com/lovell/sharp/issues/3226) + +* Ensure `trim` operation is a no-op when it would reduce an image to nothing. + [#3223](https://github.com/lovell/sharp/issues/3223) + +* Expose `vips_text` to create an image containing rendered text. + [#3252](https://github.com/lovell/sharp/pull/3252) + [@brahima](https://github.com/brahima) + +* Ensure only properties owned by the `withMetadata` EXIF Object are parsed. + [#3292](https://github.com/lovell/sharp/issues/3292) + +* Expand `linear` operation to allow use of per-channel arrays. + [#3303](https://github.com/lovell/sharp/pull/3303) + [@antonmarsden](https://github.com/antonmarsden) + +* Ensure the order of `rotate`, `resize` and `extend` operations is respected where possible. + Emit warnings when previous calls in the same pipeline will be ignored. + [#3319](https://github.com/lovell/sharp/issues/3319) + +* Ensure PNG bitdepth can be set for non-palette output. + [#3322](https://github.com/lovell/sharp/issues/3322) + +* Add trim option to provide a specific background colour. + [#3332](https://github.com/lovell/sharp/pull/3332) + [@mart-jansink](https://github.com/mart-jansink) + +* Ensure resized image is unpremultiplied before composite. + [#3334](https://github.com/lovell/sharp/issues/3334) diff --git a/docs/src/content/docs/changelog/v0.31.1.md b/docs/src/content/docs/changelog/v0.31.1.md new file mode 100644 index 000000000..44467514f --- /dev/null +++ b/docs/src/content/docs/changelog/v0.31.1.md @@ -0,0 +1,22 @@ +--- +title: v0.31.1 - 29th September 2022 +slug: changelog/v0.31.1 +--- + +* Upgrade to libvips v8.13.2 for upstream bug fixes. + +* Ensure `close` event occurs after `end` event for Stream-based output. + [#3313](https://github.com/lovell/sharp/issues/3313) + +* Ensure `limitInputPixels` constructor option uses uint64. + [#3349](https://github.com/lovell/sharp/pull/3349) + [@marcosc90](https://github.com/marcosc90) + +* Ensure auto-rotation works with shrink-on-load and extract (regression in 0.31.0). + [#3352](https://github.com/lovell/sharp/issues/3352) + +* Ensure AVIF output is always 8-bit. + [#3358](https://github.com/lovell/sharp/issues/3358) + +* Ensure greyscale images can be trimmed (regression in 0.31.0). + [#3386](https://github.com/lovell/sharp/issues/3386) diff --git a/docs/src/content/docs/changelog/v0.31.2.md b/docs/src/content/docs/changelog/v0.31.2.md new file mode 100644 index 000000000..c0be292b0 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.31.2.md @@ -0,0 +1,12 @@ +--- +title: v0.31.2 - 4th November 2022 +slug: changelog/v0.31.2 +--- + +* Upgrade to libvips v8.13.3 for upstream bug fixes. + +* Ensure manual flip, rotate, resize operation ordering (regression in 0.31.1) + [#3391](https://github.com/lovell/sharp/issues/3391) + +* Ensure auto-rotation works without resize (regression in 0.31.1) + [#3422](https://github.com/lovell/sharp/issues/3422) diff --git a/docs/src/content/docs/changelog/v0.31.3.md b/docs/src/content/docs/changelog/v0.31.3.md new file mode 100644 index 000000000..84c6ac899 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.31.3.md @@ -0,0 +1,34 @@ +--- +title: v0.31.3 - 21st December 2022 +slug: changelog/v0.31.3 +--- + +* Add experimental support for JPEG-XL images. Requires libvips compiled with libjxl. + [#2731](https://github.com/lovell/sharp/issues/2731) + +* Add runtime detection of V8 memory cage, ensures compatibility with Electron 21 onwards. + [#3384](https://github.com/lovell/sharp/issues/3384) + +* Expose `interFrameMaxError` and `interPaletteMaxError` GIF optimisation properties. + [#3401](https://github.com/lovell/sharp/issues/3401) + +* Allow installation on Linux with glibc patch versions e.g. Fedora 38. + [#3423](https://github.com/lovell/sharp/issues/3423) + +* Expand range of existing `sharpen` parameters to match libvips. + [#3427](https://github.com/lovell/sharp/issues/3427) + +* Prevent possible race condition awaiting metadata of Stream-based input. + [#3451](https://github.com/lovell/sharp/issues/3451) + +* Improve `extractChannel` support for 16-bit output colourspaces. + [#3453](https://github.com/lovell/sharp/issues/3453) + +* Ignore `sequentialRead` option when calculating image statistics. + [#3462](https://github.com/lovell/sharp/issues/3462) + +* Small performance improvement for operations that introduce a non-opaque background. + [#3465](https://github.com/lovell/sharp/issues/3465) + +* Ensure integral output of `linear` operation. + [#3468](https://github.com/lovell/sharp/issues/3468) diff --git a/docs/src/content/docs/changelog/v0.32.0.md b/docs/src/content/docs/changelog/v0.32.0.md new file mode 100644 index 000000000..f86104bfa --- /dev/null +++ b/docs/src/content/docs/changelog/v0.32.0.md @@ -0,0 +1,61 @@ +--- +title: v0.32.0 - 24th March 2023 +slug: changelog/v0.32.0 +--- + +* Default to using sequential rather than random access read where possible. + +* Replace GIF output `optimise` / `optimize` option with `reuse`. + +* Add `progressive` option to GIF output for interlacing. + +* Add `wrap` option to text image creation. + +* Add `formatMagick` property to metadata of images loaded via *magick. + +* Prefer integer (un)premultiply for faster resizing of RGBA images. + +* Add `ignoreIcc` input option to ignore embedded ICC profile. + +* Allow use of GPS (IFD3) EXIF metadata. + [#2767](https://github.com/lovell/sharp/issues/2767) + +* TypeScript definitions are now maintained and published directly, deprecating the `@types/sharp` package. + [#3369](https://github.com/lovell/sharp/issues/3369) + +* Prebuilt binaries: ensure macOS 10.13+ support, as documented. + [#3438](https://github.com/lovell/sharp/issues/3438) + +* Prebuilt binaries: prevent use of glib slice allocator, improves QEMU support. + [#3448](https://github.com/lovell/sharp/issues/3448) + +* Add focus point coordinates to output when using attention based crop. + [#3470](https://github.com/lovell/sharp/pull/3470) + [@ejoebstl](https://github.com/ejoebstl) + +* Expose sharp version as `sharp.versions.sharp`. + [#3471](https://github.com/lovell/sharp/issues/3471) + +* Respect `fastShrinkOnLoad` resize option for WebP input. + [#3516](https://github.com/lovell/sharp/issues/3516) + +* Reduce sharpen `sigma` maximum from 10000 to 10. + [#3521](https://github.com/lovell/sharp/issues/3521) + +* Add support for `ArrayBuffer` input. + [#3548](https://github.com/lovell/sharp/pull/3548) + [@kapouer](https://github.com/kapouer) + +* Add support to `extend` operation for `extendWith` to allow copy/mirror/repeat. + [#3556](https://github.com/lovell/sharp/pull/3556) + [@janaz](https://github.com/janaz) + +* Ensure all async JS callbacks are wrapped to help avoid possible race condition. + [#3569](https://github.com/lovell/sharp/issues/3569) + +* Prebuilt binaries: support for tile-based output temporarily removed due to licensing issue. + [#3581](https://github.com/lovell/sharp/issues/3581) + +* Add support to `normalise` for `lower` and `upper` percentiles. + [#3583](https://github.com/lovell/sharp/pull/3583) + [@LachlanNewman](https://github.com/LachlanNewman) diff --git a/docs/src/content/docs/changelog/v0.32.1.md b/docs/src/content/docs/changelog/v0.32.1.md new file mode 100644 index 000000000..a73cfb93e --- /dev/null +++ b/docs/src/content/docs/changelog/v0.32.1.md @@ -0,0 +1,30 @@ +--- +title: v0.32.1 - 27th April 2023 +slug: changelog/v0.32.1 +--- + +* Add experimental `unflatten` operation. + [#3461](https://github.com/lovell/sharp/pull/3461) + [@antonmarsden](https://github.com/antonmarsden) + +* Ensure use of `flip` operation forces random access read (regression in 0.32.0). + [#3600](https://github.com/lovell/sharp/issues/3600) + +* Ensure `linear` operation works with 16-bit input (regression in 0.31.3). + [#3605](https://github.com/lovell/sharp/issues/3605) + +* Install: ensure proxy URLs are logged correctly. + [#3615](https://github.com/lovell/sharp/pull/3615) + [@TomWis97](https://github.com/TomWis97) + +* Ensure profile-less CMYK to CMYK roundtrip skips colourspace conversion. + [#3620](https://github.com/lovell/sharp/issues/3620) + +* Add support for `modulate` operation when using non-sRGB pipeline colourspace. + [#3620](https://github.com/lovell/sharp/issues/3620) + +* Ensure `trim` operation works with CMYK images (regression in 0.31.0). + [#3636](https://github.com/lovell/sharp/issues/3636) + +* Install: coerce libc version to semver. + [#3641](https://github.com/lovell/sharp/issues/3641) diff --git a/docs/src/content/docs/changelog/v0.32.2.md b/docs/src/content/docs/changelog/v0.32.2.md new file mode 100644 index 000000000..a14aa1410 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.32.2.md @@ -0,0 +1,25 @@ +--- +title: v0.32.2 - 11th July 2023 +slug: changelog/v0.32.2 +--- + +* Limit HEIF output dimensions to 16384x16384, matches libvips. + +* Ensure exceptions are not thrown when terminating. + [#3569](https://github.com/lovell/sharp/issues/3569) + +* Ensure the same access method is used for all inputs (regression in 0.32.0). + [#3669](https://github.com/lovell/sharp/issues/3669) + +* Improve detection of jp2 filename extensions. + [#3674](https://github.com/lovell/sharp/pull/3674) + [@bianjunjie1981](https://github.com/bianjunjie1981) + +* Guard use of smartcrop premultiplied option to prevent warning (regression in 0.32.1). + [#3710](https://github.com/lovell/sharp/issues/3710) + +* Prevent over-compute in affine-based rotate before resize. + [#3722](https://github.com/lovell/sharp/issues/3722) + +* Allow sequential read for EXIF-based auto-orientation. + [#3725](https://github.com/lovell/sharp/issues/3725) diff --git a/docs/src/content/docs/changelog/v0.32.3.md b/docs/src/content/docs/changelog/v0.32.3.md new file mode 100644 index 000000000..ac3151982 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.32.3.md @@ -0,0 +1,10 @@ +--- +title: v0.32.3 - 14th July 2023 +slug: changelog/v0.32.3 +--- + +* Expose `preset` option for WebP output. + [#3639](https://github.com/lovell/sharp/issues/3639) + +* Ensure decoding remains sequential for all operations (regression in 0.32.2). + [#3725](https://github.com/lovell/sharp/issues/3725) diff --git a/docs/src/content/docs/changelog/v0.32.4.md b/docs/src/content/docs/changelog/v0.32.4.md new file mode 100644 index 000000000..f327f8d0b --- /dev/null +++ b/docs/src/content/docs/changelog/v0.32.4.md @@ -0,0 +1,11 @@ +--- +title: v0.32.4 - 21st July 2023 +slug: changelog/v0.32.4 +--- + +* Upgrade to libvips v8.14.3 for upstream bug fixes. + +* Expose ability to (un)block low-level libvips operations by name. + +* Prebuilt binaries: restore support for tile-based output. + [#3581](https://github.com/lovell/sharp/issues/3581) diff --git a/docs/src/content/docs/changelog/v0.32.5.md b/docs/src/content/docs/changelog/v0.32.5.md new file mode 100644 index 000000000..3a38ec7ec --- /dev/null +++ b/docs/src/content/docs/changelog/v0.32.5.md @@ -0,0 +1,24 @@ +--- +title: v0.32.5 - 15th August 2023 +slug: changelog/v0.32.5 +--- + +* Upgrade to libvips v8.14.4 for upstream bug fixes. + +* TypeScript: Add missing `WebpPresetEnum` to definitions. + [#3748](https://github.com/lovell/sharp/pull/3748) + [@pilotso11](https://github.com/pilotso11) + +* Ensure compilation using musl v1.2.4. + [#3755](https://github.com/lovell/sharp/pull/3755) + [@kleisauke](https://github.com/kleisauke) + +* Ensure resize with a `fit` of `inside` respects 90/270 degree rotation. + [#3756](https://github.com/lovell/sharp/issues/3756) + +* TypeScript: Ensure `minSize` property of `WebpOptions` is boolean. + [#3758](https://github.com/lovell/sharp/pull/3758) + [@sho-xizz](https://github.com/sho-xizz) + +* Ensure `withMetadata` adds default sRGB profile. + [#3761](https://github.com/lovell/sharp/issues/3761) diff --git a/docs/src/content/docs/changelog/v0.32.6.md b/docs/src/content/docs/changelog/v0.32.6.md new file mode 100644 index 000000000..6b7c3d431 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.32.6.md @@ -0,0 +1,19 @@ +--- +title: v0.32.6 - 18th September 2023 +slug: changelog/v0.32.6 +--- + +* Upgrade to libvips v8.14.5 for upstream bug fixes. + +* Ensure composite tile images are fully decoded (regression in 0.32.0). + [#3767](https://github.com/lovell/sharp/issues/3767) + +* Ensure `withMetadata` can add ICC profiles to RGB16 output. + [#3773](https://github.com/lovell/sharp/issues/3773) + +* Ensure `withMetadata` does not reduce 16-bit images to 8-bit (regression in 0.32.5). + [#3773](https://github.com/lovell/sharp/issues/3773) + +* TypeScript: Add definitions for block and unblock. + [#3799](https://github.com/lovell/sharp/pull/3799) + [@ldrick](https://github.com/ldrick) diff --git a/docs/src/content/docs/changelog/v0.33.0.md b/docs/src/content/docs/changelog/v0.33.0.md new file mode 100644 index 000000000..1ca8435de --- /dev/null +++ b/docs/src/content/docs/changelog/v0.33.0.md @@ -0,0 +1,47 @@ +--- +title: v0.33.0 - 29th November 2023 +slug: changelog/v0.33.0 +--- + +* Drop support for Node.js 14 and 16, now requires Node.js ^18.17.0 or >= 20.3.0 + +* Prebuilt binaries distributed via npm registry and installed via package manager. + +* Building from source requires dependency on `node-addon-api`. + +* Remove `sharp.vendor`. + +* Partially deprecate `withMetadata()`, use `withExif()` and `withIccProfile()`. + +* Add experimental support for WebAssembly-based runtimes. + [@RReverser](https://github.com/RReverser) + +* Options for `trim` operation must be an Object, add new `lineArt` option. + [#2363](https://github.com/lovell/sharp/issues/2363) + +* Improve luminance of `tint` operation with weighting function. + [#3338](https://github.com/lovell/sharp/issues/3338) + [@jcupitt](https://github.com/jcupitt) + +* Ensure all `Error` objects contain a `stack` property. + [#3653](https://github.com/lovell/sharp/issues/3653) + +* Make `compression` option of `heif` mandatory to help reduce HEIF vs HEIC confusion. + [#3740](https://github.com/lovell/sharp/issues/3740) + +* Ensure correct interpretation of 16-bit raw input. + [#3808](https://github.com/lovell/sharp/issues/3808) + +* Add support for `miniswhite` when using TIFF output. + [#3812](https://github.com/lovell/sharp/pull/3812) + [@dnsbty](https://github.com/dnsbty) + +* TypeScript: add missing definition for `withMetadata` boolean. + [#3823](https://github.com/lovell/sharp/pull/3823) + [@uhthomas](https://github.com/uhthomas) + +* Add more fine-grained control over output metadata. + [#3824](https://github.com/lovell/sharp/issues/3824) + +* Ensure multi-page extract remains sequential. + [#3837](https://github.com/lovell/sharp/issues/3837) diff --git a/docs/src/content/docs/changelog/v0.33.1.md b/docs/src/content/docs/changelog/v0.33.1.md new file mode 100644 index 000000000..9a280c82f --- /dev/null +++ b/docs/src/content/docs/changelog/v0.33.1.md @@ -0,0 +1,14 @@ +--- +title: v0.33.1 - 17th December 2023 +slug: changelog/v0.33.1 +--- + +* Add support for Yarn Plug'n'Play filesystem layout. + [#3888](https://github.com/lovell/sharp/issues/3888) + +* Emit warning when attempting to use invalid ICC profiles. + [#3895](https://github.com/lovell/sharp/issues/3895) + +* Ensure `VIPS_NOVECTOR` environment variable is respected. + [#3897](https://github.com/lovell/sharp/pull/3897) + [@icetee](https://github.com/icetee) diff --git a/docs/src/content/docs/changelog/v0.33.2.md b/docs/src/content/docs/changelog/v0.33.2.md new file mode 100644 index 000000000..7d88c0adf --- /dev/null +++ b/docs/src/content/docs/changelog/v0.33.2.md @@ -0,0 +1,16 @@ +--- +title: v0.33.2 - 12th January 2024 +slug: changelog/v0.33.2 +--- + +* Upgrade to libvips v8.15.1 for upstream bug fixes. + +* TypeScript: add definition for `keepMetadata`. + [#3914](https://github.com/lovell/sharp/pull/3914) + [@abhi0498](https://github.com/abhi0498) + +* Ensure `extend` operation stays sequential when copying (regression in 0.32.0). + [#3928](https://github.com/lovell/sharp/issues/3928) + +* Improve error handling for unsupported multi-page rotation. + [#3940](https://github.com/lovell/sharp/issues/3940) diff --git a/docs/src/content/docs/changelog/v0.33.3.md b/docs/src/content/docs/changelog/v0.33.3.md new file mode 100644 index 000000000..17e6639fe --- /dev/null +++ b/docs/src/content/docs/changelog/v0.33.3.md @@ -0,0 +1,21 @@ +--- +title: v0.33.3 - 23rd March 2024 +slug: changelog/v0.33.3 +--- + +* Upgrade to libvips v8.15.2 for upstream bug fixes. + +* Ensure `keepIccProfile` retains P3 and CMYK input profiles. + [#3906](https://github.com/lovell/sharp/issues/3906) + [#4008](https://github.com/lovell/sharp/issues/4008) + +* Ensure `text.wrap` property can accept `word-char` as value. + [#4028](https://github.com/lovell/sharp/pull/4028) + [@yolopunk](https://github.com/yolopunk) + +* Ensure `clone` takes a deep copy of existing options. + [#4029](https://github.com/lovell/sharp/issues/4029) + +* Add `bitdepth` option to `heif` output (prebuilt binaries support 8-bit only). + [#4036](https://github.com/lovell/sharp/pull/4036) + [@mertalev](https://github.com/mertalev) diff --git a/docs/src/content/docs/changelog/v0.33.4.md b/docs/src/content/docs/changelog/v0.33.4.md new file mode 100644 index 000000000..9c4500f91 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.33.4.md @@ -0,0 +1,32 @@ +--- +title: v0.33.4 - 16th May 2024 +slug: changelog/v0.33.4 +--- + +* Remove experimental status from `pipelineColourspace`. + +* Reduce default concurrency when musl thread over-subscription detected. + +* TypeScript: add missing definitions for `OverlayOptions`. + [#4048](https://github.com/lovell/sharp/pull/4048) + [@ike-gg](https://github.com/ike-gg) + +* Install: add advanced option to force use of a globally-installed libvips. + [#4060](https://github.com/lovell/sharp/issues/4060) + +* Expose `bilinear` resizing kernel (and interpolator). + [#4061](https://github.com/lovell/sharp/issues/4061) + +* Ensure `extend` operation stays sequential for multi-page TIFF (regression in 0.32.0). + [#4069](https://github.com/lovell/sharp/issues/4069) + +* Tighten validation of constructor `text` integer properties. + [#4071](https://github.com/lovell/sharp/issues/4071) + +* Simplify internal StaySequential logic. + [#4074](https://github.com/lovell/sharp/pull/4074) + [@kleisauke](https://github.com/kleisauke) + +* Ensure negate operation occurs after profile conversion. + [#4096](https://github.com/lovell/sharp/pull/4096) + [@adriaanmeuris](https://github.com/adriaanmeuris) diff --git a/docs/src/content/docs/changelog/v0.33.5.md b/docs/src/content/docs/changelog/v0.33.5.md new file mode 100644 index 000000000..7fb99baa2 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.33.5.md @@ -0,0 +1,39 @@ +--- +title: v0.33.5 - 16th August 2024 +slug: changelog/v0.33.5 +--- + +* Upgrade to libvips v8.15.3 for upstream bug fixes. + +* Add `pageHeight` and `pages` to response of multi-page output. + [#3411](https://github.com/lovell/sharp/issues/3411) + +* Ensure option to force use of a globally-installed libvips works correctly. + [#4111](https://github.com/lovell/sharp/pull/4111) + [@project0](https://github.com/project0) + +* Minimise use of `engines` property to improve yarn v1 support. + [#4130](https://github.com/lovell/sharp/issues/4130) + +* Ensure `sharp.format.heif` includes only AVIF when using prebuilt binaries. + [#4132](https://github.com/lovell/sharp/issues/4132) + +* Add support to recomb operation for 4x4 matrices. + [#4147](https://github.com/lovell/sharp/pull/4147) + [@ton11797](https://github.com/ton11797) + +* Expose PNG text chunks as `comments` metadata. + [#4157](https://github.com/lovell/sharp/pull/4157) + [@nkeynes](https://github.com/nkeynes) + +* Expose optional `precision` and `minAmplitude` parameters of `blur` operation. + [#4168](https://github.com/lovell/sharp/pull/4168) + [#4172](https://github.com/lovell/sharp/pull/4172) + [@marcosc90](https://github.com/marcosc90) + +* Ensure `keepIccProfile` avoids colour transformation where possible. + [#4186](https://github.com/lovell/sharp/issues/4186) + +* TypeScript: `chromaSubsampling` metadata is optional. + [#4191](https://github.com/lovell/sharp/pull/4191) + [@DavidVaness](https://github.com/DavidVaness) diff --git a/docs/src/content/docs/changelog/v0.34.0.md b/docs/src/content/docs/changelog/v0.34.0.md new file mode 100644 index 000000000..4fc83109e --- /dev/null +++ b/docs/src/content/docs/changelog/v0.34.0.md @@ -0,0 +1,52 @@ +--- +title: v0.34.0 - 4th April 2025 +slug: changelog/v0.34.0 +--- + +* Breaking: Support array of input images to be joined or animated. + [#1580](https://github.com/lovell/sharp/issues/1580) + +* Breaking: Ensure `removeAlpha` removes all alpha channels. + [#2266](https://github.com/lovell/sharp/issues/2266) + +* Breaking: Non-animated GIF output defaults to no-loop instead of loop-forever. + [#3394](https://github.com/lovell/sharp/issues/3394) + +* Breaking: Support `info.size` on wide-character systems via upgrade to C++17. + [#3943](https://github.com/lovell/sharp/issues/3943) + +* Breaking: Ensure `background` metadata can be parsed by `color` package. + [#4090](https://github.com/lovell/sharp/issues/4090) + +* Add `isPalette` and `bitsPerSample` to metadata, deprecate `paletteBitDepth`. + +* Expose WebP `smartDeblock` output option. + +* Prevent use of linux-x64 binaries with v1 microarchitecture. + +* Add `autoOrient` operation and constructor option. + [#4151](https://github.com/lovell/sharp/pull/4151) + [@happycollision](https://github.com/happycollision) + +* TypeScript: Ensure channel counts use the correct range. + [#4197](https://github.com/lovell/sharp/pull/4197) + [@DavidVaness](https://github.com/DavidVaness) + +* Improve support for ppc64le architecture. + [#4203](https://github.com/lovell/sharp/pull/4203) + [@sumitd2](https://github.com/sumitd2) + +* Add `pdfBackground` constructor property. + [#4207](https://github.com/lovell/sharp/pull/4207) + [@calebmer](https://github.com/calebmer) + +* Expose erode and dilate operations. + [#4243](https://github.com/lovell/sharp/pull/4243) + [@qpincon](https://github.com/qpincon) + +* Add support for RGBE images. Requires libvips compiled with radiance support. + [#4316](https://github.com/lovell/sharp/pull/4316) + [@florentzabera](https://github.com/florentzabera) + +* Allow wide-gamut HEIF output at higher bitdepths. + [#4344](https://github.com/lovell/sharp/issues/4344) diff --git a/docs/src/content/docs/changelog/v0.34.1.md b/docs/src/content/docs/changelog/v0.34.1.md new file mode 100644 index 000000000..a5ae94dcf --- /dev/null +++ b/docs/src/content/docs/changelog/v0.34.1.md @@ -0,0 +1,8 @@ +--- +title: v0.34.1 - 7th April 2025 +slug: changelog/v0.34.1 +--- + +* TypeScript: Ensure new `autoOrient` property is optional. + [#4362](https://github.com/lovell/sharp/pull/4362) + [@styfle](https://github.com/styfle) diff --git a/docs/src/content/docs/changelog/v0.34.2.md b/docs/src/content/docs/changelog/v0.34.2.md new file mode 100644 index 000000000..2292304ea --- /dev/null +++ b/docs/src/content/docs/changelog/v0.34.2.md @@ -0,0 +1,28 @@ +--- +title: v0.34.2 - 20th May 2025 +slug: changelog/v0.34.2 +--- + +* Ensure animated GIF to WebP conversion retains loop (regression in 0.34.0). + [#3394](https://github.com/lovell/sharp/issues/3394) + +* Ensure `pdfBackground` constructor property is used. + [#4207](https://github.com/lovell/sharp/pull/4207) + [#4398](https://github.com/lovell/sharp/issues/4398) + +* Add experimental support for prebuilt Windows ARM64 binaries. + [#4375](https://github.com/lovell/sharp/pull/4375) + [@hans00](https://github.com/hans00) + +* Ensure resizing with a `fit` of `contain` supports multiple alpha channels. + [#4382](https://github.com/lovell/sharp/issues/4382) + +* TypeScript: Ensure `metadata` response more closely matches reality. + [#4383](https://github.com/lovell/sharp/issues/4383) + +* TypeScript: Ensure `smartDeblock` property is included in WebP definition. + [#4387](https://github.com/lovell/sharp/pull/4387) + [@Stephen-X](https://github.com/Stephen-X) + +* Ensure support for wide-character filenames on Windows (regression in 0.34.0). + [#4391](https://github.com/lovell/sharp/issues/4391) diff --git a/docs/src/content/docs/changelog/v0.34.3.md b/docs/src/content/docs/changelog/v0.34.3.md new file mode 100644 index 000000000..1f3016741 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.34.3.md @@ -0,0 +1,33 @@ +--- +title: v0.34.3 - 10th July 2025 +slug: changelog/v0.34.3 +--- + +* Upgrade to libvips v8.17.1 for upstream bug fixes. + +* Add "Magic Kernel Sharp" (no relation) to resizing kernels. + +* Deprecate top-level, format-specific constructor parameters, e.g. `subifd` becomes `tiff.subifd`. + +* Expose `stylesheet` and `highBitdepth` SVG input parameters. + +* Expose `keepDuplicateFrames` GIF output parameter. + +* Add support for RAW digital camera image input. Requires libvips compiled with libraw support. + +* Provide XMP metadata as a string, as well as a Buffer, where possible. + +* Add `pageHeight` option to `create` and `raw` input for animated images. + [#3236](https://github.com/lovell/sharp/issues/3236) + +* Expose JPEG 2000 `oneshot` decoder option. + [#4262](https://github.com/lovell/sharp/pull/4262) + [@mbklein](https://github.com/mbklein) + +* Support composite operation with non-sRGB pipeline colourspace. + [#4412](https://github.com/lovell/sharp/pull/4412) + [@kleisauke](https://github.com/kleisauke) + +* Add `keepXmp` and `withXmp` for control over output XMP metadata. + [#4416](https://github.com/lovell/sharp/pull/4416) + [@tpatel](https://github.com/tpatel) From 628454559e0746a9db5296c9a4095036b0c640da Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Sat, 19 Jul 2025 14:00:42 +0100 Subject: [PATCH 047/115] Ensure autoOrient removes metadata after shrink-on-load #4431 --- docs/src/content/docs/changelog/v0.34.4.md | 7 +++++++ src/pipeline.cc | 4 +++- test/unit/raw.js | 2 -- test/unit/rotate.js | 13 +++++++++++++ 4 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 docs/src/content/docs/changelog/v0.34.4.md diff --git a/docs/src/content/docs/changelog/v0.34.4.md b/docs/src/content/docs/changelog/v0.34.4.md new file mode 100644 index 000000000..5ff635716 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.34.4.md @@ -0,0 +1,7 @@ +--- +title: v0.34.4 - TBD +slug: changelog/v0.34.4 +--- + +* Ensure `autoOrient` removes existing metadata after shrink-on-load. + [#4431](https://github.com/lovell/sharp/issues/4431) diff --git a/src/pipeline.cc b/src/pipeline.cc index 3aa526f3e..cd4b468c3 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -98,7 +98,6 @@ class PipelineWorker : public Napi::AsyncWorker { if (baton->input->autoOrient) { // Rotate and flip image according to Exif orientation std::tie(autoRotation, autoFlip, autoFlop) = CalculateExifRotationAndFlip(sharp::ExifOrientation(image)); - image = sharp::RemoveExifOrientation(image); } rotation = CalculateAngleRotation(baton->angle); @@ -294,6 +293,9 @@ class PipelineWorker : public Napi::AsyncWorker { throw vips::VError("Input SVG image exceeds 32767x32767 pixel limit"); } } + if (baton->input->autoOrient) { + image = sharp::RemoveExifOrientation(image); + } // Any pre-shrinking may already have been done inputWidth = image.width(); diff --git a/test/unit/raw.js b/test/unit/raw.js index 9a01d0f03..4385288c3 100644 --- a/test/unit/raw.js +++ b/test/unit/raw.js @@ -322,8 +322,6 @@ describe('Raw pixel data', function () { .gif({ keepDuplicateFrames: true }) .toBuffer(); - console.log(await sharp(gif).metadata()); - const { width, height, pages, delay } = await sharp(gif).metadata(); assert.strictEqual(width, 1); assert.strictEqual(height, 1); diff --git a/test/unit/rotate.js b/test/unit/rotate.js index 7c3175504..218f4f99f 100644 --- a/test/unit/rotate.js +++ b/test/unit/rotate.js @@ -635,6 +635,19 @@ describe('Rotation', function () { assert.strictEqual(height, 6); }); + it('Shrink-on-load with autoOrient', async () => { + const data = await sharp(fixtures.inputJpgWithLandscapeExif6) + .resize(8) + .autoOrient() + .avif({ effort: 0 }) + .toBuffer(); + + const { width, height, orientation } = await sharp(data).metadata(); + assert.strictEqual(width, 8); + assert.strictEqual(height, 6); + assert.strictEqual(orientation, undefined); + }); + it('Invalid autoOrient throws', () => assert.throws( () => sharp({ autoOrient: 'fail' }), From 67462bee79e5924f56bd879703052ea4c52eb299 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Sat, 19 Jul 2025 14:26:27 +0100 Subject: [PATCH 048/115] CI: Simplify volume mappings for linuxmusl-arm64 runners --- .github/workflows/ci.yml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index da3af0b31..891aae627 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -169,7 +169,7 @@ jobs: path: npm/${{ matrix.platform }} retention-days: 1 if-no-files-found: error - build-linuxmusl-arm-64: + build-linuxmusl-arm64: permissions: contents: read name: "build-linuxmusl-arm64 [Node.js ${{ matrix.nodejs_version_major }}] ${{ matrix.package && '[package]' }}" @@ -177,7 +177,8 @@ jobs: container: image: ${{ matrix.container }} volumes: - - /:/host + - /opt:/opt:rw,rshared + - /opt:/__e/node20:ro,rshared strategy: fail-fast: false matrix: @@ -191,12 +192,10 @@ jobs: - name: Allow Linux musl containers on ARM64 runners # https://github.com/actions/runner/issues/801#issuecomment-2394425757 shell: sh run: | - apk add nodejs - sed -i "s:ID=alpine:ID=NotpineForGHA:" /etc/os-release - cd /host/home/runner/runners/*/externals/ - rm -rf node20/* - mkdir node20/bin - ln -s /usr/bin/node node20/bin/node + sed -i "/^ID=/s/alpine/NotpineForGHA/" /etc/os-release + apk add nodejs --update-cache + mkdir /opt/bin + ln -s /usr/bin/node /opt/bin/node - name: Dependencies run: apk add build-base git python3 font-noto --update-cache - uses: actions/checkout@v4 @@ -304,7 +303,7 @@ jobs: runs-on: ubuntu-24.04 needs: - build-native - - build-linuxmusl-arm-64 + - build-linuxmusl-arm64 - build-qemu - build-emscripten steps: From 08b4242efe27c228a13ee49e9ab9bbaf71895367 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Mon, 21 Jul 2025 16:10:34 +0100 Subject: [PATCH 049/115] Ensure autoOrient occurs before non-90 rotation #4425 - Separate orient vs rotate ordering logic - Simplify EXIF auto-orient by using only rotate and/or flop --- docs/src/content/docs/changelog/v0.34.4.md | 3 + lib/constructor.js | 3 +- lib/resize.js | 11 ++-- src/pipeline.cc | 76 ++++++++++------------ src/pipeline.h | 3 +- test/unit/rotate.js | 27 +++++++- 6 files changed, 72 insertions(+), 51 deletions(-) diff --git a/docs/src/content/docs/changelog/v0.34.4.md b/docs/src/content/docs/changelog/v0.34.4.md index 5ff635716..9855b09b1 100644 --- a/docs/src/content/docs/changelog/v0.34.4.md +++ b/docs/src/content/docs/changelog/v0.34.4.md @@ -3,5 +3,8 @@ title: v0.34.4 - TBD slug: changelog/v0.34.4 --- +* Ensure `autoOrient` occurs before non-90 angle rotation. + [#4425](https://github.com/lovell/sharp/issues/4425) + * Ensure `autoOrient` removes existing metadata after shrink-on-load. [#4431](https://github.com/lovell/sharp/issues/4431) diff --git a/lib/constructor.js b/lib/constructor.js index 131a21a46..a349f42a7 100644 --- a/lib/constructor.js +++ b/lib/constructor.js @@ -230,7 +230,8 @@ const Sharp = function (input, options) { angle: 0, rotationAngle: 0, rotationBackground: [0, 0, 0, 255], - rotateBeforePreExtract: false, + rotateBefore: false, + orientBefore: false, flip: false, flop: false, extendTop: 0, diff --git a/lib/resize.js b/lib/resize.js index 665e0c879..9e4aa78a4 100644 --- a/lib/resize.js +++ b/lib/resize.js @@ -107,7 +107,7 @@ const mapFitToCanvas = { * @private */ function isRotationExpected (options) { - return (options.angle % 360) !== 0 || options.input.autoOrient === true || options.rotationAngle !== 0; + return (options.angle % 360) !== 0 || options.rotationAngle !== 0; } /** @@ -343,7 +343,7 @@ function resize (widthOrOptions, height, options) { } } if (isRotationExpected(this.options) && isResizeExpected(this.options)) { - this.options.rotateBeforePreExtract = true; + this.options.rotateBefore = true; } return this; } @@ -490,9 +490,12 @@ function extract (options) { // Ensure existing rotation occurs before pre-resize extraction if (isRotationExpected(this.options) && !isResizeExpected(this.options)) { if (this.options.widthPre === -1 || this.options.widthPost === -1) { - this.options.rotateBeforePreExtract = true; + this.options.rotateBefore = true; } } + if (this.options.input.autoOrient) { + this.options.orientBefore = true; + } return this; } @@ -566,7 +569,7 @@ function trim (options) { } } if (isRotationExpected(this.options)) { - this.options.rotateBeforePreExtract = true; + this.options.rotateBefore = true; } return this; } diff --git a/src/pipeline.cc b/src/pipeline.cc index cd4b468c3..e2dd1182a 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -92,30 +92,22 @@ class PipelineWorker : public Napi::AsyncWorker { // Calculate angle of rotation VipsAngle rotation = VIPS_ANGLE_D0; VipsAngle autoRotation = VIPS_ANGLE_D0; - bool autoFlip = false; bool autoFlop = false; if (baton->input->autoOrient) { // Rotate and flip image according to Exif orientation - std::tie(autoRotation, autoFlip, autoFlop) = CalculateExifRotationAndFlip(sharp::ExifOrientation(image)); + std::tie(autoRotation, autoFlop) = CalculateExifRotationAndFlop(sharp::ExifOrientation(image)); } rotation = CalculateAngleRotation(baton->angle); - // Rotate pre-extract - bool const shouldRotateBefore = baton->rotateBeforePreExtract && - (rotation != VIPS_ANGLE_D0 || autoRotation != VIPS_ANGLE_D0 || - autoFlip || baton->flip || autoFlop || baton->flop || - baton->rotationAngle != 0.0); - - if (shouldRotateBefore) { - image = sharp::StaySequential(image, - rotation != VIPS_ANGLE_D0 || - autoRotation != VIPS_ANGLE_D0 || - autoFlip || - baton->flip || - baton->rotationAngle != 0.0); + bool const shouldRotateBefore = baton->rotateBefore && + (rotation != VIPS_ANGLE_D0 || baton->flip || baton->flop || baton->rotationAngle != 0.0); + bool const shouldOrientBefore = (shouldRotateBefore || baton->orientBefore) && + (autoRotation != VIPS_ANGLE_D0 || autoFlop); + if (shouldOrientBefore) { + image = sharp::StaySequential(image, autoRotation != VIPS_ANGLE_D0); if (autoRotation != VIPS_ANGLE_D0) { if (autoRotation != VIPS_ANGLE_D180) { MultiPageUnsupported(nPages, "Rotate"); @@ -123,14 +115,20 @@ class PipelineWorker : public Napi::AsyncWorker { image = image.rot(autoRotation); autoRotation = VIPS_ANGLE_D0; } - if (autoFlip != baton->flip) { + if (autoFlop) { + image = image.flip(VIPS_DIRECTION_HORIZONTAL); + autoFlop = false; + } + } + + if (shouldRotateBefore) { + image = sharp::StaySequential(image, rotation != VIPS_ANGLE_D0 || baton->flip || baton->rotationAngle != 0.0); + if (baton->flip) { image = image.flip(VIPS_DIRECTION_VERTICAL); - autoFlip = false; baton->flip = false; } - if (autoFlop != baton->flop) { + if (baton->flop) { image = image.flip(VIPS_DIRECTION_HORIZONTAL); - autoFlop = false; baton->flop = false; } if (rotation != VIPS_ANGLE_D0) { @@ -145,6 +143,7 @@ class PipelineWorker : public Napi::AsyncWorker { std::vector background; std::tie(image, background) = sharp::ApplyAlpha(image, baton->rotationBackground, false); image = image.rotate(baton->rotationAngle, VImage::option()->set("background", background)).copy_memory(); + baton->rotationAngle = 0.0; } } @@ -183,8 +182,7 @@ class PipelineWorker : public Napi::AsyncWorker { // When auto-rotating by 90 or 270 degrees, swap the target width and // height to ensure the behavior aligns with how it would have been if // the rotation had taken place *before* resizing. - if (!baton->rotateBeforePreExtract && - (autoRotation == VIPS_ANGLE_D90 || autoRotation == VIPS_ANGLE_D270)) { + if (autoRotation == VIPS_ANGLE_D90 || autoRotation == VIPS_ANGLE_D270) { std::swap(targetResizeWidth, targetResizeHeight); } @@ -206,7 +204,7 @@ class PipelineWorker : public Napi::AsyncWorker { // - input colourspace is not specified; bool const shouldPreShrink = (targetResizeWidth > 0 || targetResizeHeight > 0) && baton->gamma == 0 && baton->topOffsetPre == -1 && baton->trimThreshold < 0.0 && - baton->colourspacePipeline == VIPS_INTERPRETATION_LAST && !shouldRotateBefore; + baton->colourspacePipeline == VIPS_INTERPRETATION_LAST && !(shouldOrientBefore || shouldRotateBefore); if (shouldPreShrink) { // The common part of the shrink: the bit by which both axes must be shrunk @@ -398,7 +396,6 @@ class PipelineWorker : public Napi::AsyncWorker { image = sharp::StaySequential(image, autoRotation != VIPS_ANGLE_D0 || baton->flip || - autoFlip || rotation != VIPS_ANGLE_D0); // Auto-rotate post-extract if (autoRotation != VIPS_ANGLE_D0) { @@ -408,7 +405,7 @@ class PipelineWorker : public Napi::AsyncWorker { image = image.rot(autoRotation); } // Mirror vertically (up-down) about the x-axis - if (baton->flip != autoFlip) { + if (baton->flip) { image = image.flip(VIPS_DIRECTION_VERTICAL); } // Mirror horizontally (left-right) about the y-axis @@ -515,7 +512,7 @@ class PipelineWorker : public Napi::AsyncWorker { } // Rotate post-extract non-90 angle - if (!baton->rotateBeforePreExtract && baton->rotationAngle != 0.0) { + if (!baton->rotateBefore && baton->rotationAngle != 0.0) { MultiPageUnsupported(nPages, "Rotate"); image = sharp::StaySequential(image); std::vector background; @@ -656,21 +653,16 @@ class PipelineWorker : public Napi::AsyncWorker { if (composite->input->autoOrient) { // Respect EXIF Orientation VipsAngle compositeAutoRotation = VIPS_ANGLE_D0; - bool compositeAutoFlip = false; bool compositeAutoFlop = false; - std::tie(compositeAutoRotation, compositeAutoFlip, compositeAutoFlop) = - CalculateExifRotationAndFlip(sharp::ExifOrientation(compositeImage)); + std::tie(compositeAutoRotation, compositeAutoFlop) = + CalculateExifRotationAndFlop(sharp::ExifOrientation(compositeImage)); compositeImage = sharp::RemoveExifOrientation(compositeImage); - compositeImage = sharp::StaySequential(compositeImage, - compositeAutoRotation != VIPS_ANGLE_D0 || compositeAutoFlip); + compositeImage = sharp::StaySequential(compositeImage, compositeAutoRotation != VIPS_ANGLE_D0); if (compositeAutoRotation != VIPS_ANGLE_D0) { compositeImage = compositeImage.rot(compositeAutoRotation); } - if (compositeAutoFlip) { - compositeImage = compositeImage.flip(VIPS_DIRECTION_VERTICAL); - } if (compositeAutoFlop) { compositeImage = compositeImage.flip(VIPS_DIRECTION_HORIZONTAL); } @@ -1402,21 +1394,20 @@ class PipelineWorker : public Napi::AsyncWorker { Calculate the angle of rotation and need-to-flip for the given Exif orientation By default, returns zero, i.e. no rotation. */ - std::tuple - CalculateExifRotationAndFlip(int const exifOrientation) { + std::tuple + CalculateExifRotationAndFlop(int const exifOrientation) { VipsAngle rotate = VIPS_ANGLE_D0; - bool flip = false; bool flop = false; switch (exifOrientation) { case 6: rotate = VIPS_ANGLE_D90; break; case 3: rotate = VIPS_ANGLE_D180; break; case 8: rotate = VIPS_ANGLE_D270; break; - case 2: flop = true; break; // flop 1 - case 7: flip = true; rotate = VIPS_ANGLE_D90; break; // flip 6 - case 4: flop = true; rotate = VIPS_ANGLE_D180; break; // flop 3 - case 5: flip = true; rotate = VIPS_ANGLE_D270; break; // flip 8 + case 2: flop = true; break; + case 7: flop = true; rotate = VIPS_ANGLE_D270; break; + case 4: flop = true; rotate = VIPS_ANGLE_D180; break; + case 5: flop = true; rotate = VIPS_ANGLE_D90; break; } - return std::make_tuple(rotate, flip, flop); + return std::make_tuple(rotate, flop); } /* @@ -1641,7 +1632,8 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) { baton->angle = sharp::AttrAsInt32(options, "angle"); baton->rotationAngle = sharp::AttrAsDouble(options, "rotationAngle"); baton->rotationBackground = sharp::AttrAsVectorOfDouble(options, "rotationBackground"); - baton->rotateBeforePreExtract = sharp::AttrAsBool(options, "rotateBeforePreExtract"); + baton->rotateBefore = sharp::AttrAsBool(options, "rotateBefore"); + baton->orientBefore = sharp::AttrAsBool(options, "orientBefore"); baton->flip = sharp::AttrAsBool(options, "flip"); baton->flop = sharp::AttrAsBool(options, "flop"); baton->extendTop = sharp::AttrAsInt32(options, "extendTop"); diff --git a/src/pipeline.h b/src/pipeline.h index d5d5b3fb1..8edfff58b 100644 --- a/src/pipeline.h +++ b/src/pipeline.h @@ -115,7 +115,8 @@ struct PipelineBaton { int angle; double rotationAngle; std::vector rotationBackground; - bool rotateBeforePreExtract; + bool rotateBefore; + bool orientBefore; bool flip; bool flop; int extendTop; diff --git a/test/unit/rotate.js b/test/unit/rotate.js index 218f4f99f..0a7298b62 100644 --- a/test/unit/rotate.js +++ b/test/unit/rotate.js @@ -565,9 +565,9 @@ describe('Rotation', function () { .raw() .toBuffer(); - assert.strictEqual(r, 60); - assert.strictEqual(g, 73); - assert.strictEqual(b, 52); + assert.strictEqual(r, 61); + assert.strictEqual(g, 74); + assert.strictEqual(b, 51); }); it('Flip and rotate ordering', async () => { @@ -648,6 +648,27 @@ describe('Rotation', function () { assert.strictEqual(orientation, undefined); }); + it('Auto-orient and rotate 45', async () => { + const data = await sharp(fixtures.inputJpgWithLandscapeExif2, { autoOrient: true }) + .rotate(45) + .toBuffer(); + + const { width, height } = await sharp(data).metadata(); + assert.strictEqual(width, 742); + assert.strictEqual(height, 742); + }); + + it('Auto-orient, extract and rotate 45', async () => { + const data = await sharp(fixtures.inputJpgWithLandscapeExif2, { autoOrient: true }) + .extract({ left: 20, top: 20, width: 200, height: 100 }) + .rotate(45) + .toBuffer(); + + const { width, height } = await sharp(data).metadata(); + assert.strictEqual(width, 212); + assert.strictEqual(height, 212); + }); + it('Invalid autoOrient throws', () => assert.throws( () => sharp({ autoOrient: 'fail' }), From e0452355454d2a830a110c119c1708de0f4f193f Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Thu, 24 Jul 2025 16:51:28 +0100 Subject: [PATCH 050/115] Upgrade to sharp-libvips v1.2.1 --- .github/workflows/ci.yml | 2 +- npm/darwin-arm64/package.json | 2 +- npm/darwin-x64/package.json | 2 +- npm/linux-arm/package.json | 2 +- npm/linux-arm64/package.json | 2 +- npm/linux-ppc64/package.json | 2 +- npm/linux-s390x/package.json | 2 +- npm/linux-x64/package.json | 2 +- npm/linuxmusl-arm64/package.json | 2 +- npm/linuxmusl-x64/package.json | 2 +- npm/wasm32/package.json | 2 +- package.json | 36 ++++++++++++++++---------------- test/unit/libvips.js | 2 +- 13 files changed, 30 insertions(+), 30 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 891aae627..56ec651a2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -269,7 +269,7 @@ jobs: contents: read name: "build-wasm32 [package]" runs-on: ubuntu-24.04 - container: "emscripten/emsdk:4.0.10" + container: "emscripten/emsdk:4.0.11" steps: - uses: actions/checkout@v4 - name: Dependencies diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index 235974579..4e2f3de0f 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.0" + "@img/sharp-libvips-darwin-arm64": "1.2.1" }, "files": [ "lib" diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index bb28645bd..c31468361 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.0" + "@img/sharp-libvips-darwin-x64": "1.2.1" }, "files": [ "lib" diff --git a/npm/linux-arm/package.json b/npm/linux-arm/package.json index f8408346d..848b5e6ca 100644 --- a/npm/linux-arm/package.json +++ b/npm/linux-arm/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.0" + "@img/sharp-libvips-linux-arm": "1.2.1" }, "files": [ "lib" diff --git a/npm/linux-arm64/package.json b/npm/linux-arm64/package.json index 8cac11535..24e92a3e0 100644 --- a/npm/linux-arm64/package.json +++ b/npm/linux-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.0" + "@img/sharp-libvips-linux-arm64": "1.2.1" }, "files": [ "lib" diff --git a/npm/linux-ppc64/package.json b/npm/linux-ppc64/package.json index 495440149..b1dacbd62 100644 --- a/npm/linux-ppc64/package.json +++ b/npm/linux-ppc64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.2.0" + "@img/sharp-libvips-linux-ppc64": "1.2.1" }, "files": [ "lib" diff --git a/npm/linux-s390x/package.json b/npm/linux-s390x/package.json index 7294d7173..df654afef 100644 --- a/npm/linux-s390x/package.json +++ b/npm/linux-s390x/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.2.0" + "@img/sharp-libvips-linux-s390x": "1.2.1" }, "files": [ "lib" diff --git a/npm/linux-x64/package.json b/npm/linux-x64/package.json index 709c3a306..bcbacc70b 100644 --- a/npm/linux-x64/package.json +++ b/npm/linux-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.0" + "@img/sharp-libvips-linux-x64": "1.2.1" }, "files": [ "lib" diff --git a/npm/linuxmusl-arm64/package.json b/npm/linuxmusl-arm64/package.json index a5b0bb6bd..b98c1d87c 100644 --- a/npm/linuxmusl-arm64/package.json +++ b/npm/linuxmusl-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.0" + "@img/sharp-libvips-linuxmusl-arm64": "1.2.1" }, "files": [ "lib" diff --git a/npm/linuxmusl-x64/package.json b/npm/linuxmusl-x64/package.json index 1e1db57d4..2133caec8 100644 --- a/npm/linuxmusl-x64/package.json +++ b/npm/linuxmusl-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.0" + "@img/sharp-libvips-linuxmusl-x64": "1.2.1" }, "files": [ "lib" diff --git a/npm/wasm32/package.json b/npm/wasm32/package.json index fcf0d3b39..9e4f518d1 100644 --- a/npm/wasm32/package.json +++ b/npm/wasm32/package.json @@ -31,7 +31,7 @@ "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "dependencies": { - "@emnapi/runtime": "^1.4.4" + "@emnapi/runtime": "^1.4.5" }, "cpu": [ "wasm32" diff --git a/package.json b/package.json index 9262ac094..85f72e8b2 100644 --- a/package.json +++ b/package.json @@ -143,15 +143,15 @@ "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.3", "@img/sharp-darwin-x64": "0.34.3", - "@img/sharp-libvips-darwin-arm64": "1.2.0", - "@img/sharp-libvips-darwin-x64": "1.2.0", - "@img/sharp-libvips-linux-arm": "1.2.0", - "@img/sharp-libvips-linux-arm64": "1.2.0", - "@img/sharp-libvips-linux-ppc64": "1.2.0", - "@img/sharp-libvips-linux-s390x": "1.2.0", - "@img/sharp-libvips-linux-x64": "1.2.0", - "@img/sharp-libvips-linuxmusl-arm64": "1.2.0", - "@img/sharp-libvips-linuxmusl-x64": "1.2.0", + "@img/sharp-libvips-darwin-arm64": "1.2.1", + "@img/sharp-libvips-darwin-x64": "1.2.1", + "@img/sharp-libvips-linux-arm": "1.2.1", + "@img/sharp-libvips-linux-arm64": "1.2.1", + "@img/sharp-libvips-linux-ppc64": "1.2.1", + "@img/sharp-libvips-linux-s390x": "1.2.1", + "@img/sharp-libvips-linux-x64": "1.2.1", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.1", + "@img/sharp-libvips-linuxmusl-x64": "1.2.1", "@img/sharp-linux-arm": "0.34.3", "@img/sharp-linux-arm64": "0.34.3", "@img/sharp-linux-ppc64": "0.34.3", @@ -165,22 +165,22 @@ "@img/sharp-win32-x64": "0.34.3" }, "devDependencies": { - "@emnapi/runtime": "^1.4.4", - "@img/sharp-libvips-dev": "1.2.0", - "@img/sharp-libvips-dev-wasm32": "1.2.0", - "@img/sharp-libvips-win32-arm64": "1.2.0", - "@img/sharp-libvips-win32-ia32": "1.2.0", - "@img/sharp-libvips-win32-x64": "1.2.0", + "@emnapi/runtime": "^1.4.5", + "@img/sharp-libvips-dev": "1.2.1", + "@img/sharp-libvips-dev-wasm32": "1.2.1", + "@img/sharp-libvips-win32-arm64": "1.2.1", + "@img/sharp-libvips-win32-ia32": "1.2.1", + "@img/sharp-libvips-win32-x64": "1.2.1", "@types/node": "*", "cc": "^3.0.1", - "emnapi": "^1.4.4", + "emnapi": "^1.4.5", "exif-reader": "^2.0.2", "extract-zip": "^2.0.1", "icc": "^3.0.0", - "jsdoc-to-markdown": "^9.1.1", + "jsdoc-to-markdown": "^9.1.2", "license-checker": "^25.0.1", "mocha": "^11.7.1", - "node-addon-api": "^8.4.0", + "node-addon-api": "^8.5.0", "node-gyp": "^11.2.0", "nyc": "^17.1.0", "semistandard": "^17.0.0", diff --git a/test/unit/libvips.js b/test/unit/libvips.js index 770acf61c..15042da91 100644 --- a/test/unit/libvips.js +++ b/test/unit/libvips.js @@ -179,7 +179,7 @@ describe('libvips binaries', function () { process.env.npm_config_arch = 's390x'; process.env.npm_config_libc = ''; const locatorHash = libvips.yarnLocator(); - assert.strictEqual(locatorHash, '30afd744f9'); + assert.strictEqual(locatorHash, '7e40558001'); delete process.env.npm_config_platform; delete process.env.npm_config_arch; delete process.env.npm_config_libc; From fefda85d2db0e516e34e83da05a38fd1e396a288 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Thu, 24 Jul 2025 17:14:27 +0100 Subject: [PATCH 051/115] CI: Upgrade to Debian 12 for ppc64 and s390x Debian 11 has reached EOL on these platforms --- .github/workflows/ci.yml | 4 ++-- docs/src/content/docs/install.md | 4 ++-- npm/linux-ppc64/package.json | 2 +- npm/linux-s390x/package.json | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 56ec651a2..ef2701aa1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -230,14 +230,14 @@ jobs: nodejs_version: "18.17.0" nodejs_version_major: 18 - platform: linux-s390x - distro: bullseye + distro: bookworm run_on_arch: s390x nodejs_arch: s390x nodejs_hostname: nodejs.org nodejs_version: "18.17.0" nodejs_version_major: 18 - platform: linux-ppc64 - distro: bullseye + distro: bookworm run_on_arch: ppc64le nodejs_arch: ppc64le nodejs_hostname: nodejs.org diff --git a/docs/src/content/docs/install.md b/docs/src/content/docs/install.md index 41c18714e..7afc56c62 100644 --- a/docs/src/content/docs/install.md +++ b/docs/src/content/docs/install.md @@ -48,8 +48,8 @@ Ready-compiled sharp and libvips binaries are provided for use on the most commo * macOS ARM64 * Linux ARM (glibc >= 2.31) * Linux ARM64 (glibc >= 2.26, musl >= 1.2.2) -* Linux ppc64 (glibc >= 2.31) -* Linux s390x (glibc >= 2.31) +* Linux ppc64 (glibc >= 2.36) +* Linux s390x (glibc >= 2.36) * Linux x64 (glibc >= 2.26, musl >= 1.2.2, CPU with SSE4.2) * Windows x64 * Windows x86 diff --git a/npm/linux-ppc64/package.json b/npm/linux-ppc64/package.json index b1dacbd62..efac8f0dd 100644 --- a/npm/linux-ppc64/package.json +++ b/npm/linux-ppc64/package.json @@ -32,7 +32,7 @@ "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "config": { - "glibc": ">=2.31" + "glibc": ">=2.36" }, "os": [ "linux" diff --git a/npm/linux-s390x/package.json b/npm/linux-s390x/package.json index df654afef..a26cc0c25 100644 --- a/npm/linux-s390x/package.json +++ b/npm/linux-s390x/package.json @@ -32,7 +32,7 @@ "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "config": { - "glibc": ">=2.31" + "glibc": ">=2.36" }, "os": [ "linux" From 9e20a25c5d490916682da7a0d3151a68837c328f Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Fri, 25 Jul 2025 10:44:00 +0100 Subject: [PATCH 052/115] Prerelease v0.34.4-rc.0 --- npm/darwin-arm64/package.json | 2 +- npm/darwin-x64/package.json | 2 +- npm/linux-arm/package.json | 2 +- npm/linux-arm64/package.json | 2 +- npm/linux-ppc64/package.json | 2 +- npm/linux-s390x/package.json | 2 +- npm/linux-x64/package.json | 2 +- npm/linuxmusl-arm64/package.json | 2 +- npm/linuxmusl-x64/package.json | 2 +- npm/package.json | 2 +- npm/wasm32/package.json | 2 +- npm/win32-arm64/package.json | 2 +- npm/win32-ia32/package.json | 2 +- npm/win32-x64/package.json | 2 +- package.json | 28 ++++++++++++++-------------- 15 files changed, 28 insertions(+), 28 deletions(-) diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index 4e2f3de0f..9fc9ca655 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-arm64", - "version": "0.34.3", + "version": "0.34.4-rc.0", "description": "Prebuilt sharp for use with macOS 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index c31468361..5bf105b7e 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-x64", - "version": "0.34.3", + "version": "0.34.4-rc.0", "description": "Prebuilt sharp for use with macOS x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm/package.json b/npm/linux-arm/package.json index 848b5e6ca..b8bdf97da 100644 --- a/npm/linux-arm/package.json +++ b/npm/linux-arm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm", - "version": "0.34.3", + "version": "0.34.4-rc.0", "description": "Prebuilt sharp for use with Linux (glibc) ARM (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm64/package.json b/npm/linux-arm64/package.json index 24e92a3e0..079e0c451 100644 --- a/npm/linux-arm64/package.json +++ b/npm/linux-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm64", - "version": "0.34.3", + "version": "0.34.4-rc.0", "description": "Prebuilt sharp for use with Linux (glibc) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-ppc64/package.json b/npm/linux-ppc64/package.json index efac8f0dd..90a563e95 100644 --- a/npm/linux-ppc64/package.json +++ b/npm/linux-ppc64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-ppc64", - "version": "0.34.3", + "version": "0.34.4-rc.0", "description": "Prebuilt sharp for use with Linux (glibc) ppc64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-s390x/package.json b/npm/linux-s390x/package.json index a26cc0c25..bf9111129 100644 --- a/npm/linux-s390x/package.json +++ b/npm/linux-s390x/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-s390x", - "version": "0.34.3", + "version": "0.34.4-rc.0", "description": "Prebuilt sharp for use with Linux (glibc) s390x", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-x64/package.json b/npm/linux-x64/package.json index bcbacc70b..c0b6513c3 100644 --- a/npm/linux-x64/package.json +++ b/npm/linux-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-x64", - "version": "0.34.3", + "version": "0.34.4-rc.0", "description": "Prebuilt sharp for use with Linux (glibc) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-arm64/package.json b/npm/linuxmusl-arm64/package.json index b98c1d87c..d5da94d05 100644 --- a/npm/linuxmusl-arm64/package.json +++ b/npm/linuxmusl-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-arm64", - "version": "0.34.3", + "version": "0.34.4-rc.0", "description": "Prebuilt sharp for use with Linux (musl) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-x64/package.json b/npm/linuxmusl-x64/package.json index 2133caec8..f53582825 100644 --- a/npm/linuxmusl-x64/package.json +++ b/npm/linuxmusl-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-x64", - "version": "0.34.3", + "version": "0.34.4-rc.0", "description": "Prebuilt sharp for use with Linux (musl) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/package.json b/npm/package.json index f7562ed41..0295044d5 100644 --- a/npm/package.json +++ b/npm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp", - "version": "0.34.3", + "version": "0.34.4-rc.0", "private": "true", "workspaces": [ "darwin-arm64", diff --git a/npm/wasm32/package.json b/npm/wasm32/package.json index 9e4f518d1..ba8996bb8 100644 --- a/npm/wasm32/package.json +++ b/npm/wasm32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-wasm32", - "version": "0.34.3", + "version": "0.34.4-rc.0", "description": "Prebuilt sharp for use with wasm32", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-arm64/package.json b/npm/win32-arm64/package.json index 44ce09acb..dc055ac18 100644 --- a/npm/win32-arm64/package.json +++ b/npm/win32-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-arm64", - "version": "0.34.3", + "version": "0.34.4-rc.0", "description": "Prebuilt sharp for use with Windows 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-ia32/package.json b/npm/win32-ia32/package.json index 3645bce40..2131df2df 100644 --- a/npm/win32-ia32/package.json +++ b/npm/win32-ia32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-ia32", - "version": "0.34.3", + "version": "0.34.4-rc.0", "description": "Prebuilt sharp for use with Windows x86 (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-x64/package.json b/npm/win32-x64/package.json index e2e557193..d55a78704 100644 --- a/npm/win32-x64/package.json +++ b/npm/win32-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-x64", - "version": "0.34.3", + "version": "0.34.4-rc.0", "description": "Prebuilt sharp for use with Windows x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/package.json b/package.json index 85f72e8b2..0371408b4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "sharp", "description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images", - "version": "0.34.3", + "version": "0.34.4-rc.0", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", "contributors": [ @@ -141,8 +141,8 @@ "semver": "^7.7.2" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.3", - "@img/sharp-darwin-x64": "0.34.3", + "@img/sharp-darwin-arm64": "0.34.4-rc.0", + "@img/sharp-darwin-x64": "0.34.4-rc.0", "@img/sharp-libvips-darwin-arm64": "1.2.1", "@img/sharp-libvips-darwin-x64": "1.2.1", "@img/sharp-libvips-linux-arm": "1.2.1", @@ -152,17 +152,17 @@ "@img/sharp-libvips-linux-x64": "1.2.1", "@img/sharp-libvips-linuxmusl-arm64": "1.2.1", "@img/sharp-libvips-linuxmusl-x64": "1.2.1", - "@img/sharp-linux-arm": "0.34.3", - "@img/sharp-linux-arm64": "0.34.3", - "@img/sharp-linux-ppc64": "0.34.3", - "@img/sharp-linux-s390x": "0.34.3", - "@img/sharp-linux-x64": "0.34.3", - "@img/sharp-linuxmusl-arm64": "0.34.3", - "@img/sharp-linuxmusl-x64": "0.34.3", - "@img/sharp-wasm32": "0.34.3", - "@img/sharp-win32-arm64": "0.34.3", - "@img/sharp-win32-ia32": "0.34.3", - "@img/sharp-win32-x64": "0.34.3" + "@img/sharp-linux-arm": "0.34.4-rc.0", + "@img/sharp-linux-arm64": "0.34.4-rc.0", + "@img/sharp-linux-ppc64": "0.34.4-rc.0", + "@img/sharp-linux-s390x": "0.34.4-rc.0", + "@img/sharp-linux-x64": "0.34.4-rc.0", + "@img/sharp-linuxmusl-arm64": "0.34.4-rc.0", + "@img/sharp-linuxmusl-x64": "0.34.4-rc.0", + "@img/sharp-wasm32": "0.34.4-rc.0", + "@img/sharp-win32-arm64": "0.34.4-rc.0", + "@img/sharp-win32-ia32": "0.34.4-rc.0", + "@img/sharp-win32-x64": "0.34.4-rc.0" }, "devDependencies": { "@emnapi/runtime": "^1.4.5", From dda00f63e6c78ff3c47f60c4658a9875883e25ae Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Sat, 26 Jul 2025 23:58:48 +0100 Subject: [PATCH 053/115] CI: Remove frontmatter from release notes --- .github/workflows/ci.yml | 11 ++++++----- .gitignore | 1 + npm/release-notes.js | 9 +++++++++ package.json | 1 + 4 files changed, 17 insertions(+), 5 deletions(-) create mode 100644 npm/release-notes.js diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ef2701aa1..605cea294 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -313,12 +313,13 @@ jobs: path: npm - name: Create npm workspace tarball run: tar -vcaf npm-workspace.tar.xz --directory npm --exclude=from-local-build.js . - - name: Parse semver for tag + - uses: actions/setup-node@v4 if: startsWith(github.ref, 'refs/tags/v') - uses: madhead/semver-utils@v4 - id: semver with: - version: ${{ github.ref_name }} + node-version: "24" + - name: Create release notes + if: startsWith(github.ref, 'refs/tags/v') + run: npm run package-release-notes - name: Create GitHub release for tag if: startsWith(github.ref, 'refs/tags/v') uses: ncipollo/release-action@v1 @@ -327,4 +328,4 @@ jobs: artifactContentType: application/x-xz prerelease: ${{ contains(github.ref, '-rc') }} makeLatest: ${{ !contains(github.ref, '-rc') }} - bodyFile: "docs/src/content/docs/changelog/v${{ steps.semver.outputs.major }}.${{ steps.semver.outputs.minor }}.${{ steps.semver.outputs.patch }}.md" + bodyFile: release-notes.md diff --git a/.gitignore b/.gitignore index 6959cf624..82f73b3f0 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ package-lock.json .firebase .astro docs/dist +release-notes.md diff --git a/npm/release-notes.js b/npm/release-notes.js new file mode 100644 index 000000000..13cc18772 --- /dev/null +++ b/npm/release-notes.js @@ -0,0 +1,9 @@ +const { readFileSync, writeFileSync } = require('node:fs'); + +const { version } = require('./package.json'); +const versionWithoutPreRelease = version.replace(/-rc\.\d+$/, ''); + +const markdown = readFileSync(`./docs/src/content/docs/changelog/v${versionWithoutPreRelease}.md`, 'utf8'); +const markdownWithoutFrontmatter = markdown.replace(/---\n.*?\n---\n+/s, ''); + +writeFileSync('./release-notes.md', markdownWithoutFrontmatter); diff --git a/package.json b/package.json index 0371408b4..faa7da7eb 100644 --- a/package.json +++ b/package.json @@ -101,6 +101,7 @@ "test-leak": "./test/leak/leak.sh", "test-types": "tsd", "package-from-local-build": "node npm/from-local-build.js", + "package-release-notes": "node npm/release-notes.js", "docs-build": "node docs/build.mjs", "docs-serve": "cd docs && npm start", "docs-publish": "cd docs && npm run build && npx firebase-tools deploy --project pixelplumbing --only hosting:pixelplumbing-sharp" From 51d1a49abceb224d8e9d7122f54819904109d581 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Mon, 28 Jul 2025 14:32:52 +0100 Subject: [PATCH 054/115] v0.34.4-rc.1 --- npm/darwin-arm64/package.json | 2 +- npm/darwin-x64/package.json | 2 +- npm/linux-arm/package.json | 2 +- npm/linux-arm64/package.json | 2 +- npm/linux-ppc64/package.json | 2 +- npm/linux-s390x/package.json | 2 +- npm/linux-x64/package.json | 2 +- npm/linuxmusl-arm64/package.json | 2 +- npm/linuxmusl-x64/package.json | 2 +- npm/package.json | 2 +- npm/wasm32/package.json | 2 +- npm/win32-arm64/package.json | 2 +- npm/win32-ia32/package.json | 2 +- npm/win32-x64/package.json | 2 +- package.json | 28 ++++++++++++++-------------- 15 files changed, 28 insertions(+), 28 deletions(-) diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index 9fc9ca655..c75c237cc 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-arm64", - "version": "0.34.4-rc.0", + "version": "0.34.4-rc.1", "description": "Prebuilt sharp for use with macOS 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index 5bf105b7e..3750f6a16 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-x64", - "version": "0.34.4-rc.0", + "version": "0.34.4-rc.1", "description": "Prebuilt sharp for use with macOS x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm/package.json b/npm/linux-arm/package.json index b8bdf97da..395ee7f22 100644 --- a/npm/linux-arm/package.json +++ b/npm/linux-arm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm", - "version": "0.34.4-rc.0", + "version": "0.34.4-rc.1", "description": "Prebuilt sharp for use with Linux (glibc) ARM (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm64/package.json b/npm/linux-arm64/package.json index 079e0c451..06bf7a0e2 100644 --- a/npm/linux-arm64/package.json +++ b/npm/linux-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm64", - "version": "0.34.4-rc.0", + "version": "0.34.4-rc.1", "description": "Prebuilt sharp for use with Linux (glibc) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-ppc64/package.json b/npm/linux-ppc64/package.json index 90a563e95..74fc33aa8 100644 --- a/npm/linux-ppc64/package.json +++ b/npm/linux-ppc64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-ppc64", - "version": "0.34.4-rc.0", + "version": "0.34.4-rc.1", "description": "Prebuilt sharp for use with Linux (glibc) ppc64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-s390x/package.json b/npm/linux-s390x/package.json index bf9111129..8e0661b35 100644 --- a/npm/linux-s390x/package.json +++ b/npm/linux-s390x/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-s390x", - "version": "0.34.4-rc.0", + "version": "0.34.4-rc.1", "description": "Prebuilt sharp for use with Linux (glibc) s390x", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-x64/package.json b/npm/linux-x64/package.json index c0b6513c3..4a8e13199 100644 --- a/npm/linux-x64/package.json +++ b/npm/linux-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-x64", - "version": "0.34.4-rc.0", + "version": "0.34.4-rc.1", "description": "Prebuilt sharp for use with Linux (glibc) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-arm64/package.json b/npm/linuxmusl-arm64/package.json index d5da94d05..9897991bd 100644 --- a/npm/linuxmusl-arm64/package.json +++ b/npm/linuxmusl-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-arm64", - "version": "0.34.4-rc.0", + "version": "0.34.4-rc.1", "description": "Prebuilt sharp for use with Linux (musl) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-x64/package.json b/npm/linuxmusl-x64/package.json index f53582825..63a85beb5 100644 --- a/npm/linuxmusl-x64/package.json +++ b/npm/linuxmusl-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-x64", - "version": "0.34.4-rc.0", + "version": "0.34.4-rc.1", "description": "Prebuilt sharp for use with Linux (musl) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/package.json b/npm/package.json index 0295044d5..2cfe6a0e3 100644 --- a/npm/package.json +++ b/npm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp", - "version": "0.34.4-rc.0", + "version": "0.34.4-rc.1", "private": "true", "workspaces": [ "darwin-arm64", diff --git a/npm/wasm32/package.json b/npm/wasm32/package.json index ba8996bb8..486d23c99 100644 --- a/npm/wasm32/package.json +++ b/npm/wasm32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-wasm32", - "version": "0.34.4-rc.0", + "version": "0.34.4-rc.1", "description": "Prebuilt sharp for use with wasm32", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-arm64/package.json b/npm/win32-arm64/package.json index dc055ac18..db152c7f6 100644 --- a/npm/win32-arm64/package.json +++ b/npm/win32-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-arm64", - "version": "0.34.4-rc.0", + "version": "0.34.4-rc.1", "description": "Prebuilt sharp for use with Windows 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-ia32/package.json b/npm/win32-ia32/package.json index 2131df2df..d9a3e2ab3 100644 --- a/npm/win32-ia32/package.json +++ b/npm/win32-ia32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-ia32", - "version": "0.34.4-rc.0", + "version": "0.34.4-rc.1", "description": "Prebuilt sharp for use with Windows x86 (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-x64/package.json b/npm/win32-x64/package.json index d55a78704..8430d7930 100644 --- a/npm/win32-x64/package.json +++ b/npm/win32-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-x64", - "version": "0.34.4-rc.0", + "version": "0.34.4-rc.1", "description": "Prebuilt sharp for use with Windows x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/package.json b/package.json index faa7da7eb..b06847daa 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "sharp", "description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images", - "version": "0.34.4-rc.0", + "version": "0.34.4-rc.1", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", "contributors": [ @@ -142,8 +142,8 @@ "semver": "^7.7.2" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.4-rc.0", - "@img/sharp-darwin-x64": "0.34.4-rc.0", + "@img/sharp-darwin-arm64": "0.34.4-rc.1", + "@img/sharp-darwin-x64": "0.34.4-rc.1", "@img/sharp-libvips-darwin-arm64": "1.2.1", "@img/sharp-libvips-darwin-x64": "1.2.1", "@img/sharp-libvips-linux-arm": "1.2.1", @@ -153,17 +153,17 @@ "@img/sharp-libvips-linux-x64": "1.2.1", "@img/sharp-libvips-linuxmusl-arm64": "1.2.1", "@img/sharp-libvips-linuxmusl-x64": "1.2.1", - "@img/sharp-linux-arm": "0.34.4-rc.0", - "@img/sharp-linux-arm64": "0.34.4-rc.0", - "@img/sharp-linux-ppc64": "0.34.4-rc.0", - "@img/sharp-linux-s390x": "0.34.4-rc.0", - "@img/sharp-linux-x64": "0.34.4-rc.0", - "@img/sharp-linuxmusl-arm64": "0.34.4-rc.0", - "@img/sharp-linuxmusl-x64": "0.34.4-rc.0", - "@img/sharp-wasm32": "0.34.4-rc.0", - "@img/sharp-win32-arm64": "0.34.4-rc.0", - "@img/sharp-win32-ia32": "0.34.4-rc.0", - "@img/sharp-win32-x64": "0.34.4-rc.0" + "@img/sharp-linux-arm": "0.34.4-rc.1", + "@img/sharp-linux-arm64": "0.34.4-rc.1", + "@img/sharp-linux-ppc64": "0.34.4-rc.1", + "@img/sharp-linux-s390x": "0.34.4-rc.1", + "@img/sharp-linux-x64": "0.34.4-rc.1", + "@img/sharp-linuxmusl-arm64": "0.34.4-rc.1", + "@img/sharp-linuxmusl-x64": "0.34.4-rc.1", + "@img/sharp-wasm32": "0.34.4-rc.1", + "@img/sharp-win32-arm64": "0.34.4-rc.1", + "@img/sharp-win32-ia32": "0.34.4-rc.1", + "@img/sharp-win32-x64": "0.34.4-rc.1" }, "devDependencies": { "@emnapi/runtime": "^1.4.5", From cd337e4de3381397b7c345b4a4edbffc69c79f8a Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Mon, 18 Aug 2025 10:24:38 +0100 Subject: [PATCH 055/115] Docs: extractChannel output colourspace is b-w or grey16 --- docs/src/content/docs/api-channel.md | 2 ++ lib/channel.js | 2 ++ 2 files changed, 4 insertions(+) diff --git a/docs/src/content/docs/api-channel.md b/docs/src/content/docs/api-channel.md index 298083487..fb8ed3339 100644 --- a/docs/src/content/docs/api-channel.md +++ b/docs/src/content/docs/api-channel.md @@ -61,6 +61,8 @@ const rgba = await sharp(rgb) Extract a single channel from a multi-channel image. +The output colourspace will be either `b-w` (8-bit) or `grey16` (16-bit). + **Throws**: diff --git a/lib/channel.js b/lib/channel.js index 46bce3d57..b6381ae9b 100644 --- a/lib/channel.js +++ b/lib/channel.js @@ -74,6 +74,8 @@ function ensureAlpha (alpha) { /** * Extract a single channel from a multi-channel image. * + * The output colourspace will be either `b-w` (8-bit) or `grey16` (16-bit). + * * @example * // green.jpg is a greyscale image containing the green channel of the input * await sharp(input) From 8607ff2f4a5d0f523f57c589378256a626b62c97 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Mon, 18 Aug 2025 10:33:32 +0100 Subject: [PATCH 056/115] Tests: remove extraneous use of toColourspace --- test/unit/extractChannel.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/unit/extractChannel.js b/test/unit/extractChannel.js index 59c53600d..2d19588ae 100644 --- a/test/unit/extractChannel.js +++ b/test/unit/extractChannel.js @@ -82,7 +82,6 @@ describe('Image channel extraction', function () { const output = fixtures.path('output.extract-alpha-2-channel.png'); sharp(fixtures.inputPngWithGreyAlpha) .extractChannel('alpha') - .toColourspace('b-w') .toFile(output, function (err, info) { if (err) throw err; assert.strictEqual(1, info.channels); From c01e272db522a8b7d174bd3be7400a4a87f08702 Mon Sep 17 00:00:00 2001 From: Bayan Bennett <16971062+BayanBennett@users.noreply.github.com> Date: Thu, 21 Aug 2025 01:35:41 -0700 Subject: [PATCH 057/115] TypeScript: Ensure KernelEnum includes linear (#4441) --- lib/index.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/index.d.ts b/lib/index.d.ts index 198e443e5..412363450 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1784,6 +1784,7 @@ declare namespace sharp { interface KernelEnum { nearest: 'nearest'; cubic: 'cubic'; + linear: 'linear'; mitchell: 'mitchell'; lanczos2: 'lanczos2'; lanczos3: 'lanczos3'; From 4164705113ea06d62a27b2ebdb20f9a9d6c5ece5 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Fri, 22 Aug 2025 20:01:18 +0100 Subject: [PATCH 058/115] Bump devDeps --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index b06847daa..59e3b420b 100644 --- a/package.json +++ b/package.json @@ -182,11 +182,11 @@ "license-checker": "^25.0.1", "mocha": "^11.7.1", "node-addon-api": "^8.5.0", - "node-gyp": "^11.2.0", + "node-gyp": "^11.4.1", "nyc": "^17.1.0", "semistandard": "^17.0.0", "tar-fs": "^3.1.0", - "tsd": "^0.32.0" + "tsd": "^0.33.0" }, "license": "Apache-2.0", "engines": { From 660bbdb1c0789fb4fcf99e51c2a3ad84c7026782 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Fri, 22 Aug 2025 20:01:46 +0100 Subject: [PATCH 059/115] Docs: changelog for #4441 --- docs/src/content/docs/changelog/v0.34.4.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/src/content/docs/changelog/v0.34.4.md b/docs/src/content/docs/changelog/v0.34.4.md index 9855b09b1..54d9d0eb8 100644 --- a/docs/src/content/docs/changelog/v0.34.4.md +++ b/docs/src/content/docs/changelog/v0.34.4.md @@ -8,3 +8,7 @@ slug: changelog/v0.34.4 * Ensure `autoOrient` removes existing metadata after shrink-on-load. [#4431](https://github.com/lovell/sharp/issues/4431) + +* TypeScript: Ensure `KernelEnum` includes `linear`. + [#4441](https://github.com/lovell/sharp/pull/4441) + [@BayanBennett](https://github.com/BayanBennett) From b77c97067a93659d4599e4dba1ab7f698a846e35 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Tue, 26 Aug 2025 10:28:16 +0200 Subject: [PATCH 060/115] Remove `-sTEXTDECODER=0` linker flag See: emscripten-core/emscripten@b490c44 --- src/binding.gyp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/binding.gyp b/src/binding.gyp index ae38a29f3..4cbda4a86 100644 --- a/src/binding.gyp +++ b/src/binding.gyp @@ -210,7 +210,6 @@ '-sENVIRONMENT=node', '-sEXPORTED_FUNCTIONS=["emnapiInit", "_vips_shutdown", "_uv_library_shutdown"]', '-sNODERAWFS', - '-sTEXTDECODER=0', '-sWASM_ASYNC_COMPILATION=0', '-sWASM_BIGINT' ], From 16e248f93ef0012a5a0b5c9915ae43de5502342a Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Tue, 26 Aug 2025 10:29:31 +0200 Subject: [PATCH 061/115] Remove `-sWASM_BIGINT` linker flag Enabled by default since Emscripten 4.0.0, see commit: emscripten-core/emscripten@93d2f8d --- src/binding.gyp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/binding.gyp b/src/binding.gyp index 4cbda4a86..ca3812b83 100644 --- a/src/binding.gyp +++ b/src/binding.gyp @@ -210,8 +210,7 @@ '-sENVIRONMENT=node', '-sEXPORTED_FUNCTIONS=["emnapiInit", "_vips_shutdown", "_uv_library_shutdown"]', '-sNODERAWFS', - '-sWASM_ASYNC_COMPILATION=0', - '-sWASM_BIGINT' + '-sWASM_ASYNC_COMPILATION=0' ], 'libraries': [ ' Date: Tue, 26 Aug 2025 10:31:12 +0200 Subject: [PATCH 062/115] Remove `-sNODEJS_CATCH_EXIT=0` linker flag Disabled by default since Emscripten 3.1.65, see commit: emscripten-core/emscripten@cd831e7 --- src/emscripten/common.gypi | 1 - 1 file changed, 1 deletion(-) diff --git a/src/emscripten/common.gypi b/src/emscripten/common.gypi index 125a52659..714affe59 100644 --- a/src/emscripten/common.gypi +++ b/src/emscripten/common.gypi @@ -19,7 +19,6 @@ '-sAUTO_JS_LIBRARIES=0', '-sAUTO_NATIVE_LIBRARIES=0', '-sDEFAULT_TO_CXX=0', - '-sNODEJS_CATCH_EXIT=0', '-sNODEJS_CATCH_REJECTION=0' ], 'defines': [ From 40be212bba30864391c5afdaaa90369d482e7cff Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Tue, 26 Aug 2025 10:33:58 +0200 Subject: [PATCH 063/115] Use modern -s command line lists See: emscripten-core/emscripten@bb615a9 --- src/binding.gyp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/binding.gyp b/src/binding.gyp index ca3812b83..18f8efd1f 100644 --- a/src/binding.gyp +++ b/src/binding.gyp @@ -208,7 +208,7 @@ '-Oz', '-sALLOW_MEMORY_GROWTH', '-sENVIRONMENT=node', - '-sEXPORTED_FUNCTIONS=["emnapiInit", "_vips_shutdown", "_uv_library_shutdown"]', + '-sEXPORTED_FUNCTIONS=emnapiInit,_vips_shutdown,_uv_library_shutdown', '-sNODERAWFS', '-sWASM_ASYNC_COMPILATION=0' ], From 0e4b648593732df061733a0d152bb7e70fed753f Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Fri, 29 Aug 2025 23:29:24 +0100 Subject: [PATCH 064/115] Ensure unlimited flag is passed to tiffload #4446 --- docs/src/content/docs/changelog/v0.34.4.md | 3 +++ src/common.cc | 1 + 2 files changed, 4 insertions(+) diff --git a/docs/src/content/docs/changelog/v0.34.4.md b/docs/src/content/docs/changelog/v0.34.4.md index 54d9d0eb8..c3aa1af75 100644 --- a/docs/src/content/docs/changelog/v0.34.4.md +++ b/docs/src/content/docs/changelog/v0.34.4.md @@ -12,3 +12,6 @@ slug: changelog/v0.34.4 * TypeScript: Ensure `KernelEnum` includes `linear`. [#4441](https://github.com/lovell/sharp/pull/4441) [@BayanBennett](https://github.com/BayanBennett) + +* Ensure `unlimited` flag is passed upstream when reading TIFF images. + [#4446](https://github.com/lovell/sharp/issues/4446) diff --git a/src/common.cc b/src/common.cc index 42e4a442d..2688bd730 100644 --- a/src/common.cc +++ b/src/common.cc @@ -396,6 +396,7 @@ namespace sharp { imageType == ImageType::JPEG || imageType == ImageType::PNG || imageType == ImageType::SVG || + imageType == ImageType::TIFF || imageType == ImageType::HEIF; } From c1e33de33c168629bd18accc5f68b07e2b389291 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Mon, 1 Sep 2025 12:37:16 +0100 Subject: [PATCH 065/115] CI: Automate npm publish-with-provenance Temporarily flagged with dry-run for now --- .github/workflows/ci.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 605cea294..36786a20d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -300,6 +300,7 @@ jobs: release: permissions: contents: write + id-token: write runs-on: ubuntu-24.04 needs: - build-native @@ -314,11 +315,9 @@ jobs: - name: Create npm workspace tarball run: tar -vcaf npm-workspace.tar.xz --directory npm --exclude=from-local-build.js . - uses: actions/setup-node@v4 - if: startsWith(github.ref, 'refs/tags/v') with: - node-version: "24" + node-version: '24' - name: Create release notes - if: startsWith(github.ref, 'refs/tags/v') run: npm run package-release-notes - name: Create GitHub release for tag if: startsWith(github.ref, 'refs/tags/v') @@ -329,3 +328,9 @@ jobs: prerelease: ${{ contains(github.ref, '-rc') }} makeLatest: ${{ !contains(github.ref, '-rc') }} bodyFile: release-notes.md + - name: Publish platform-specific npm packages + if: startsWith(github.ref, 'refs/tags/v') + run: cd npm && npm publish --workspaces --tag=${{ contains(github.ref, '-rc') && 'next' || 'latest' }} --dry-run + - name: Publish sharp npm package + if: startsWith(github.ref, 'refs/tags/v') + run: npm publish --tag=${{ contains(github.ref, '-rc') && 'next' || 'latest' }} --dry-run From 1835288ab8aa68a147a771eff4c17888a54bd3a6 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Mon, 8 Sep 2025 11:10:51 +0100 Subject: [PATCH 066/115] Docs: remove frame clutter from code samples --- docs/package.json | 4 ++-- docs/src/content/docs/index.md | 2 +- docs/src/content/docs/install.md | 36 ++++++++++++++-------------- docs/src/content/docs/performance.md | 6 ++--- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/docs/package.json b/docs/package.json index c433dea07..89bd0f291 100644 --- a/docs/package.json +++ b/docs/package.json @@ -11,8 +11,8 @@ "astro": "astro" }, "dependencies": { - "@astrojs/starlight": "^0.34.6", - "astro": "^5.11.1", + "@astrojs/starlight": "^0.35.2", + "astro": "^5.13.5", "starlight-auto-sidebar": "^0.1.2" } } diff --git a/docs/src/content/docs/index.md b/docs/src/content/docs/index.md index 4c04edd88..3ba704f43 100644 --- a/docs/src/content/docs/index.md +++ b/docs/src/content/docs/index.md @@ -25,7 +25,7 @@ rotation, extraction, compositing and gamma correction are available. Most modern macOS, Windows and Linux systems do not require any additional install or runtime dependencies. -```sh +```sh frame="none" npm install sharp ``` diff --git a/docs/src/content/docs/install.md b/docs/src/content/docs/install.md index 7afc56c62..329083994 100644 --- a/docs/src/content/docs/install.md +++ b/docs/src/content/docs/install.md @@ -12,11 +12,11 @@ If a package manager lockfile must support multiple platforms, please see the [cross-platform](#cross-platform) section to help decide which package manager is appropriate. -```sh +```sh frame="none" npm install sharp ``` -```sh +```sh frame="none" pnpm add sharp ``` @@ -24,15 +24,15 @@ When using `pnpm`, you may need to add `sharp` to [ignoredBuiltDependencies](https://pnpm.io/settings#ignoredbuiltdependencies) to silence warnings. -```sh +```sh frame="none" yarn add sharp ``` -```sh +```sh frame="none" bun add sharp ``` -```sh +```sh frame="none" deno run --allow-ffi ... ``` @@ -75,7 +75,7 @@ npm `package-lock.json` files shared by multiple platforms can cause installatio Provides limited support via `--os`, `--cpu` and `--libc` flags. To support macOS with Intel x64 and ARM64 CPUs: -```sh +```sh frame="none" npm install --cpu=x64 --os=darwin sharp npm install --cpu=arm64 --os=darwin sharp ``` @@ -83,7 +83,7 @@ npm install --cpu=arm64 --os=darwin sharp When the cross-target is Linux, the C standard library must be specified. To support glibc (e.g. Debian) and musl (e.g. Alpine) Linux with Intel x64 CPUs: -```sh +```sh frame="none" npm install --cpu=x64 --os=linux --libc=glibc sharp npm install --cpu=x64 --os=linux --libc=musl sharp ``` @@ -129,7 +129,7 @@ Building from source requires: There is an install-time check for these dependencies. If `node-addon-api` or `node-gyp` cannot be found, try adding them via: -```sh +```sh frame="none" npm install --save node-addon-api node-gyp ``` @@ -152,7 +152,7 @@ Native text rendering is unsupported. [Tile-based output](/api-output#tile) is unsupported. -```sh +```sh frame="none" npm install --cpu=wasm32 sharp ``` @@ -160,11 +160,11 @@ npm install --cpu=wasm32 sharp The `vips` package must be installed before `npm install` is run. -```sh +```sh frame="none" pkg install -y pkgconf vips ``` -```sh +```sh frame="none" cd /usr/ports/graphics/vips/ && make install clean ``` @@ -213,7 +213,7 @@ Ensure sharp is excluded from bundling via the [externals](https://webpack.js.org/configuration/externals/) configuration. -```js +```js frame="none" externals: { 'sharp': 'commonjs sharp' } @@ -225,7 +225,7 @@ Ensure sharp is excluded from bundling via the [external](https://esbuild.github.io/api/#external) configuration. -```js +```js frame="none" buildSync({ entryPoints: ['app.js'], bundle: true, @@ -234,14 +234,14 @@ buildSync({ }) ``` -```sh +```sh frame="none" esbuild app.js --bundle --platform=node --external:sharp ``` For `serverless-esbuild`, ensure platform-specific binaries are installed via the `serverless.yml` configuration. -```yaml +```yaml frame="none" custom: esbuild: external: @@ -259,7 +259,7 @@ Ensure `sharp` is unpacked from the ASAR archive file using the [asarUnpack](https://www.electron.build/app-builder-lib.interface.platformspecificbuildoptions#asarunpack) option. -```json +```json frame="none" { "build": { "asar": true, @@ -277,7 +277,7 @@ Ensure `sharp` is unpacked from the ASAR archive file using the [unpack](https://js.electronforge.io/interfaces/_electron_forge_maker_squirrel.InternalOptions.Options.html#asar) option. -```json +```json frame="none" { "packagerConfig": { "asar": { @@ -297,7 +297,7 @@ Ensure `sharp` is excluded from bundling via the [build.rollupOptions](https://vitejs.dev/config/build-options.html) configuration. -```js +```js frame="none" import { defineConfig } from 'vite'; export default defineConfig({ diff --git a/docs/src/content/docs/performance.md b/docs/src/content/docs/performance.md index 0c0344aaa..9b5001bcd 100644 --- a/docs/src/content/docs/performance.md +++ b/docs/src/content/docs/performance.md @@ -13,7 +13,7 @@ environment variable, which defaults to 4. When using more than 4 physical CPU cores, set this environment variable before the Node.js process starts to increase the thread pool size. -```sh +```sh frame="none" export UV_THREADPOOL_SIZE="$(lscpu -p | egrep -v "^#" | sort -u -t, -k 2,4 | wc -l)" ``` @@ -28,7 +28,7 @@ To reduce memory fragmentation when using the default Linux glibc memory allocat [`MALLOC_ARENA_MAX`](https://www.gnu.org/software/libc/manual/html_node/Memory-Allocation-Tunables.html) environment variable before the Node.js process starts to reduce the number of memory pools. -```sh +```sh frame="none" export MALLOC_ARENA_MAX="2" ``` @@ -130,7 +130,7 @@ Note: jimp does not support premultiply/unpremultiply. Requires Docker. -```sh +```sh frame="none" git clone https://github.com/lovell/sharp.git cd sharp/test/bench ./run-with-docker.sh From c270455007d34d8e7ffc5a94a884475ab7f734c6 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Wed, 10 Sep 2025 08:43:47 +0100 Subject: [PATCH 067/115] Bump deps --- npm/wasm32/package.json | 2 +- package.json | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/npm/wasm32/package.json b/npm/wasm32/package.json index 486d23c99..580bc14f8 100644 --- a/npm/wasm32/package.json +++ b/npm/wasm32/package.json @@ -31,7 +31,7 @@ "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "dependencies": { - "@emnapi/runtime": "^1.4.5" + "@emnapi/runtime": "^1.5.0" }, "cpu": [ "wasm32" diff --git a/package.json b/package.json index 59e3b420b..f8853e922 100644 --- a/package.json +++ b/package.json @@ -166,7 +166,7 @@ "@img/sharp-win32-x64": "0.34.4-rc.1" }, "devDependencies": { - "@emnapi/runtime": "^1.4.5", + "@emnapi/runtime": "^1.5.0", "@img/sharp-libvips-dev": "1.2.1", "@img/sharp-libvips-dev-wasm32": "1.2.1", "@img/sharp-libvips-win32-arm64": "1.2.1", @@ -174,15 +174,15 @@ "@img/sharp-libvips-win32-x64": "1.2.1", "@types/node": "*", "cc": "^3.0.1", - "emnapi": "^1.4.5", + "emnapi": "^1.5.0", "exif-reader": "^2.0.2", "extract-zip": "^2.0.1", "icc": "^3.0.0", "jsdoc-to-markdown": "^9.1.2", "license-checker": "^25.0.1", - "mocha": "^11.7.1", + "mocha": "^11.7.2", "node-addon-api": "^8.5.0", - "node-gyp": "^11.4.1", + "node-gyp": "^11.4.2", "nyc": "^17.1.0", "semistandard": "^17.0.0", "tar-fs": "^3.1.0", From 45f871790057017a42647d3a47f925a84541c9c5 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Wed, 10 Sep 2025 08:55:14 +0100 Subject: [PATCH 068/115] Upgrade color to latest version via CommonJS wrapper package Allows continued support of non-ESM runtimes - see #4450 --- lib/colour.js | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/colour.js b/lib/colour.js index ad283830e..e17b77bd2 100644 --- a/lib/colour.js +++ b/lib/colour.js @@ -3,7 +3,7 @@ 'use strict'; -const color = require('color'); +const color = require('@img/colour'); const is = require('./is'); /** diff --git a/package.json b/package.json index f8853e922..1ce6b5aa3 100644 --- a/package.json +++ b/package.json @@ -137,7 +137,7 @@ "vips" ], "dependencies": { - "color": "^4.2.3", + "@img/colour": "^1.0.0", "detect-libc": "^2.0.4", "semver": "^7.7.2" }, From 43b579c903570cc381fe08cf75de722080f09b34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Nison?= Date: Fri, 12 Sep 2025 12:15:04 +0200 Subject: [PATCH 069/115] Add sharp-libvips rpath for yarn v5 support (#4452) This should future proof sharp against upcoming changes in yarn's plug-n-play filesystem layout. --- src/binding.gyp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/binding.gyp b/src/binding.gyp index 18f8efd1f..c4ec70cc0 100644 --- a/src/binding.gyp +++ b/src/binding.gyp @@ -168,6 +168,7 @@ # Ensure runtime linking is relative to sharp.node '-Wl,-rpath,\'@loader_path/../../sharp-libvips-<(platform_and_arch)/lib\'', '-Wl,-rpath,\'@loader_path/../../../sharp-libvips-<(platform_and_arch)/<(sharp_libvips_version)/lib\'', + '-Wl,-rpath,\'@loader_path/../node_modules/@img/sharp-libvips-<(platform_and_arch)/lib\'', '-Wl,-rpath,\'@loader_path/../../node_modules/@img/sharp-libvips-<(platform_and_arch)/lib\'', '-Wl,-rpath,\'@loader_path/../../../node_modules/@img/sharp-libvips-<(platform_and_arch)/lib\'', '-Wl,-rpath,\'@loader_path/../../../../../@img-sharp-libvips-<(platform_and_arch)-npm-<(sharp_libvips_version)-<(sharp_libvips_yarn_locator)/node_modules/@img/sharp-libvips-<(platform_and_arch)/lib\'' From 23a0e81d982d41a6d113529fe478927d86d96389 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Fri, 12 Sep 2025 11:50:16 +0100 Subject: [PATCH 070/115] Docs: changelog and credit for #4452 --- docs/public/humans.txt | 3 +++ docs/src/content/docs/changelog/v0.34.4.md | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/docs/public/humans.txt b/docs/public/humans.txt index 327f55321..7119152ab 100644 --- a/docs/public/humans.txt +++ b/docs/public/humans.txt @@ -323,3 +323,6 @@ GitHub: https://github.com/hans00 Name: Thibaut Patel GitHub: https://github.com/tpatel + +Name: Maël Nison +GitHub: https://github.com/arcanis diff --git a/docs/src/content/docs/changelog/v0.34.4.md b/docs/src/content/docs/changelog/v0.34.4.md index c3aa1af75..d60b52707 100644 --- a/docs/src/content/docs/changelog/v0.34.4.md +++ b/docs/src/content/docs/changelog/v0.34.4.md @@ -15,3 +15,7 @@ slug: changelog/v0.34.4 * Ensure `unlimited` flag is passed upstream when reading TIFF images. [#4446](https://github.com/lovell/sharp/issues/4446) + +* Add sharp-libvips rpath for yarn v5 support. + [#4452](https://github.com/lovell/sharp/pull/4452) + [@arcanis](https://github.com/arcanis) From d8686e7c64824de16c17db30acdf69d4012e5ca2 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Fri, 12 Sep 2025 12:33:59 +0100 Subject: [PATCH 071/115] Ensure Electron support for images with XMP metadata #4451 --- docs/src/content/docs/changelog/v0.34.4.md | 3 +++ src/metadata.cc | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/src/content/docs/changelog/v0.34.4.md b/docs/src/content/docs/changelog/v0.34.4.md index d60b52707..8adf526b3 100644 --- a/docs/src/content/docs/changelog/v0.34.4.md +++ b/docs/src/content/docs/changelog/v0.34.4.md @@ -16,6 +16,9 @@ slug: changelog/v0.34.4 * Ensure `unlimited` flag is passed upstream when reading TIFF images. [#4446](https://github.com/lovell/sharp/issues/4446) +* Support Electron memory cage when reading XMP metadata (regression in 0.34.3). + [#4451](https://github.com/lovell/sharp/issues/4451) + * Add sharp-libvips rpath for yarn v5 support. [#4452](https://github.com/lovell/sharp/pull/4452) [@arcanis](https://github.com/arcanis) diff --git a/src/metadata.cc b/src/metadata.cc index 703199106..788b71298 100644 --- a/src/metadata.cc +++ b/src/metadata.cc @@ -261,11 +261,11 @@ class MetadataWorker : public Napi::AsyncWorker { info.Set("iptc", Napi::Buffer::NewOrCopy(env, baton->iptc, baton->iptcLength, sharp::FreeCallback)); } if (baton->xmpLength > 0) { - info.Set("xmp", Napi::Buffer::NewOrCopy(env, baton->xmp, baton->xmpLength, sharp::FreeCallback)); if (g_utf8_validate(static_cast(baton->xmp), baton->xmpLength, nullptr)) { info.Set("xmpAsString", Napi::String::New(env, static_cast(baton->xmp), baton->xmpLength)); } + info.Set("xmp", Napi::Buffer::NewOrCopy(env, baton->xmp, baton->xmpLength, sharp::FreeCallback)); } if (baton->tifftagPhotoshopLength > 0) { info.Set("tifftagPhotoshop", From 6d4d44e2fa8a2924645ce681d5740e3e910e9311 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Sat, 13 Sep 2025 13:37:35 +0100 Subject: [PATCH 072/115] Docs: improve FreeBSD build-from-source install help --- docs/src/content/docs/install.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/src/content/docs/install.md b/docs/src/content/docs/install.md index 329083994..b4d1d5a86 100644 --- a/docs/src/content/docs/install.md +++ b/docs/src/content/docs/install.md @@ -158,7 +158,8 @@ npm install --cpu=wasm32 sharp ## FreeBSD -The `vips` package must be installed before `npm install` is run. +The `vips` package must be installed before `npm install` is run, +as well as the additional [building from source](#building-from-source) dependencies. ```sh frame="none" pkg install -y pkgconf vips From 93b814f849b8e2789628ccf70fd9d2bd19bb4ba5 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Sun, 14 Sep 2025 12:22:27 +0100 Subject: [PATCH 073/115] Upgrade to libvips v8.17.2 --- .github/workflows/ci.yml | 2 +- docs/src/content/docs/changelog/v0.34.4.md | 2 ++ npm/darwin-arm64/package.json | 2 +- npm/darwin-x64/package.json | 2 +- npm/linux-arm/package.json | 2 +- npm/linux-arm64/package.json | 2 +- npm/linux-ppc64/package.json | 2 +- npm/linux-s390x/package.json | 2 +- npm/linux-x64/package.json | 2 +- npm/linuxmusl-arm64/package.json | 2 +- npm/linuxmusl-x64/package.json | 2 +- package.json | 30 +++++++++++----------- src/common.h | 4 +-- test/unit/libvips.js | 2 +- test/unit/median.js | 2 +- 15 files changed, 31 insertions(+), 29 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 36786a20d..931139b3a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -269,7 +269,7 @@ jobs: contents: read name: "build-wasm32 [package]" runs-on: ubuntu-24.04 - container: "emscripten/emsdk:4.0.11" + container: "emscripten/emsdk:4.0.14" steps: - uses: actions/checkout@v4 - name: Dependencies diff --git a/docs/src/content/docs/changelog/v0.34.4.md b/docs/src/content/docs/changelog/v0.34.4.md index 8adf526b3..d1f80d66e 100644 --- a/docs/src/content/docs/changelog/v0.34.4.md +++ b/docs/src/content/docs/changelog/v0.34.4.md @@ -3,6 +3,8 @@ title: v0.34.4 - TBD slug: changelog/v0.34.4 --- +* Upgrade to libvips v8.17.2 for upstream bug fixes. + * Ensure `autoOrient` occurs before non-90 angle rotation. [#4425](https://github.com/lovell/sharp/issues/4425) diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index c75c237cc..95692c8c7 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.1" + "@img/sharp-libvips-darwin-arm64": "1.2.2-rc.2" }, "files": [ "lib" diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index 3750f6a16..fef9569db 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.1" + "@img/sharp-libvips-darwin-x64": "1.2.2-rc.2" }, "files": [ "lib" diff --git a/npm/linux-arm/package.json b/npm/linux-arm/package.json index 395ee7f22..1eb8992d9 100644 --- a/npm/linux-arm/package.json +++ b/npm/linux-arm/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.1" + "@img/sharp-libvips-linux-arm": "1.2.2-rc.2" }, "files": [ "lib" diff --git a/npm/linux-arm64/package.json b/npm/linux-arm64/package.json index 06bf7a0e2..771c0a3e8 100644 --- a/npm/linux-arm64/package.json +++ b/npm/linux-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.1" + "@img/sharp-libvips-linux-arm64": "1.2.2-rc.2" }, "files": [ "lib" diff --git a/npm/linux-ppc64/package.json b/npm/linux-ppc64/package.json index 74fc33aa8..63b663c64 100644 --- a/npm/linux-ppc64/package.json +++ b/npm/linux-ppc64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.2.1" + "@img/sharp-libvips-linux-ppc64": "1.2.2-rc.2" }, "files": [ "lib" diff --git a/npm/linux-s390x/package.json b/npm/linux-s390x/package.json index 8e0661b35..f723f7ec7 100644 --- a/npm/linux-s390x/package.json +++ b/npm/linux-s390x/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.2.1" + "@img/sharp-libvips-linux-s390x": "1.2.2-rc.2" }, "files": [ "lib" diff --git a/npm/linux-x64/package.json b/npm/linux-x64/package.json index 4a8e13199..af6a65248 100644 --- a/npm/linux-x64/package.json +++ b/npm/linux-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.1" + "@img/sharp-libvips-linux-x64": "1.2.2-rc.2" }, "files": [ "lib" diff --git a/npm/linuxmusl-arm64/package.json b/npm/linuxmusl-arm64/package.json index 9897991bd..ca89e6029 100644 --- a/npm/linuxmusl-arm64/package.json +++ b/npm/linuxmusl-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.1" + "@img/sharp-libvips-linuxmusl-arm64": "1.2.2-rc.2" }, "files": [ "lib" diff --git a/npm/linuxmusl-x64/package.json b/npm/linuxmusl-x64/package.json index 63a85beb5..4543736d0 100644 --- a/npm/linuxmusl-x64/package.json +++ b/npm/linuxmusl-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.1" + "@img/sharp-libvips-linuxmusl-x64": "1.2.2-rc.2" }, "files": [ "lib" diff --git a/package.json b/package.json index 1ce6b5aa3..6a9bb8384 100644 --- a/package.json +++ b/package.json @@ -144,15 +144,15 @@ "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.4-rc.1", "@img/sharp-darwin-x64": "0.34.4-rc.1", - "@img/sharp-libvips-darwin-arm64": "1.2.1", - "@img/sharp-libvips-darwin-x64": "1.2.1", - "@img/sharp-libvips-linux-arm": "1.2.1", - "@img/sharp-libvips-linux-arm64": "1.2.1", - "@img/sharp-libvips-linux-ppc64": "1.2.1", - "@img/sharp-libvips-linux-s390x": "1.2.1", - "@img/sharp-libvips-linux-x64": "1.2.1", - "@img/sharp-libvips-linuxmusl-arm64": "1.2.1", - "@img/sharp-libvips-linuxmusl-x64": "1.2.1", + "@img/sharp-libvips-darwin-arm64": "1.2.2-rc.2", + "@img/sharp-libvips-darwin-x64": "1.2.2-rc.2", + "@img/sharp-libvips-linux-arm": "1.2.2-rc.2", + "@img/sharp-libvips-linux-arm64": "1.2.2-rc.2", + "@img/sharp-libvips-linux-ppc64": "1.2.2-rc.2", + "@img/sharp-libvips-linux-s390x": "1.2.2-rc.2", + "@img/sharp-libvips-linux-x64": "1.2.2-rc.2", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.2-rc.2", + "@img/sharp-libvips-linuxmusl-x64": "1.2.2-rc.2", "@img/sharp-linux-arm": "0.34.4-rc.1", "@img/sharp-linux-arm64": "0.34.4-rc.1", "@img/sharp-linux-ppc64": "0.34.4-rc.1", @@ -167,11 +167,11 @@ }, "devDependencies": { "@emnapi/runtime": "^1.5.0", - "@img/sharp-libvips-dev": "1.2.1", - "@img/sharp-libvips-dev-wasm32": "1.2.1", - "@img/sharp-libvips-win32-arm64": "1.2.1", - "@img/sharp-libvips-win32-ia32": "1.2.1", - "@img/sharp-libvips-win32-x64": "1.2.1", + "@img/sharp-libvips-dev": "1.2.2-rc.2", + "@img/sharp-libvips-dev-wasm32": "1.2.2-rc.2", + "@img/sharp-libvips-win32-arm64": "1.2.2-rc.2", + "@img/sharp-libvips-win32-ia32": "1.2.2-rc.2", + "@img/sharp-libvips-win32-x64": "1.2.2-rc.2", "@types/node": "*", "cc": "^3.0.1", "emnapi": "^1.5.0", @@ -193,7 +193,7 @@ "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "config": { - "libvips": ">=8.17.1" + "libvips": ">=8.17.2" }, "funding": { "url": "https://opencollective.com/libvips" diff --git a/src/common.h b/src/common.h index 4d871d33f..2bba5e1c1 100644 --- a/src/common.h +++ b/src/common.h @@ -16,8 +16,8 @@ #if (VIPS_MAJOR_VERSION < 8) || \ (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 17) || \ - (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 17 && VIPS_MICRO_VERSION < 1) -#error "libvips version 8.17.1+ is required - please see https://sharp.pixelplumbing.com/install" + (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 17 && VIPS_MICRO_VERSION < 2) +#error "libvips version 8.17.2+ is required - please see https://sharp.pixelplumbing.com/install" #endif #if defined(__has_include) diff --git a/test/unit/libvips.js b/test/unit/libvips.js index 15042da91..5dc4c7891 100644 --- a/test/unit/libvips.js +++ b/test/unit/libvips.js @@ -179,7 +179,7 @@ describe('libvips binaries', function () { process.env.npm_config_arch = 's390x'; process.env.npm_config_libc = ''; const locatorHash = libvips.yarnLocator(); - assert.strictEqual(locatorHash, '7e40558001'); + assert.strictEqual(locatorHash, 'b5865b53e1'); delete process.env.npm_config_platform; delete process.env.npm_config_arch; delete process.env.npm_config_libc; diff --git a/test/unit/median.js b/test/unit/median.js index d674bb19e..b11ab5d4d 100644 --- a/test/unit/median.js +++ b/test/unit/median.js @@ -43,7 +43,7 @@ describe('Median filter', function () { .raw() .toBuffer(); - assert.deepStrictEqual(data.subarray(0, 6), Buffer.from([0, 3, 15, 15, 63, 127])); + assert.deepStrictEqual(data.subarray(0, 6), Buffer.from(row)); }); it('invalid radius', () => { From b0154ed83cfff48efed7e347d49995b5476ee072 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Mon, 15 Sep 2025 10:01:04 +0100 Subject: [PATCH 074/115] Upgrade sharp-libvips to v1.2.2 --- npm/darwin-arm64/package.json | 2 +- npm/darwin-x64/package.json | 2 +- npm/linux-arm/package.json | 2 +- npm/linux-arm64/package.json | 2 +- npm/linux-ppc64/package.json | 2 +- npm/linux-s390x/package.json | 2 +- npm/linux-x64/package.json | 2 +- npm/linuxmusl-arm64/package.json | 2 +- npm/linuxmusl-x64/package.json | 2 +- package.json | 30 +++++++++++++++--------------- test/unit/libvips.js | 2 +- 11 files changed, 25 insertions(+), 25 deletions(-) diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index 95692c8c7..a6a3e8f90 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.2-rc.2" + "@img/sharp-libvips-darwin-arm64": "1.2.2" }, "files": [ "lib" diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index fef9569db..a25cf6e91 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.2-rc.2" + "@img/sharp-libvips-darwin-x64": "1.2.2" }, "files": [ "lib" diff --git a/npm/linux-arm/package.json b/npm/linux-arm/package.json index 1eb8992d9..7d74202b3 100644 --- a/npm/linux-arm/package.json +++ b/npm/linux-arm/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.2-rc.2" + "@img/sharp-libvips-linux-arm": "1.2.2" }, "files": [ "lib" diff --git a/npm/linux-arm64/package.json b/npm/linux-arm64/package.json index 771c0a3e8..36ff6fecd 100644 --- a/npm/linux-arm64/package.json +++ b/npm/linux-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.2-rc.2" + "@img/sharp-libvips-linux-arm64": "1.2.2" }, "files": [ "lib" diff --git a/npm/linux-ppc64/package.json b/npm/linux-ppc64/package.json index 63b663c64..bdf2f4a67 100644 --- a/npm/linux-ppc64/package.json +++ b/npm/linux-ppc64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.2.2-rc.2" + "@img/sharp-libvips-linux-ppc64": "1.2.2" }, "files": [ "lib" diff --git a/npm/linux-s390x/package.json b/npm/linux-s390x/package.json index f723f7ec7..6e9c1b98c 100644 --- a/npm/linux-s390x/package.json +++ b/npm/linux-s390x/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.2.2-rc.2" + "@img/sharp-libvips-linux-s390x": "1.2.2" }, "files": [ "lib" diff --git a/npm/linux-x64/package.json b/npm/linux-x64/package.json index af6a65248..ba72a09b7 100644 --- a/npm/linux-x64/package.json +++ b/npm/linux-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.2-rc.2" + "@img/sharp-libvips-linux-x64": "1.2.2" }, "files": [ "lib" diff --git a/npm/linuxmusl-arm64/package.json b/npm/linuxmusl-arm64/package.json index ca89e6029..6be461cce 100644 --- a/npm/linuxmusl-arm64/package.json +++ b/npm/linuxmusl-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.2-rc.2" + "@img/sharp-libvips-linuxmusl-arm64": "1.2.2" }, "files": [ "lib" diff --git a/npm/linuxmusl-x64/package.json b/npm/linuxmusl-x64/package.json index 4543736d0..938090aef 100644 --- a/npm/linuxmusl-x64/package.json +++ b/npm/linuxmusl-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.2-rc.2" + "@img/sharp-libvips-linuxmusl-x64": "1.2.2" }, "files": [ "lib" diff --git a/package.json b/package.json index 6a9bb8384..918814fb1 100644 --- a/package.json +++ b/package.json @@ -138,21 +138,21 @@ ], "dependencies": { "@img/colour": "^1.0.0", - "detect-libc": "^2.0.4", + "detect-libc": "^2.1.0", "semver": "^7.7.2" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.4-rc.1", "@img/sharp-darwin-x64": "0.34.4-rc.1", - "@img/sharp-libvips-darwin-arm64": "1.2.2-rc.2", - "@img/sharp-libvips-darwin-x64": "1.2.2-rc.2", - "@img/sharp-libvips-linux-arm": "1.2.2-rc.2", - "@img/sharp-libvips-linux-arm64": "1.2.2-rc.2", - "@img/sharp-libvips-linux-ppc64": "1.2.2-rc.2", - "@img/sharp-libvips-linux-s390x": "1.2.2-rc.2", - "@img/sharp-libvips-linux-x64": "1.2.2-rc.2", - "@img/sharp-libvips-linuxmusl-arm64": "1.2.2-rc.2", - "@img/sharp-libvips-linuxmusl-x64": "1.2.2-rc.2", + "@img/sharp-libvips-darwin-arm64": "1.2.2", + "@img/sharp-libvips-darwin-x64": "1.2.2", + "@img/sharp-libvips-linux-arm": "1.2.2", + "@img/sharp-libvips-linux-arm64": "1.2.2", + "@img/sharp-libvips-linux-ppc64": "1.2.2", + "@img/sharp-libvips-linux-s390x": "1.2.2", + "@img/sharp-libvips-linux-x64": "1.2.2", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.2", + "@img/sharp-libvips-linuxmusl-x64": "1.2.2", "@img/sharp-linux-arm": "0.34.4-rc.1", "@img/sharp-linux-arm64": "0.34.4-rc.1", "@img/sharp-linux-ppc64": "0.34.4-rc.1", @@ -167,11 +167,11 @@ }, "devDependencies": { "@emnapi/runtime": "^1.5.0", - "@img/sharp-libvips-dev": "1.2.2-rc.2", - "@img/sharp-libvips-dev-wasm32": "1.2.2-rc.2", - "@img/sharp-libvips-win32-arm64": "1.2.2-rc.2", - "@img/sharp-libvips-win32-ia32": "1.2.2-rc.2", - "@img/sharp-libvips-win32-x64": "1.2.2-rc.2", + "@img/sharp-libvips-dev": "1.2.2", + "@img/sharp-libvips-dev-wasm32": "1.2.2", + "@img/sharp-libvips-win32-arm64": "1.2.2", + "@img/sharp-libvips-win32-ia32": "1.2.2", + "@img/sharp-libvips-win32-x64": "1.2.2", "@types/node": "*", "cc": "^3.0.1", "emnapi": "^1.5.0", diff --git a/test/unit/libvips.js b/test/unit/libvips.js index 5dc4c7891..bbeadb760 100644 --- a/test/unit/libvips.js +++ b/test/unit/libvips.js @@ -179,7 +179,7 @@ describe('libvips binaries', function () { process.env.npm_config_arch = 's390x'; process.env.npm_config_libc = ''; const locatorHash = libvips.yarnLocator(); - assert.strictEqual(locatorHash, 'b5865b53e1'); + assert.strictEqual(locatorHash, '9773928ef2'); delete process.env.npm_config_platform; delete process.env.npm_config_arch; delete process.env.npm_config_libc; From 905f69837e80c9005b0b764fe1c174d21c9843d6 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Mon, 15 Sep 2025 10:13:47 +0100 Subject: [PATCH 075/115] Prerelease v0.34.4-rc.2 --- npm/darwin-arm64/package.json | 2 +- npm/darwin-x64/package.json | 2 +- npm/linux-arm/package.json | 2 +- npm/linux-arm64/package.json | 2 +- npm/linux-ppc64/package.json | 2 +- npm/linux-s390x/package.json | 2 +- npm/linux-x64/package.json | 2 +- npm/linuxmusl-arm64/package.json | 2 +- npm/linuxmusl-x64/package.json | 2 +- npm/package.json | 2 +- npm/wasm32/package.json | 2 +- npm/win32-arm64/package.json | 2 +- npm/win32-ia32/package.json | 2 +- npm/win32-x64/package.json | 2 +- package.json | 28 ++++++++++++++-------------- 15 files changed, 28 insertions(+), 28 deletions(-) diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index a6a3e8f90..07069dbcc 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-arm64", - "version": "0.34.4-rc.1", + "version": "0.34.4-rc.2", "description": "Prebuilt sharp for use with macOS 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index a25cf6e91..7c462b9df 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-x64", - "version": "0.34.4-rc.1", + "version": "0.34.4-rc.2", "description": "Prebuilt sharp for use with macOS x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm/package.json b/npm/linux-arm/package.json index 7d74202b3..f02714286 100644 --- a/npm/linux-arm/package.json +++ b/npm/linux-arm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm", - "version": "0.34.4-rc.1", + "version": "0.34.4-rc.2", "description": "Prebuilt sharp for use with Linux (glibc) ARM (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm64/package.json b/npm/linux-arm64/package.json index 36ff6fecd..cb3279d52 100644 --- a/npm/linux-arm64/package.json +++ b/npm/linux-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm64", - "version": "0.34.4-rc.1", + "version": "0.34.4-rc.2", "description": "Prebuilt sharp for use with Linux (glibc) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-ppc64/package.json b/npm/linux-ppc64/package.json index bdf2f4a67..d340d69c8 100644 --- a/npm/linux-ppc64/package.json +++ b/npm/linux-ppc64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-ppc64", - "version": "0.34.4-rc.1", + "version": "0.34.4-rc.2", "description": "Prebuilt sharp for use with Linux (glibc) ppc64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-s390x/package.json b/npm/linux-s390x/package.json index 6e9c1b98c..ab540cc0a 100644 --- a/npm/linux-s390x/package.json +++ b/npm/linux-s390x/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-s390x", - "version": "0.34.4-rc.1", + "version": "0.34.4-rc.2", "description": "Prebuilt sharp for use with Linux (glibc) s390x", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-x64/package.json b/npm/linux-x64/package.json index ba72a09b7..a4a63deec 100644 --- a/npm/linux-x64/package.json +++ b/npm/linux-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-x64", - "version": "0.34.4-rc.1", + "version": "0.34.4-rc.2", "description": "Prebuilt sharp for use with Linux (glibc) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-arm64/package.json b/npm/linuxmusl-arm64/package.json index 6be461cce..b0074a76b 100644 --- a/npm/linuxmusl-arm64/package.json +++ b/npm/linuxmusl-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-arm64", - "version": "0.34.4-rc.1", + "version": "0.34.4-rc.2", "description": "Prebuilt sharp for use with Linux (musl) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-x64/package.json b/npm/linuxmusl-x64/package.json index 938090aef..954cbf6a6 100644 --- a/npm/linuxmusl-x64/package.json +++ b/npm/linuxmusl-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-x64", - "version": "0.34.4-rc.1", + "version": "0.34.4-rc.2", "description": "Prebuilt sharp for use with Linux (musl) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/package.json b/npm/package.json index 2cfe6a0e3..038e0cf6c 100644 --- a/npm/package.json +++ b/npm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp", - "version": "0.34.4-rc.1", + "version": "0.34.4-rc.2", "private": "true", "workspaces": [ "darwin-arm64", diff --git a/npm/wasm32/package.json b/npm/wasm32/package.json index 580bc14f8..6ec45dd98 100644 --- a/npm/wasm32/package.json +++ b/npm/wasm32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-wasm32", - "version": "0.34.4-rc.1", + "version": "0.34.4-rc.2", "description": "Prebuilt sharp for use with wasm32", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-arm64/package.json b/npm/win32-arm64/package.json index db152c7f6..83643b08e 100644 --- a/npm/win32-arm64/package.json +++ b/npm/win32-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-arm64", - "version": "0.34.4-rc.1", + "version": "0.34.4-rc.2", "description": "Prebuilt sharp for use with Windows 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-ia32/package.json b/npm/win32-ia32/package.json index d9a3e2ab3..716f18fa8 100644 --- a/npm/win32-ia32/package.json +++ b/npm/win32-ia32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-ia32", - "version": "0.34.4-rc.1", + "version": "0.34.4-rc.2", "description": "Prebuilt sharp for use with Windows x86 (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-x64/package.json b/npm/win32-x64/package.json index 8430d7930..f4366a0a6 100644 --- a/npm/win32-x64/package.json +++ b/npm/win32-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-x64", - "version": "0.34.4-rc.1", + "version": "0.34.4-rc.2", "description": "Prebuilt sharp for use with Windows x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/package.json b/package.json index 918814fb1..8c8c8e932 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "sharp", "description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images", - "version": "0.34.4-rc.1", + "version": "0.34.4-rc.2", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", "contributors": [ @@ -142,8 +142,8 @@ "semver": "^7.7.2" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.4-rc.1", - "@img/sharp-darwin-x64": "0.34.4-rc.1", + "@img/sharp-darwin-arm64": "0.34.4-rc.2", + "@img/sharp-darwin-x64": "0.34.4-rc.2", "@img/sharp-libvips-darwin-arm64": "1.2.2", "@img/sharp-libvips-darwin-x64": "1.2.2", "@img/sharp-libvips-linux-arm": "1.2.2", @@ -153,17 +153,17 @@ "@img/sharp-libvips-linux-x64": "1.2.2", "@img/sharp-libvips-linuxmusl-arm64": "1.2.2", "@img/sharp-libvips-linuxmusl-x64": "1.2.2", - "@img/sharp-linux-arm": "0.34.4-rc.1", - "@img/sharp-linux-arm64": "0.34.4-rc.1", - "@img/sharp-linux-ppc64": "0.34.4-rc.1", - "@img/sharp-linux-s390x": "0.34.4-rc.1", - "@img/sharp-linux-x64": "0.34.4-rc.1", - "@img/sharp-linuxmusl-arm64": "0.34.4-rc.1", - "@img/sharp-linuxmusl-x64": "0.34.4-rc.1", - "@img/sharp-wasm32": "0.34.4-rc.1", - "@img/sharp-win32-arm64": "0.34.4-rc.1", - "@img/sharp-win32-ia32": "0.34.4-rc.1", - "@img/sharp-win32-x64": "0.34.4-rc.1" + "@img/sharp-linux-arm": "0.34.4-rc.2", + "@img/sharp-linux-arm64": "0.34.4-rc.2", + "@img/sharp-linux-ppc64": "0.34.4-rc.2", + "@img/sharp-linux-s390x": "0.34.4-rc.2", + "@img/sharp-linux-x64": "0.34.4-rc.2", + "@img/sharp-linuxmusl-arm64": "0.34.4-rc.2", + "@img/sharp-linuxmusl-x64": "0.34.4-rc.2", + "@img/sharp-wasm32": "0.34.4-rc.2", + "@img/sharp-win32-arm64": "0.34.4-rc.2", + "@img/sharp-win32-ia32": "0.34.4-rc.2", + "@img/sharp-win32-x64": "0.34.4-rc.2" }, "devDependencies": { "@emnapi/runtime": "^1.5.0", From b507831a1191175b83e1f3fa52ad4cd56686a6a5 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Mon, 15 Sep 2025 11:18:00 +0100 Subject: [PATCH 076/115] CI: Remove dry-run flag This was temporary whilst setting up auto-publish --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 931139b3a..1f126419a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -330,7 +330,7 @@ jobs: bodyFile: release-notes.md - name: Publish platform-specific npm packages if: startsWith(github.ref, 'refs/tags/v') - run: cd npm && npm publish --workspaces --tag=${{ contains(github.ref, '-rc') && 'next' || 'latest' }} --dry-run + run: cd npm && npm publish --workspaces --tag=${{ contains(github.ref, '-rc') && 'next' || 'latest' }} - name: Publish sharp npm package if: startsWith(github.ref, 'refs/tags/v') - run: npm publish --tag=${{ contains(github.ref, '-rc') && 'next' || 'latest' }} --dry-run + run: npm publish --tag=${{ contains(github.ref, '-rc') && 'next' || 'latest' }} From 9f4bace03bd047602d9f120f655f19a2cdc7c1ff Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Mon, 15 Sep 2025 11:18:53 +0100 Subject: [PATCH 077/115] Prerelease v0.34.4-rc.3 --- npm/darwin-arm64/package.json | 2 +- npm/darwin-x64/package.json | 2 +- npm/linux-arm/package.json | 2 +- npm/linux-arm64/package.json | 2 +- npm/linux-ppc64/package.json | 2 +- npm/linux-s390x/package.json | 2 +- npm/linux-x64/package.json | 2 +- npm/linuxmusl-arm64/package.json | 2 +- npm/linuxmusl-x64/package.json | 2 +- npm/package.json | 2 +- npm/wasm32/package.json | 2 +- npm/win32-arm64/package.json | 2 +- npm/win32-ia32/package.json | 2 +- npm/win32-x64/package.json | 2 +- package.json | 28 ++++++++++++++-------------- 15 files changed, 28 insertions(+), 28 deletions(-) diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index 07069dbcc..a3aeb1383 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-arm64", - "version": "0.34.4-rc.2", + "version": "0.34.4-rc.3", "description": "Prebuilt sharp for use with macOS 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index 7c462b9df..63a2e4922 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-x64", - "version": "0.34.4-rc.2", + "version": "0.34.4-rc.3", "description": "Prebuilt sharp for use with macOS x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm/package.json b/npm/linux-arm/package.json index f02714286..467655b09 100644 --- a/npm/linux-arm/package.json +++ b/npm/linux-arm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm", - "version": "0.34.4-rc.2", + "version": "0.34.4-rc.3", "description": "Prebuilt sharp for use with Linux (glibc) ARM (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm64/package.json b/npm/linux-arm64/package.json index cb3279d52..a3980eae8 100644 --- a/npm/linux-arm64/package.json +++ b/npm/linux-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm64", - "version": "0.34.4-rc.2", + "version": "0.34.4-rc.3", "description": "Prebuilt sharp for use with Linux (glibc) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-ppc64/package.json b/npm/linux-ppc64/package.json index d340d69c8..611065c1a 100644 --- a/npm/linux-ppc64/package.json +++ b/npm/linux-ppc64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-ppc64", - "version": "0.34.4-rc.2", + "version": "0.34.4-rc.3", "description": "Prebuilt sharp for use with Linux (glibc) ppc64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-s390x/package.json b/npm/linux-s390x/package.json index ab540cc0a..2b79845f3 100644 --- a/npm/linux-s390x/package.json +++ b/npm/linux-s390x/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-s390x", - "version": "0.34.4-rc.2", + "version": "0.34.4-rc.3", "description": "Prebuilt sharp for use with Linux (glibc) s390x", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-x64/package.json b/npm/linux-x64/package.json index a4a63deec..523e64a7f 100644 --- a/npm/linux-x64/package.json +++ b/npm/linux-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-x64", - "version": "0.34.4-rc.2", + "version": "0.34.4-rc.3", "description": "Prebuilt sharp for use with Linux (glibc) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-arm64/package.json b/npm/linuxmusl-arm64/package.json index b0074a76b..f104f2c6e 100644 --- a/npm/linuxmusl-arm64/package.json +++ b/npm/linuxmusl-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-arm64", - "version": "0.34.4-rc.2", + "version": "0.34.4-rc.3", "description": "Prebuilt sharp for use with Linux (musl) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-x64/package.json b/npm/linuxmusl-x64/package.json index 954cbf6a6..1b9c21c03 100644 --- a/npm/linuxmusl-x64/package.json +++ b/npm/linuxmusl-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-x64", - "version": "0.34.4-rc.2", + "version": "0.34.4-rc.3", "description": "Prebuilt sharp for use with Linux (musl) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/package.json b/npm/package.json index 038e0cf6c..c57a76d73 100644 --- a/npm/package.json +++ b/npm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp", - "version": "0.34.4-rc.2", + "version": "0.34.4-rc.3", "private": "true", "workspaces": [ "darwin-arm64", diff --git a/npm/wasm32/package.json b/npm/wasm32/package.json index 6ec45dd98..17fef619a 100644 --- a/npm/wasm32/package.json +++ b/npm/wasm32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-wasm32", - "version": "0.34.4-rc.2", + "version": "0.34.4-rc.3", "description": "Prebuilt sharp for use with wasm32", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-arm64/package.json b/npm/win32-arm64/package.json index 83643b08e..c454fd00b 100644 --- a/npm/win32-arm64/package.json +++ b/npm/win32-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-arm64", - "version": "0.34.4-rc.2", + "version": "0.34.4-rc.3", "description": "Prebuilt sharp for use with Windows 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-ia32/package.json b/npm/win32-ia32/package.json index 716f18fa8..16be8b098 100644 --- a/npm/win32-ia32/package.json +++ b/npm/win32-ia32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-ia32", - "version": "0.34.4-rc.2", + "version": "0.34.4-rc.3", "description": "Prebuilt sharp for use with Windows x86 (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-x64/package.json b/npm/win32-x64/package.json index f4366a0a6..6e90c4ffe 100644 --- a/npm/win32-x64/package.json +++ b/npm/win32-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-x64", - "version": "0.34.4-rc.2", + "version": "0.34.4-rc.3", "description": "Prebuilt sharp for use with Windows x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/package.json b/package.json index 8c8c8e932..088a23ed8 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "sharp", "description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images", - "version": "0.34.4-rc.2", + "version": "0.34.4-rc.3", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", "contributors": [ @@ -142,8 +142,8 @@ "semver": "^7.7.2" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.4-rc.2", - "@img/sharp-darwin-x64": "0.34.4-rc.2", + "@img/sharp-darwin-arm64": "0.34.4-rc.3", + "@img/sharp-darwin-x64": "0.34.4-rc.3", "@img/sharp-libvips-darwin-arm64": "1.2.2", "@img/sharp-libvips-darwin-x64": "1.2.2", "@img/sharp-libvips-linux-arm": "1.2.2", @@ -153,17 +153,17 @@ "@img/sharp-libvips-linux-x64": "1.2.2", "@img/sharp-libvips-linuxmusl-arm64": "1.2.2", "@img/sharp-libvips-linuxmusl-x64": "1.2.2", - "@img/sharp-linux-arm": "0.34.4-rc.2", - "@img/sharp-linux-arm64": "0.34.4-rc.2", - "@img/sharp-linux-ppc64": "0.34.4-rc.2", - "@img/sharp-linux-s390x": "0.34.4-rc.2", - "@img/sharp-linux-x64": "0.34.4-rc.2", - "@img/sharp-linuxmusl-arm64": "0.34.4-rc.2", - "@img/sharp-linuxmusl-x64": "0.34.4-rc.2", - "@img/sharp-wasm32": "0.34.4-rc.2", - "@img/sharp-win32-arm64": "0.34.4-rc.2", - "@img/sharp-win32-ia32": "0.34.4-rc.2", - "@img/sharp-win32-x64": "0.34.4-rc.2" + "@img/sharp-linux-arm": "0.34.4-rc.3", + "@img/sharp-linux-arm64": "0.34.4-rc.3", + "@img/sharp-linux-ppc64": "0.34.4-rc.3", + "@img/sharp-linux-s390x": "0.34.4-rc.3", + "@img/sharp-linux-x64": "0.34.4-rc.3", + "@img/sharp-linuxmusl-arm64": "0.34.4-rc.3", + "@img/sharp-linuxmusl-x64": "0.34.4-rc.3", + "@img/sharp-wasm32": "0.34.4-rc.3", + "@img/sharp-win32-arm64": "0.34.4-rc.3", + "@img/sharp-win32-ia32": "0.34.4-rc.3", + "@img/sharp-win32-x64": "0.34.4-rc.3" }, "devDependencies": { "@emnapi/runtime": "^1.5.0", From 35d3f56c67fb6e61d9685309352fcb985da649f5 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Tue, 16 Sep 2025 08:44:08 +0100 Subject: [PATCH 078/115] Ensure TIFF subifd and OpenSlide level are respected Fixes regression introduced in 852c7f8 --- docs/src/content/docs/changelog/v0.34.4.md | 2 ++ src/common.cc | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/src/content/docs/changelog/v0.34.4.md b/docs/src/content/docs/changelog/v0.34.4.md index d1f80d66e..10ef68fd4 100644 --- a/docs/src/content/docs/changelog/v0.34.4.md +++ b/docs/src/content/docs/changelog/v0.34.4.md @@ -5,6 +5,8 @@ slug: changelog/v0.34.4 * Upgrade to libvips v8.17.2 for upstream bug fixes. +* Ensure TIFF `subifd` and OpenSlide `level` input options are respected (regression in 0.34.3). + * Ensure `autoOrient` occurs before non-90 angle rotation. [#4425](https://github.com/lovell/sharp/issues/4425) diff --git a/src/common.cc b/src/common.cc index 2688bd730..e4ce73209 100644 --- a/src/common.cc +++ b/src/common.cc @@ -421,14 +421,14 @@ namespace sharp { ->set("high_bitdepth", descriptor->svgHighBitdepth); break; case ImageType::TIFF: - option->set("tiffSubifd", descriptor->tiffSubifd); + option->set("subifd", descriptor->tiffSubifd); break; case ImageType::PDF: option->set("dpi", descriptor->density) ->set("background", descriptor->pdfBackground); break; case ImageType::OPENSLIDE: - option->set("openSlideLevel", descriptor->openSlideLevel); + option->set("level", descriptor->openSlideLevel); break; case ImageType::JP2: option->set("oneshot", descriptor->jp2Oneshot); From dfcbceee4bf4fc9ef3162a3805caaada6dd5a38a Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Wed, 17 Sep 2025 12:10:36 +0100 Subject: [PATCH 079/115] Upgrade sharp-libvips to v1.2.3 --- npm/darwin-arm64/package.json | 2 +- npm/darwin-x64/package.json | 2 +- npm/linux-arm/package.json | 2 +- npm/linux-arm64/package.json | 2 +- npm/linux-ppc64/package.json | 2 +- npm/linux-s390x/package.json | 2 +- npm/linux-x64/package.json | 2 +- npm/linuxmusl-arm64/package.json | 2 +- npm/linuxmusl-x64/package.json | 2 +- package.json | 30 +++++++++++++++--------------- test/unit/libvips.js | 2 +- 11 files changed, 25 insertions(+), 25 deletions(-) diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index a3aeb1383..b54bad7d6 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.2" + "@img/sharp-libvips-darwin-arm64": "1.2.3" }, "files": [ "lib" diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index 63a2e4922..9abfae775 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.2" + "@img/sharp-libvips-darwin-x64": "1.2.3" }, "files": [ "lib" diff --git a/npm/linux-arm/package.json b/npm/linux-arm/package.json index 467655b09..1bf6d7470 100644 --- a/npm/linux-arm/package.json +++ b/npm/linux-arm/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.2" + "@img/sharp-libvips-linux-arm": "1.2.3" }, "files": [ "lib" diff --git a/npm/linux-arm64/package.json b/npm/linux-arm64/package.json index a3980eae8..f7d78c248 100644 --- a/npm/linux-arm64/package.json +++ b/npm/linux-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.2" + "@img/sharp-libvips-linux-arm64": "1.2.3" }, "files": [ "lib" diff --git a/npm/linux-ppc64/package.json b/npm/linux-ppc64/package.json index 611065c1a..13afdccc0 100644 --- a/npm/linux-ppc64/package.json +++ b/npm/linux-ppc64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.2.2" + "@img/sharp-libvips-linux-ppc64": "1.2.3" }, "files": [ "lib" diff --git a/npm/linux-s390x/package.json b/npm/linux-s390x/package.json index 2b79845f3..bd09456e9 100644 --- a/npm/linux-s390x/package.json +++ b/npm/linux-s390x/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.2.2" + "@img/sharp-libvips-linux-s390x": "1.2.3" }, "files": [ "lib" diff --git a/npm/linux-x64/package.json b/npm/linux-x64/package.json index 523e64a7f..94c00c47e 100644 --- a/npm/linux-x64/package.json +++ b/npm/linux-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.2" + "@img/sharp-libvips-linux-x64": "1.2.3" }, "files": [ "lib" diff --git a/npm/linuxmusl-arm64/package.json b/npm/linuxmusl-arm64/package.json index f104f2c6e..f7bd7ce76 100644 --- a/npm/linuxmusl-arm64/package.json +++ b/npm/linuxmusl-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.2" + "@img/sharp-libvips-linuxmusl-arm64": "1.2.3" }, "files": [ "lib" diff --git a/npm/linuxmusl-x64/package.json b/npm/linuxmusl-x64/package.json index 1b9c21c03..50e8ae803 100644 --- a/npm/linuxmusl-x64/package.json +++ b/npm/linuxmusl-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.2" + "@img/sharp-libvips-linuxmusl-x64": "1.2.3" }, "files": [ "lib" diff --git a/package.json b/package.json index 088a23ed8..6ba96e63d 100644 --- a/package.json +++ b/package.json @@ -144,15 +144,15 @@ "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.4-rc.3", "@img/sharp-darwin-x64": "0.34.4-rc.3", - "@img/sharp-libvips-darwin-arm64": "1.2.2", - "@img/sharp-libvips-darwin-x64": "1.2.2", - "@img/sharp-libvips-linux-arm": "1.2.2", - "@img/sharp-libvips-linux-arm64": "1.2.2", - "@img/sharp-libvips-linux-ppc64": "1.2.2", - "@img/sharp-libvips-linux-s390x": "1.2.2", - "@img/sharp-libvips-linux-x64": "1.2.2", - "@img/sharp-libvips-linuxmusl-arm64": "1.2.2", - "@img/sharp-libvips-linuxmusl-x64": "1.2.2", + "@img/sharp-libvips-darwin-arm64": "1.2.3", + "@img/sharp-libvips-darwin-x64": "1.2.3", + "@img/sharp-libvips-linux-arm": "1.2.3", + "@img/sharp-libvips-linux-arm64": "1.2.3", + "@img/sharp-libvips-linux-ppc64": "1.2.3", + "@img/sharp-libvips-linux-s390x": "1.2.3", + "@img/sharp-libvips-linux-x64": "1.2.3", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.3", + "@img/sharp-libvips-linuxmusl-x64": "1.2.3", "@img/sharp-linux-arm": "0.34.4-rc.3", "@img/sharp-linux-arm64": "0.34.4-rc.3", "@img/sharp-linux-ppc64": "0.34.4-rc.3", @@ -167,11 +167,11 @@ }, "devDependencies": { "@emnapi/runtime": "^1.5.0", - "@img/sharp-libvips-dev": "1.2.2", - "@img/sharp-libvips-dev-wasm32": "1.2.2", - "@img/sharp-libvips-win32-arm64": "1.2.2", - "@img/sharp-libvips-win32-ia32": "1.2.2", - "@img/sharp-libvips-win32-x64": "1.2.2", + "@img/sharp-libvips-dev": "1.2.3", + "@img/sharp-libvips-dev-wasm32": "1.2.3", + "@img/sharp-libvips-win32-arm64": "1.2.3", + "@img/sharp-libvips-win32-ia32": "1.2.3", + "@img/sharp-libvips-win32-x64": "1.2.3", "@types/node": "*", "cc": "^3.0.1", "emnapi": "^1.5.0", @@ -185,7 +185,7 @@ "node-gyp": "^11.4.2", "nyc": "^17.1.0", "semistandard": "^17.0.0", - "tar-fs": "^3.1.0", + "tar-fs": "^3.1.1", "tsd": "^0.33.0" }, "license": "Apache-2.0", diff --git a/test/unit/libvips.js b/test/unit/libvips.js index bbeadb760..ded3f8bb7 100644 --- a/test/unit/libvips.js +++ b/test/unit/libvips.js @@ -179,7 +179,7 @@ describe('libvips binaries', function () { process.env.npm_config_arch = 's390x'; process.env.npm_config_libc = ''; const locatorHash = libvips.yarnLocator(); - assert.strictEqual(locatorHash, '9773928ef2'); + assert.strictEqual(locatorHash, '7c141893d6'); delete process.env.npm_config_platform; delete process.env.npm_config_arch; delete process.env.npm_config_libc; From ed1ac43e55d7125a347cd3db9facab4e68ac6363 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Wed, 17 Sep 2025 12:11:06 +0100 Subject: [PATCH 080/115] CI: Upgrade packaging test dependencies --- .github/workflows/npm.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/npm.yml b/.github/workflows/npm.yml index 25286b454..a8e37aa14 100644 --- a/.github/workflows/npm.yml +++ b/.github/workflows/npm.yml @@ -96,7 +96,7 @@ jobs: steps: - name: Install Node.js if: ${{ matrix.runtime == 'node' }} - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: 20 - name: Install pnpm @@ -106,9 +106,9 @@ jobs: version: 8 - name: Install Deno if: ${{ matrix.runtime == 'deno' }} - uses: denoland/setup-deno@v1 + uses: denoland/setup-deno@v2 with: - deno-version: v1.x + deno-version: v2.x - name: Install Bun if: ${{ matrix.runtime == 'bun' }} uses: oven-sh/setup-bun@v2 @@ -117,7 +117,7 @@ jobs: - name: Version id: version - uses: actions/github-script@v7 + uses: actions/github-script@v8 with: script: | core.setOutput('semver', context.ref.replace('refs/tags/v','')) From 4710092b2a38baf126c6814a42e01a0ac012bf90 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Wed, 17 Sep 2025 12:53:47 +0100 Subject: [PATCH 081/115] Prerelease v0.34.4-rc.4 --- npm/darwin-arm64/package.json | 2 +- npm/darwin-x64/package.json | 2 +- npm/linux-arm/package.json | 2 +- npm/linux-arm64/package.json | 2 +- npm/linux-ppc64/package.json | 2 +- npm/linux-s390x/package.json | 2 +- npm/linux-x64/package.json | 2 +- npm/linuxmusl-arm64/package.json | 2 +- npm/linuxmusl-x64/package.json | 2 +- npm/package.json | 2 +- npm/wasm32/package.json | 2 +- npm/win32-arm64/package.json | 2 +- npm/win32-ia32/package.json | 2 +- npm/win32-x64/package.json | 2 +- package.json | 28 ++++++++++++++-------------- 15 files changed, 28 insertions(+), 28 deletions(-) diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index b54bad7d6..95eed24b3 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-arm64", - "version": "0.34.4-rc.3", + "version": "0.34.4-rc.4", "description": "Prebuilt sharp for use with macOS 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index 9abfae775..49828bfbb 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-x64", - "version": "0.34.4-rc.3", + "version": "0.34.4-rc.4", "description": "Prebuilt sharp for use with macOS x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm/package.json b/npm/linux-arm/package.json index 1bf6d7470..b6a87822d 100644 --- a/npm/linux-arm/package.json +++ b/npm/linux-arm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm", - "version": "0.34.4-rc.3", + "version": "0.34.4-rc.4", "description": "Prebuilt sharp for use with Linux (glibc) ARM (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm64/package.json b/npm/linux-arm64/package.json index f7d78c248..ce296f50c 100644 --- a/npm/linux-arm64/package.json +++ b/npm/linux-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm64", - "version": "0.34.4-rc.3", + "version": "0.34.4-rc.4", "description": "Prebuilt sharp for use with Linux (glibc) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-ppc64/package.json b/npm/linux-ppc64/package.json index 13afdccc0..ab2dd75d4 100644 --- a/npm/linux-ppc64/package.json +++ b/npm/linux-ppc64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-ppc64", - "version": "0.34.4-rc.3", + "version": "0.34.4-rc.4", "description": "Prebuilt sharp for use with Linux (glibc) ppc64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-s390x/package.json b/npm/linux-s390x/package.json index bd09456e9..0abecbee5 100644 --- a/npm/linux-s390x/package.json +++ b/npm/linux-s390x/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-s390x", - "version": "0.34.4-rc.3", + "version": "0.34.4-rc.4", "description": "Prebuilt sharp for use with Linux (glibc) s390x", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-x64/package.json b/npm/linux-x64/package.json index 94c00c47e..3efdc51eb 100644 --- a/npm/linux-x64/package.json +++ b/npm/linux-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-x64", - "version": "0.34.4-rc.3", + "version": "0.34.4-rc.4", "description": "Prebuilt sharp for use with Linux (glibc) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-arm64/package.json b/npm/linuxmusl-arm64/package.json index f7bd7ce76..d61c9f9e0 100644 --- a/npm/linuxmusl-arm64/package.json +++ b/npm/linuxmusl-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-arm64", - "version": "0.34.4-rc.3", + "version": "0.34.4-rc.4", "description": "Prebuilt sharp for use with Linux (musl) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-x64/package.json b/npm/linuxmusl-x64/package.json index 50e8ae803..38dc008d2 100644 --- a/npm/linuxmusl-x64/package.json +++ b/npm/linuxmusl-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-x64", - "version": "0.34.4-rc.3", + "version": "0.34.4-rc.4", "description": "Prebuilt sharp for use with Linux (musl) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/package.json b/npm/package.json index c57a76d73..d78d5dea3 100644 --- a/npm/package.json +++ b/npm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp", - "version": "0.34.4-rc.3", + "version": "0.34.4-rc.4", "private": "true", "workspaces": [ "darwin-arm64", diff --git a/npm/wasm32/package.json b/npm/wasm32/package.json index 17fef619a..68f844fea 100644 --- a/npm/wasm32/package.json +++ b/npm/wasm32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-wasm32", - "version": "0.34.4-rc.3", + "version": "0.34.4-rc.4", "description": "Prebuilt sharp for use with wasm32", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-arm64/package.json b/npm/win32-arm64/package.json index c454fd00b..2fb9b3351 100644 --- a/npm/win32-arm64/package.json +++ b/npm/win32-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-arm64", - "version": "0.34.4-rc.3", + "version": "0.34.4-rc.4", "description": "Prebuilt sharp for use with Windows 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-ia32/package.json b/npm/win32-ia32/package.json index 16be8b098..c0501960d 100644 --- a/npm/win32-ia32/package.json +++ b/npm/win32-ia32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-ia32", - "version": "0.34.4-rc.3", + "version": "0.34.4-rc.4", "description": "Prebuilt sharp for use with Windows x86 (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-x64/package.json b/npm/win32-x64/package.json index 6e90c4ffe..c93fae480 100644 --- a/npm/win32-x64/package.json +++ b/npm/win32-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-x64", - "version": "0.34.4-rc.3", + "version": "0.34.4-rc.4", "description": "Prebuilt sharp for use with Windows x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/package.json b/package.json index 6ba96e63d..8bfa71049 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "sharp", "description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images", - "version": "0.34.4-rc.3", + "version": "0.34.4-rc.4", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", "contributors": [ @@ -142,8 +142,8 @@ "semver": "^7.7.2" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.4-rc.3", - "@img/sharp-darwin-x64": "0.34.4-rc.3", + "@img/sharp-darwin-arm64": "0.34.4-rc.4", + "@img/sharp-darwin-x64": "0.34.4-rc.4", "@img/sharp-libvips-darwin-arm64": "1.2.3", "@img/sharp-libvips-darwin-x64": "1.2.3", "@img/sharp-libvips-linux-arm": "1.2.3", @@ -153,17 +153,17 @@ "@img/sharp-libvips-linux-x64": "1.2.3", "@img/sharp-libvips-linuxmusl-arm64": "1.2.3", "@img/sharp-libvips-linuxmusl-x64": "1.2.3", - "@img/sharp-linux-arm": "0.34.4-rc.3", - "@img/sharp-linux-arm64": "0.34.4-rc.3", - "@img/sharp-linux-ppc64": "0.34.4-rc.3", - "@img/sharp-linux-s390x": "0.34.4-rc.3", - "@img/sharp-linux-x64": "0.34.4-rc.3", - "@img/sharp-linuxmusl-arm64": "0.34.4-rc.3", - "@img/sharp-linuxmusl-x64": "0.34.4-rc.3", - "@img/sharp-wasm32": "0.34.4-rc.3", - "@img/sharp-win32-arm64": "0.34.4-rc.3", - "@img/sharp-win32-ia32": "0.34.4-rc.3", - "@img/sharp-win32-x64": "0.34.4-rc.3" + "@img/sharp-linux-arm": "0.34.4-rc.4", + "@img/sharp-linux-arm64": "0.34.4-rc.4", + "@img/sharp-linux-ppc64": "0.34.4-rc.4", + "@img/sharp-linux-s390x": "0.34.4-rc.4", + "@img/sharp-linux-x64": "0.34.4-rc.4", + "@img/sharp-linuxmusl-arm64": "0.34.4-rc.4", + "@img/sharp-linuxmusl-x64": "0.34.4-rc.4", + "@img/sharp-wasm32": "0.34.4-rc.4", + "@img/sharp-win32-arm64": "0.34.4-rc.4", + "@img/sharp-win32-ia32": "0.34.4-rc.4", + "@img/sharp-win32-x64": "0.34.4-rc.4" }, "devDependencies": { "@emnapi/runtime": "^1.5.0", From 529901177b814aefedba80a7dbb670760d4dfbda Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Wed, 17 Sep 2025 13:56:49 +0100 Subject: [PATCH 082/115] CI/Docs: Deno v2 support --- .github/workflows/npm.yml | 4 +++- docs/src/content/docs/install.md | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/npm.yml b/.github/workflows/npm.yml index a8e37aa14..7f0d04bb5 100644 --- a/.github/workflows/npm.yml +++ b/.github/workflows/npm.yml @@ -185,7 +185,9 @@ jobs: - name: Run with Deno if: ${{ matrix.runtime == 'deno' }} - run: deno run --allow-read --allow-ffi release.mjs + run: | + deno install + deno run --allow-env --allow-ffi --allow-read --allow-sys release.mjs - name: Run with Bun if: ${{ matrix.runtime == 'bun' }} diff --git a/docs/src/content/docs/install.md b/docs/src/content/docs/install.md index b4d1d5a86..6e14ab1ca 100644 --- a/docs/src/content/docs/install.md +++ b/docs/src/content/docs/install.md @@ -20,7 +20,7 @@ npm install sharp pnpm add sharp ``` -When using `pnpm`, you may need to add `sharp` to +When using `pnpm`, add `sharp` to [ignoredBuiltDependencies](https://pnpm.io/settings#ignoredbuiltdependencies) to silence warnings. @@ -33,7 +33,8 @@ bun add sharp ``` ```sh frame="none" -deno run --allow-ffi ... +deno add --quiet npm:sharp +deno run --allow-env --allow-ffi --allow-read --allow-sys ... ``` ## Prerequisites From ee437832e2fa383345103550a1258f20feac247a Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Wed, 17 Sep 2025 13:57:10 +0100 Subject: [PATCH 083/115] Release v0.34.4 --- docs/src/content/docs/changelog/v0.34.4.md | 2 +- npm/darwin-arm64/package.json | 2 +- npm/darwin-x64/package.json | 2 +- npm/linux-arm/package.json | 2 +- npm/linux-arm64/package.json | 2 +- npm/linux-ppc64/package.json | 2 +- npm/linux-s390x/package.json | 2 +- npm/linux-x64/package.json | 2 +- npm/linuxmusl-arm64/package.json | 2 +- npm/linuxmusl-x64/package.json | 2 +- npm/package.json | 2 +- npm/wasm32/package.json | 2 +- npm/win32-arm64/package.json | 2 +- npm/win32-ia32/package.json | 2 +- npm/win32-x64/package.json | 2 +- package.json | 28 +++++++++++----------- 16 files changed, 29 insertions(+), 29 deletions(-) diff --git a/docs/src/content/docs/changelog/v0.34.4.md b/docs/src/content/docs/changelog/v0.34.4.md index 10ef68fd4..83c95ce43 100644 --- a/docs/src/content/docs/changelog/v0.34.4.md +++ b/docs/src/content/docs/changelog/v0.34.4.md @@ -1,5 +1,5 @@ --- -title: v0.34.4 - TBD +title: v0.34.4 - 17th September 2025 slug: changelog/v0.34.4 --- diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index 95eed24b3..da5ee34b3 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-arm64", - "version": "0.34.4-rc.4", + "version": "0.34.4", "description": "Prebuilt sharp for use with macOS 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index 49828bfbb..835d80a00 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-x64", - "version": "0.34.4-rc.4", + "version": "0.34.4", "description": "Prebuilt sharp for use with macOS x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm/package.json b/npm/linux-arm/package.json index b6a87822d..4872f3576 100644 --- a/npm/linux-arm/package.json +++ b/npm/linux-arm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm", - "version": "0.34.4-rc.4", + "version": "0.34.4", "description": "Prebuilt sharp for use with Linux (glibc) ARM (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm64/package.json b/npm/linux-arm64/package.json index ce296f50c..320764149 100644 --- a/npm/linux-arm64/package.json +++ b/npm/linux-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm64", - "version": "0.34.4-rc.4", + "version": "0.34.4", "description": "Prebuilt sharp for use with Linux (glibc) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-ppc64/package.json b/npm/linux-ppc64/package.json index ab2dd75d4..7db2e1e70 100644 --- a/npm/linux-ppc64/package.json +++ b/npm/linux-ppc64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-ppc64", - "version": "0.34.4-rc.4", + "version": "0.34.4", "description": "Prebuilt sharp for use with Linux (glibc) ppc64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-s390x/package.json b/npm/linux-s390x/package.json index 0abecbee5..ff0f657d1 100644 --- a/npm/linux-s390x/package.json +++ b/npm/linux-s390x/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-s390x", - "version": "0.34.4-rc.4", + "version": "0.34.4", "description": "Prebuilt sharp for use with Linux (glibc) s390x", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-x64/package.json b/npm/linux-x64/package.json index 3efdc51eb..20996aaba 100644 --- a/npm/linux-x64/package.json +++ b/npm/linux-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-x64", - "version": "0.34.4-rc.4", + "version": "0.34.4", "description": "Prebuilt sharp for use with Linux (glibc) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-arm64/package.json b/npm/linuxmusl-arm64/package.json index d61c9f9e0..da27e8ad6 100644 --- a/npm/linuxmusl-arm64/package.json +++ b/npm/linuxmusl-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-arm64", - "version": "0.34.4-rc.4", + "version": "0.34.4", "description": "Prebuilt sharp for use with Linux (musl) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-x64/package.json b/npm/linuxmusl-x64/package.json index 38dc008d2..3d2180614 100644 --- a/npm/linuxmusl-x64/package.json +++ b/npm/linuxmusl-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-x64", - "version": "0.34.4-rc.4", + "version": "0.34.4", "description": "Prebuilt sharp for use with Linux (musl) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/package.json b/npm/package.json index d78d5dea3..6fe69b646 100644 --- a/npm/package.json +++ b/npm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp", - "version": "0.34.4-rc.4", + "version": "0.34.4", "private": "true", "workspaces": [ "darwin-arm64", diff --git a/npm/wasm32/package.json b/npm/wasm32/package.json index 68f844fea..f6a40247b 100644 --- a/npm/wasm32/package.json +++ b/npm/wasm32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-wasm32", - "version": "0.34.4-rc.4", + "version": "0.34.4", "description": "Prebuilt sharp for use with wasm32", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-arm64/package.json b/npm/win32-arm64/package.json index 2fb9b3351..741cca7ef 100644 --- a/npm/win32-arm64/package.json +++ b/npm/win32-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-arm64", - "version": "0.34.4-rc.4", + "version": "0.34.4", "description": "Prebuilt sharp for use with Windows 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-ia32/package.json b/npm/win32-ia32/package.json index c0501960d..e92a3bc92 100644 --- a/npm/win32-ia32/package.json +++ b/npm/win32-ia32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-ia32", - "version": "0.34.4-rc.4", + "version": "0.34.4", "description": "Prebuilt sharp for use with Windows x86 (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-x64/package.json b/npm/win32-x64/package.json index c93fae480..ea1c7cdda 100644 --- a/npm/win32-x64/package.json +++ b/npm/win32-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-x64", - "version": "0.34.4-rc.4", + "version": "0.34.4", "description": "Prebuilt sharp for use with Windows x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/package.json b/package.json index 8bfa71049..39547c807 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "sharp", "description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images", - "version": "0.34.4-rc.4", + "version": "0.34.4", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", "contributors": [ @@ -142,8 +142,8 @@ "semver": "^7.7.2" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.4-rc.4", - "@img/sharp-darwin-x64": "0.34.4-rc.4", + "@img/sharp-darwin-arm64": "0.34.4", + "@img/sharp-darwin-x64": "0.34.4", "@img/sharp-libvips-darwin-arm64": "1.2.3", "@img/sharp-libvips-darwin-x64": "1.2.3", "@img/sharp-libvips-linux-arm": "1.2.3", @@ -153,17 +153,17 @@ "@img/sharp-libvips-linux-x64": "1.2.3", "@img/sharp-libvips-linuxmusl-arm64": "1.2.3", "@img/sharp-libvips-linuxmusl-x64": "1.2.3", - "@img/sharp-linux-arm": "0.34.4-rc.4", - "@img/sharp-linux-arm64": "0.34.4-rc.4", - "@img/sharp-linux-ppc64": "0.34.4-rc.4", - "@img/sharp-linux-s390x": "0.34.4-rc.4", - "@img/sharp-linux-x64": "0.34.4-rc.4", - "@img/sharp-linuxmusl-arm64": "0.34.4-rc.4", - "@img/sharp-linuxmusl-x64": "0.34.4-rc.4", - "@img/sharp-wasm32": "0.34.4-rc.4", - "@img/sharp-win32-arm64": "0.34.4-rc.4", - "@img/sharp-win32-ia32": "0.34.4-rc.4", - "@img/sharp-win32-x64": "0.34.4-rc.4" + "@img/sharp-linux-arm": "0.34.4", + "@img/sharp-linux-arm64": "0.34.4", + "@img/sharp-linux-ppc64": "0.34.4", + "@img/sharp-linux-s390x": "0.34.4", + "@img/sharp-linux-x64": "0.34.4", + "@img/sharp-linuxmusl-arm64": "0.34.4", + "@img/sharp-linuxmusl-x64": "0.34.4", + "@img/sharp-wasm32": "0.34.4", + "@img/sharp-win32-arm64": "0.34.4", + "@img/sharp-win32-ia32": "0.34.4", + "@img/sharp-win32-x64": "0.34.4" }, "devDependencies": { "@emnapi/runtime": "^1.5.0", From a0af662d783466c8354e5555011934e8b05c7035 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Thu, 18 Sep 2025 12:51:22 +0100 Subject: [PATCH 084/115] CI: Separate platform-independent linter tasks Run these before platform-specific build/testing tasks --- .github/workflows/ci.yml | 51 +++++++++++++++++++++++----------------- package.json | 12 ++++++---- 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f126419a..b777acb99 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,9 +4,24 @@ on: - pull_request permissions: {} jobs: + lint: + permissions: + contents: read + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v5 + with: + node-version: "24" + - run: npm install --ignore-scripts --omit=optional + - run: npm run lint-cpp + - run: npm run lint-js + - run: npm run lint-licensing + - run: npm run lint-types build-native: permissions: contents: read + needs: lint name: "build-${{ matrix.platform }} [Node.js ${{ matrix.nodejs_version_major }}] ${{ matrix.package && '[package]' }}" runs-on: ${{ matrix.os }} container: ${{ matrix.container }} @@ -150,17 +165,14 @@ jobs: python-version: "3.12" - name: Dependencies (Node.js) if: "!contains(matrix.platform, 'linuxmusl')" - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: ${{ matrix.nodejs_version }} architecture: ${{ matrix.nodejs_arch }} - uses: actions/checkout@v4 - - name: Install - run: npm install --build-from-source - - name: Test - run: npm test - - name: Populate npm package - if: matrix.package + - run: npm install --build-from-source + - run: npm run test-unit + - if: matrix.package run: npm run package-from-local-build - uses: actions/upload-artifact@v4 if: matrix.package @@ -172,6 +184,7 @@ jobs: build-linuxmusl-arm64: permissions: contents: read + needs: lint name: "build-linuxmusl-arm64 [Node.js ${{ matrix.nodejs_version_major }}] ${{ matrix.package && '[package]' }}" runs-on: ubuntu-24.04-arm container: @@ -199,12 +212,9 @@ jobs: - name: Dependencies run: apk add build-base git python3 font-noto --update-cache - uses: actions/checkout@v4 - - name: Install - run: npm install --build-from-source - - name: Test - run: npm test - - name: Populate npm package - if: matrix.package + - run: npm install --build-from-source + - run: npm run test-unit + - if: matrix.package run: npm run package-from-local-build - uses: actions/upload-artifact@v4 if: matrix.package @@ -216,6 +226,7 @@ jobs: build-qemu: permissions: contents: read + needs: lint name: "build-${{ matrix.platform }} [Node.js ${{ matrix.nodejs_version_major }}] [package]" runs-on: ubuntu-24.04 strategy: @@ -267,6 +278,7 @@ jobs: build-emscripten: permissions: contents: read + needs: lint name: "build-wasm32 [package]" runs-on: ubuntu-24.04 container: "emscripten/emsdk:4.0.14" @@ -275,11 +287,10 @@ jobs: - name: Dependencies run: apt-get update && apt-get install -y pkg-config - name: Dependencies (Node.js) - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: "20" - - name: Install - run: emmake npm install --build-from-source + - run: emmake npm install --build-from-source - name: Verify emscripten versions match run: | EMSCRIPTEN_VERSION_LIBVIPS=$(node -p "require('@img/sharp-libvips-dev-wasm32/versions').emscripten") @@ -287,10 +298,8 @@ jobs: echo "libvips built with emscripten $EMSCRIPTEN_VERSION_LIBVIPS" echo "sharp built with emscripten $EMSCRIPTEN_VERSION_SHARP" test "$EMSCRIPTEN_VERSION_LIBVIPS" = "$EMSCRIPTEN_VERSION_SHARP" - - name: Test - run: emmake npm test - - name: Populate npm package - run: emmake npm run package-from-local-build + - run: emmake npm run test-unit + - run: emmake npm run package-from-local-build - uses: actions/upload-artifact@v4 with: name: wasm32 @@ -314,7 +323,7 @@ jobs: path: npm - name: Create npm workspace tarball run: tar -vcaf npm-workspace.tar.xz --directory npm --exclude=from-local-build.js . - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v5 with: node-version: '24' - name: Create release notes diff --git a/package.json b/package.json index 39547c807..82f92e040 100644 --- a/package.json +++ b/package.json @@ -94,12 +94,14 @@ "scripts": { "install": "node install/check.js", "clean": "rm -rf src/build/ .nyc_output/ coverage/ test/fixtures/output.*", - "test": "npm run test-lint && npm run test-unit && npm run test-licensing && npm run test-types", - "test-lint": "semistandard && cpplint", - "test-unit": "nyc --reporter=lcov --reporter=text --check-coverage --branches=100 mocha", - "test-licensing": "license-checker --production --summary --onlyAllow=\"Apache-2.0;BSD;ISC;LGPL-3.0-or-later;MIT\"", + "test": "npm run lint && npm run test-unit", + "lint": "npm run lint-cpp && npm run lint-js && npm run lint-licensing && npm run lint-types", + "lint-cpp": "cpplint", + "lint-js": "semistandard", + "lint-licensing": "license-checker --production --summary --onlyAllow=\"Apache-2.0;BSD;ISC;LGPL-3.0-or-later;MIT\"", + "lint-types": "tsd", "test-leak": "./test/leak/leak.sh", - "test-types": "tsd", + "test-unit": "nyc --reporter=lcov --reporter=text --check-coverage --branches=100 mocha", "package-from-local-build": "node npm/from-local-build.js", "package-release-notes": "node npm/release-notes.js", "docs-build": "node docs/build.mjs", From b36237ddcbc5b9bbdc9c94e7d71989fd57b4f76a Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Wed, 17 Sep 2025 16:47:33 +0100 Subject: [PATCH 085/115] Switch linter from semistandard to biome Uses the recommended rules apart from complexity/useArrowFunction, which would affect about 1700 lines of code with little benefit right now. This is something that can be addressed over time. --- .editorconfig | 4 +--- .github/workflows/ci.yml | 2 +- biome.json | 29 +++++++++++++++++++++++++++ docs/astro.config.mjs | 2 +- docs/build.mjs | 2 -- install/check.js | 6 ++---- lib/channel.js | 2 -- lib/colour.js | 2 -- lib/composite.js | 2 -- lib/constructor.js | 3 +-- lib/index.d.ts | 2 +- lib/index.js | 2 -- lib/input.js | 10 ++++------ lib/is.js | 2 -- lib/libvips.js | 4 +--- lib/operation.js | 2 -- lib/output.js | 2 -- lib/resize.js | 2 -- lib/sharp.js | 4 +--- lib/utility.js | 2 -- npm/from-local-build.js | 2 -- package.json | 9 ++------- test/beforeEach.js | 2 -- test/bench/parallel.js | 13 +++++-------- test/bench/perf.js | 22 ++++++++++----------- test/bench/random.js | 6 ++---- test/fixtures/index.js | 10 ++++------ test/types/sharp.test-d.ts | 7 +++++-- test/unit/affine.js | 4 +--- test/unit/alpha.js | 12 +++++------- test/unit/avif.js | 24 +++++++++++------------ test/unit/bandbool.js | 10 ++++------ test/unit/blur.js | 4 +--- test/unit/boolean.js | 18 ++++++++--------- test/unit/clahe.js | 4 +--- test/unit/clone.js | 6 ++---- test/unit/colourspace.js | 4 +--- test/unit/composite.js | 8 +++----- test/unit/convolve.js | 4 +--- test/unit/dilate.js | 4 +--- test/unit/erode.js | 4 +--- test/unit/extend.js | 4 +--- test/unit/extract.js | 4 +--- test/unit/extractChannel.js | 4 +--- test/unit/failOn.js | 8 +++----- test/unit/fixtures.js | 4 +--- test/unit/gamma.js | 4 +--- test/unit/gif.js | 6 ++---- test/unit/heif.js | 4 +--- test/unit/io.js | 39 ++++++++++++++----------------------- test/unit/join.js | 4 +--- test/unit/joinChannel.js | 6 ++---- test/unit/jp2.js | 6 ++---- test/unit/jpeg.js | 4 +--- test/unit/jxl.js | 4 +--- test/unit/libvips.js | 6 ++---- test/unit/linear.js | 12 +++++------- test/unit/median.js | 4 +--- test/unit/metadata.js | 8 +++----- test/unit/modulate.js | 4 +--- test/unit/negate.js | 6 ++---- test/unit/noise.js | 4 +--- test/unit/normalize.js | 16 +++++++-------- test/unit/png.js | 7 +++---- test/unit/raw.js | 32 ++++++++++++++---------------- test/unit/recomb.js | 4 +--- test/unit/resize-contain.js | 4 +--- test/unit/resize-cover.js | 4 +--- test/unit/resize.js | 12 +++++------- test/unit/rotate.js | 20 +++++++++---------- test/unit/sharpen.js | 4 +--- test/unit/stats.js | 12 +++++------- test/unit/svg.js | 6 ++---- test/unit/text.js | 4 +--- test/unit/threshold.js | 6 ++---- test/unit/tiff.js | 6 ++---- test/unit/tile.js | 36 ++++++++++++++++------------------ test/unit/timeout.js | 4 +--- test/unit/tint.js | 4 +--- test/unit/toBuffer.js | 4 +--- test/unit/toFormat.js | 4 +--- test/unit/trim.js | 4 +--- test/unit/unflatten.js | 2 -- test/unit/util.js | 4 +--- test/unit/webp.js | 6 ++---- 85 files changed, 238 insertions(+), 375 deletions(-) create mode 100644 biome.json diff --git a/.editorconfig b/.editorconfig index 5760be583..62fb51fed 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,6 +7,4 @@ indent_size = 2 charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true - -[*.md] -trim_trailing_whitespace = false +max_line_length = 120 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b777acb99..c815127ff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/setup-node@v5 with: node-version: "24" - - run: npm install --ignore-scripts --omit=optional + - run: npm install --ignore-scripts - run: npm run lint-cpp - run: npm run lint-js - run: npm run lint-licensing diff --git a/biome.json b/biome.json new file mode 100644 index 000000000..2ed1c1042 --- /dev/null +++ b/biome.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.2.4/schema.json", + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + }, + "files": { + "ignoreUnknown": true + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "complexity": { + "useArrowFunction": "off" + } + } + }, + "formatter": { + "enabled": false, + "useEditorconfig": true + }, + "javascript": { + "formatter": { + "quoteStyle": "single" + } + } +} diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index 49b1c00e8..2209c3381 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -1,6 +1,6 @@ // @ts-check -import { defineConfig } from 'astro/config'; import starlight from '@astrojs/starlight'; +import { defineConfig } from 'astro/config'; import starlightAutoSidebar from 'starlight-auto-sidebar'; import { version } from '../package.json'; diff --git a/docs/build.mjs b/docs/build.mjs index de4d8b716..522e6cd96 100644 --- a/docs/build.mjs +++ b/docs/build.mjs @@ -1,8 +1,6 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - import fs from 'node:fs/promises'; import path from 'node:path'; import jsdoc2md from 'jsdoc-to-markdown'; diff --git a/install/check.js b/install/check.js index 0e00133ab..8e96da86e 100644 --- a/install/check.js +++ b/install/check.js @@ -1,8 +1,6 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - try { const { useGlobalLibvips, globalLibvipsVersion, log, spawnRebuild } = require('../lib/libvips'); @@ -12,14 +10,14 @@ try { try { const addonApi = require('node-addon-api'); log(`Found node-addon-api ${addonApi.version || ''}`); - } catch (err) { + } catch (_err) { log('Please add node-addon-api to your dependencies'); return; } try { const gyp = require('node-gyp'); log(`Found node-gyp ${gyp().version}`); - } catch (err) { + } catch (_err) { log('Please add node-gyp to your dependencies'); return; } diff --git a/lib/channel.js b/lib/channel.js index b6381ae9b..bb1368cb1 100644 --- a/lib/channel.js +++ b/lib/channel.js @@ -1,8 +1,6 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - const is = require('./is'); /** diff --git a/lib/colour.js b/lib/colour.js index e17b77bd2..8de8d3326 100644 --- a/lib/colour.js +++ b/lib/colour.js @@ -1,8 +1,6 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - const color = require('@img/colour'); const is = require('./is'); diff --git a/lib/composite.js b/lib/composite.js index 98f8aefef..1d41ba9d0 100644 --- a/lib/composite.js +++ b/lib/composite.js @@ -1,8 +1,6 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - const is = require('./is'); /** diff --git a/lib/constructor.js b/lib/constructor.js index a349f42a7..82acbd08e 100644 --- a/lib/constructor.js +++ b/lib/constructor.js @@ -1,8 +1,6 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - const util = require('node:util'); const stream = require('node:stream'); const is = require('./is'); @@ -205,6 +203,7 @@ const debuglog = util.debuglog('sharp'); * @throws {Error} Invalid parameters */ const Sharp = function (input, options) { + // biome-ignore lint/complexity/noArguments: constructor factory if (arguments.length === 1 && !is.defined(input)) { throw new Error('Invalid input'); } diff --git a/lib/index.d.ts b/lib/index.d.ts index 412363450..83e010d80 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -27,7 +27,7 @@ /// -import { Duplex } from 'stream'; +import type { Duplex } from 'node:stream'; //#region Constructor functions diff --git a/lib/index.js b/lib/index.js index 8cfc08a80..cb632edfe 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,8 +1,6 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - const Sharp = require('./constructor'); require('./input')(Sharp); require('./resize')(Sharp); diff --git a/lib/input.js b/lib/input.js index aca0b16c9..f6a869227 100644 --- a/lib/input.js +++ b/lib/input.js @@ -1,8 +1,6 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - const is = require('./is'); const sharp = require('./sharp'); @@ -54,7 +52,7 @@ function _createInputDescriptor (input, inputOptions, containerOptions) { const inputDescriptor = { autoOrient: false, failOn: 'warning', - limitInputPixels: Math.pow(0x3FFF, 2), + limitInputPixels: 0x3FFF ** 2, ignoreIcc: false, unlimited: false, sequentialRead: true @@ -150,7 +148,7 @@ function _createInputDescriptor (input, inputOptions, containerOptions) { if (is.defined(inputOptions.limitInputPixels)) { if (is.bool(inputOptions.limitInputPixels)) { inputDescriptor.limitInputPixels = inputOptions.limitInputPixels - ? Math.pow(0x3FFF, 2) + ? 0x3FFF ** 2 : 0; } else if (is.integer(inputOptions.limitInputPixels) && is.inRange(inputOptions.limitInputPixels, 0, Number.MAX_SAFE_INTEGER)) { inputDescriptor.limitInputPixels = inputOptions.limitInputPixels; @@ -513,7 +511,7 @@ function _createInputDescriptor (input, inputOptions, containerOptions) { } } } else if (is.defined(inputOptions)) { - throw new Error('Invalid input options ' + inputOptions); + throw new Error(`Invalid input options ${inputOptions}`); } return inputDescriptor; } @@ -525,7 +523,7 @@ function _createInputDescriptor (input, inputOptions, containerOptions) { * @param {string} encoding - unused * @param {Function} callback */ -function _write (chunk, encoding, callback) { +function _write (chunk, _encoding, callback) { /* istanbul ignore else */ if (Array.isArray(this.options.input.buffer)) { /* istanbul ignore else */ diff --git a/lib/is.js b/lib/is.js index a63cb2066..c61b6bbd9 100644 --- a/lib/is.js +++ b/lib/is.js @@ -1,8 +1,6 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - /** * Is this value defined and not null? * @private diff --git a/lib/libvips.js b/lib/libvips.js index 1bab0ca51..96edde12a 100644 --- a/lib/libvips.js +++ b/lib/libvips.js @@ -1,8 +1,6 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - const { spawnSync } = require('node:child_process'); const { createHash } = require('node:crypto'); const semverCoerce = require('semver/functions/coerce'); @@ -96,7 +94,7 @@ const isUnsupportedNodeRuntime = () => { /* istanbul ignore next */ const isEmscripten = () => { const { CC } = process.env; - return Boolean(CC && CC.endsWith('/emcc')); + return Boolean(CC?.endsWith('/emcc')); }; const isRosetta = () => { diff --git a/lib/operation.js b/lib/operation.js index f76f65dc3..824da9110 100644 --- a/lib/operation.js +++ b/lib/operation.js @@ -1,8 +1,6 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - const is = require('./is'); /** diff --git a/lib/output.js b/lib/output.js index f1cdaf842..653215596 100644 --- a/lib/output.js +++ b/lib/output.js @@ -1,8 +1,6 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - const path = require('node:path'); const is = require('./is'); const sharp = require('./sharp'); diff --git a/lib/resize.js b/lib/resize.js index 9e4aa78a4..287d0ae3f 100644 --- a/lib/resize.js +++ b/lib/resize.js @@ -1,8 +1,6 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - const is = require('./is'); /** diff --git a/lib/sharp.js b/lib/sharp.js index 78853e95f..8a90d826a 100644 --- a/lib/sharp.js +++ b/lib/sharp.js @@ -1,8 +1,6 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - // Inspects the runtime environment and exports the relevant sharp.node binary const { familySync, versionSync } = require('detect-libc'); @@ -88,7 +86,7 @@ if (sharp) { ` Found ${libcFound}`, ` Requires ${libcRequires}` ); - } catch (errEngines) {} + } catch (_errEngines) {} } if (isLinux && /\/snap\/core[0-9]{2}/.test(messages)) { help.push( diff --git a/lib/utility.js b/lib/utility.js index 4b11892d5..d91605e53 100644 --- a/lib/utility.js +++ b/lib/utility.js @@ -1,8 +1,6 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - const events = require('node:events'); const detectLibc = require('detect-libc'); diff --git a/npm/from-local-build.js b/npm/from-local-build.js index 2fee2db9c..76719cb3c 100644 --- a/npm/from-local-build.js +++ b/npm/from-local-build.js @@ -1,8 +1,6 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - // Populate the npm package for the current platform with the local build const { copyFileSync, cpSync, readFileSync, writeFileSync, appendFileSync } = require('node:fs'); diff --git a/package.json b/package.json index 82f92e040..4dd623861 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,7 @@ "test": "npm run lint && npm run test-unit", "lint": "npm run lint-cpp && npm run lint-js && npm run lint-licensing && npm run lint-types", "lint-cpp": "cpplint", - "lint-js": "semistandard", + "lint-js": "biome lint", "lint-licensing": "license-checker --production --summary --onlyAllow=\"Apache-2.0;BSD;ISC;LGPL-3.0-or-later;MIT\"", "lint-types": "tsd", "test-leak": "./test/leak/leak.sh", @@ -168,6 +168,7 @@ "@img/sharp-win32-x64": "0.34.4" }, "devDependencies": { + "@biomejs/biome": "^2.2.4", "@emnapi/runtime": "^1.5.0", "@img/sharp-libvips-dev": "1.2.3", "@img/sharp-libvips-dev-wasm32": "1.2.3", @@ -186,7 +187,6 @@ "node-addon-api": "^8.5.0", "node-gyp": "^11.4.2", "nyc": "^17.1.0", - "semistandard": "^17.0.0", "tar-fs": "^3.1.1", "tsd": "^0.33.0" }, @@ -200,11 +200,6 @@ "funding": { "url": "https://opencollective.com/libvips" }, - "semistandard": { - "env": [ - "mocha" - ] - }, "cc": { "linelength": "120", "filter": [ diff --git a/test/beforeEach.js b/test/beforeEach.js index 5a4d4feae..586869fe3 100644 --- a/test/beforeEach.js +++ b/test/beforeEach.js @@ -1,8 +1,6 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - const sharp = require('../'); const usingCache = !process.env.G_DEBUG; diff --git a/test/bench/parallel.js b/test/bench/parallel.js index 5c2568c5b..7f2c4aaa9 100644 --- a/test/bench/parallel.js +++ b/test/bench/parallel.js @@ -1,11 +1,9 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - process.env.UV_THREADPOOL_SIZE = 64; -const assert = require('assert'); +const assert = require('node:assert'); const async = require('async'); const sharp = require('../../'); @@ -21,13 +19,12 @@ const timer = setInterval(function () { }, 100); async.mapSeries([1, 1, 2, 4, 8, 16, 32, 64], function (parallelism, next) { - const start = new Date().getTime(); + const start = Date.now(); async.times(parallelism, - function (id, callback) { - /* jslint unused: false */ + function (_id, callback) { sharp(fixtures.inputJpg).resize(width, height).toBuffer(function (err, buffer) { buffer = null; - callback(err, new Date().getTime() - start); + callback(err, Date.now() - start); }); }, function (err, ids) { @@ -37,7 +34,7 @@ async.mapSeries([1, 1, 2, 4, 8, 16, 32, 64], function (parallelism, next) { const mean = ids.reduce(function (a, b) { return a + b; }) / ids.length; - console.log(parallelism + ' parallel calls: fastest=' + ids[0] + 'ms slowest=' + ids[ids.length - 1] + 'ms mean=' + mean + 'ms'); + console.log(`${parallelism} parallel calls: fastest=${ids[0]}ms slowest=${ids[ids.length - 1]}ms mean=${mean}ms`); next(); } ); diff --git a/test/bench/perf.js b/test/bench/perf.js index eef42808f..c10802c7b 100644 --- a/test/bench/perf.js +++ b/test/bench/perf.js @@ -1,10 +1,8 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const fs = require('fs'); -const { execSync } = require('child_process'); +const fs = require('node:fs'); +const { execSync } = require('node:child_process'); const async = require('async'); const Benchmark = require('benchmark'); @@ -12,7 +10,7 @@ const Benchmark = require('benchmark'); const safeRequire = (name) => { try { return require(name); - } catch (err) {} + } catch (_err) {} return null; }; @@ -280,7 +278,7 @@ async.series({ }); } }).on('cycle', function (event) { - console.log('jpeg ' + String(event.target)); + console.log(`jpeg ${String(event.target)}`); }).on('complete', function () { callback(null, this.filter('fastest').map('name')); }).run(); @@ -505,7 +503,7 @@ async.series({ }); } }).on('cycle', function (event) { - console.log('operations ' + String(event.target)); + console.log(`operations ${String(event.target)}`); }).on('complete', function () { callback(null, this.filter('fastest').map('name')); }).run(); @@ -579,7 +577,7 @@ async.series({ }); } }).on('cycle', function (event) { - console.log('kernels ' + String(event.target)); + console.log(`kernels ${String(event.target)}`); }).on('complete', function () { callback(null, this.filter('fastest').map('name')); }).run(); @@ -735,7 +733,7 @@ async.series({ sharp(inputPngBuffer) .resize(width, heightPng) .png({ compressionLevel: 6 }) - .toBuffer(function (err, data) { + .toBuffer(function (err) { if (err) { throw err; } else { @@ -820,7 +818,7 @@ async.series({ } }); pngSuite.on('cycle', function (event) { - console.log(' png ' + String(event.target)); + console.log(` png ${String(event.target)}`); }).on('complete', function () { callback(null, this.filter('fastest').map('name')); }).run(); @@ -881,7 +879,7 @@ async.series({ }); } }).on('cycle', function (event) { - console.log('webp ' + String(event.target)); + console.log(`webp ${String(event.target)}`); }).on('complete', function () { callback(null, this.filter('fastest').map('name')); }).run(); @@ -892,7 +890,7 @@ async.series({ } Object.keys(results).forEach(function (format) { if (results[format].toString().substr(0, 5) !== 'sharp') { - console.log('sharp was slower than ' + results[format] + ' for ' + format); + console.log(`sharp was slower than ${results[format]} for ${format}`); } }); console.dir(sharp.cache()); diff --git a/test/bench/random.js b/test/bench/random.js index 6c6a23786..fa575d355 100644 --- a/test/bench/random.js +++ b/test/bench/random.js @@ -1,11 +1,9 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - const imagemagick = require('imagemagick'); const gm = require('gm'); -const assert = require('assert'); +const assert = require('node:assert'); const Benchmark = require('benchmark'); const sharp = require('../../'); @@ -73,5 +71,5 @@ new Benchmark.Suite('random').add('imagemagick', { console.log(String(event.target)); }).on('complete', function () { const winner = this.filter('fastest').map('name'); - assert.strictEqual('sharp', String(winner), 'sharp was slower than ' + winner); + assert.strictEqual('sharp', String(winner), `sharp was slower than ${winner}`); }).run(); diff --git a/test/fixtures/index.js b/test/fixtures/index.js index b69d64656..153eb37b4 100644 --- a/test/fixtures/index.js +++ b/test/fixtures/index.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const path = require('path'); +const path = require('node:path'); const sharp = require('../../'); const maxColourDistance = require('../../lib/sharp')._maxColourDistance; @@ -196,10 +194,10 @@ module.exports = { assertMaxColourDistance: function (actualImagePath, expectedImagePath, acceptedDistance) { if (typeof actualImagePath !== 'string') { - throw new TypeError('`actualImagePath` must be a string; got ' + actualImagePath); + throw new TypeError(`\`actualImagePath\` must be a string; got ${actualImagePath}`); } if (typeof expectedImagePath !== 'string') { - throw new TypeError('`expectedImagePath` must be a string; got ' + expectedImagePath); + throw new TypeError(`\`expectedImagePath\` must be a string; got ${expectedImagePath}`); } if (typeof acceptedDistance !== 'number') { // Default threshold @@ -207,7 +205,7 @@ module.exports = { } const distance = maxColourDistance(actualImagePath, expectedImagePath); if (distance > acceptedDistance) { - throw new Error('Expected maximum absolute distance of ' + acceptedDistance + ', actual ' + distance); + throw new Error(`Expected maximum absolute distance of ${acceptedDistance}, actual ${distance}`); } } diff --git a/test/types/sharp.test-d.ts b/test/types/sharp.test-d.ts index 27e5ec462..9c6e78506 100644 --- a/test/types/sharp.test-d.ts +++ b/test/types/sharp.test-d.ts @@ -1,6 +1,9 @@ +// biome-ignore-all lint/correctness/noUnusedFunctionParameters: types only test file +// biome-ignore-all lint/correctness/noUnusedVariables: types only test file + import sharp = require('../../'); -import { createReadStream, createWriteStream } from 'fs'; +import { createReadStream, createWriteStream } from 'node:fs'; const input: Buffer = Buffer.alloc(0); const readableStream: NodeJS.ReadableStream = createReadStream(input); @@ -79,7 +82,7 @@ sharp({ let transformer = sharp() .resize(300) .on('info', (info: sharp.OutputInfo) => { - console.log('Image height is ' + info.height); + console.log(`Image height is ${info.height}`); }); readableStream.pipe(transformer).pipe(writableStream); diff --git a/test/unit/affine.js b/test/unit/affine.js index 2122f0072..6ff523be8 100644 --- a/test/unit/affine.js +++ b/test/unit/affine.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/alpha.js b/test/unit/alpha.js index c7c0d6e6c..13b3bc279 100644 --- a/test/unit/alpha.js +++ b/test/unit/alpha.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const fixtures = require('../fixtures'); const sharp = require('../../'); @@ -67,7 +65,7 @@ describe('Alpha transparency', function () { it('Do not flatten', function (done) { sharp(fixtures.inputPngWithTransparency) .flatten(false) - .toBuffer(function (err, data, info) { + .toBuffer(function (err, _data, info) { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(4, info.channels); @@ -78,7 +76,7 @@ describe('Alpha transparency', function () { it('Ignored for JPEG', function (done) { sharp(fixtures.inputJpg) .flatten({ background: '#ff0000' }) - .toBuffer(function (err, data, info) { + .toBuffer(function (err, _data, info) { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(3, info.channels); @@ -100,7 +98,7 @@ describe('Alpha transparency', function () { it('Enlargement with non-nearest neighbor interpolation shouldn’t cause dark edges', function () { const base = 'alpha-premultiply-enlargement-2048x1536-paper.png'; - const actual = fixtures.path('output.' + base); + const actual = fixtures.path(`output.${base}`); const expected = fixtures.expected(base); return sharp(fixtures.inputPngAlphaPremultiplicationSmall) .resize(2048, 1536) @@ -112,7 +110,7 @@ describe('Alpha transparency', function () { it('Reduction with non-nearest neighbor interpolation shouldn’t cause dark edges', function () { const base = 'alpha-premultiply-reduction-1024x768-paper.png'; - const actual = fixtures.path('output.' + base); + const actual = fixtures.path(`output.${base}`); const expected = fixtures.expected(base); return sharp(fixtures.inputPngAlphaPremultiplicationLarge) .resize(1024, 768) diff --git a/test/unit/avif.js b/test/unit/avif.js index 9eeb50000..8f3cb606d 100644 --- a/test/unit/avif.js +++ b/test/unit/avif.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const { inputAvif, inputJpg, inputGifAnimated } = require('../fixtures'); @@ -20,8 +18,8 @@ describe('AVIF', () => { .resize(32) .jpeg() .toBuffer(); - const { size, ...metadata } = await sharp(data) - .metadata(); + const { size, ...metadata } = await sharp(data).metadata(); + void size; assert.deepStrictEqual(metadata, { autoOrient: { height: 13, @@ -49,8 +47,8 @@ describe('AVIF', () => { .resize(32) .avif({ effort: 0 }) .toBuffer(); - const { size, ...metadata } = await sharp(data) - .metadata(); + const { size, ...metadata } = await sharp(data).metadata(); + void size; assert.deepStrictEqual(metadata, { autoOrient: { height: 26, @@ -77,8 +75,8 @@ describe('AVIF', () => { const data = await sharp(inputAvif) .resize(32) .toBuffer(); - const { size, ...metadata } = await sharp(data) - .metadata(); + const { size, ...metadata } = await sharp(data).metadata(); + void size; assert.deepStrictEqual(metadata, { autoOrient: { height: 13, @@ -106,8 +104,8 @@ describe('AVIF', () => { .resize(10) .avif({ effort: 0 }) .toBuffer(); - const { size, ...metadata } = await sharp(data) - .metadata(); + const { size, ...metadata } = await sharp(data).metadata(); + void size; assert.deepStrictEqual(metadata, { autoOrient: { height: 300, @@ -136,8 +134,8 @@ describe('AVIF', () => { .sharpen() .avif({ effort: 0 }) .toBuffer(); - const { size, ...metadata } = await sharp(data) - .metadata(); + const { size, ...metadata } = await sharp(data).metadata(); + void size; assert.deepStrictEqual(metadata, { autoOrient: { height: 26, diff --git a/test/unit/bandbool.js b/test/unit/bandbool.js index 66ad404cb..5fad6590a 100644 --- a/test/unit/bandbool.js +++ b/test/unit/bandbool.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const fixtures = require('../fixtures'); const sharp = require('../../'); @@ -14,7 +12,7 @@ describe('Bandbool per-channel boolean operations', function () { sharp.bool.eor ] .forEach(function (op) { - it(op + ' operation', function (done) { + it(`${op} operation`, function (done) { sharp(fixtures.inputPngBooleanNoAlpha) .bandbool(op) .toColourspace('b-w') @@ -23,7 +21,7 @@ describe('Bandbool per-channel boolean operations', function () { assert.strictEqual(200, info.width); assert.strictEqual(200, info.height); assert.strictEqual(1, info.channels); - fixtures.assertSimilar(fixtures.expected('bandbool_' + op + '_result.png'), data, done); + fixtures.assertSimilar(fixtures.expected(`bandbool_${op}_result.png`), data, done); }); }); }); @@ -31,7 +29,7 @@ describe('Bandbool per-channel boolean operations', function () { it('sRGB image retains 3 channels', function (done) { sharp(fixtures.inputJpg) .bandbool('and') - .toBuffer(function (err, data, info) { + .toBuffer(function (err, _data, info) { if (err) throw err; assert.strictEqual(3, info.channels); done(); diff --git a/test/unit/blur.js b/test/unit/blur.js index facff648b..efa7163e5 100644 --- a/test/unit/blur.js +++ b/test/unit/blur.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/boolean.js b/test/unit/boolean.js index c5fcaf67d..e1c3e3f23 100644 --- a/test/unit/boolean.js +++ b/test/unit/boolean.js @@ -1,10 +1,8 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const fs = require('fs'); -const assert = require('assert'); +const fs = require('node:fs'); +const assert = require('node:assert'); const fixtures = require('../fixtures'); const sharp = require('../../'); @@ -18,7 +16,7 @@ describe('Boolean operation between two images', function () { sharp.bool.eor ] .forEach(function (op) { - it(op + ' operation, file', function (done) { + it(`${op} operation, file`, function (done) { sharp(fixtures.inputJpg) .resize(320, 240) .boolean(fixtures.inputJpgBooleanTest, op) @@ -26,11 +24,11 @@ describe('Boolean operation between two images', function () { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); - fixtures.assertSimilar(fixtures.expected('boolean_' + op + '_result.jpg'), data, done); + fixtures.assertSimilar(fixtures.expected(`boolean_${op}_result.jpg`), data, done); }); }); - it(op + ' operation, buffer', function (done) { + it(`${op} operation, buffer`, function (done) { sharp(fixtures.inputJpg) .resize(320, 240) .boolean(inputJpgBooleanTestBuffer, op) @@ -38,11 +36,11 @@ describe('Boolean operation between two images', function () { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); - fixtures.assertSimilar(fixtures.expected('boolean_' + op + '_result.jpg'), data, done); + fixtures.assertSimilar(fixtures.expected(`boolean_${op}_result.jpg`), data, done); }); }); - it(op + ' operation, raw', function (done) { + it(`${op} operation, raw`, function (done) { sharp(fixtures.inputJpgBooleanTest) .raw() .toBuffer(function (err, data, info) { @@ -54,7 +52,7 @@ describe('Boolean operation between two images', function () { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); - fixtures.assertSimilar(fixtures.expected('boolean_' + op + '_result.jpg'), data, done); + fixtures.assertSimilar(fixtures.expected(`boolean_${op}_result.jpg`), data, done); }); }); }); diff --git a/test/unit/clahe.js b/test/unit/clahe.js index 9c93536bf..8f459c4bd 100644 --- a/test/unit/clahe.js +++ b/test/unit/clahe.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../lib'); const fixtures = require('../fixtures'); diff --git a/test/unit/clone.js b/test/unit/clone.js index 0db81ae53..3ac46cee0 100644 --- a/test/unit/clone.js +++ b/test/unit/clone.js @@ -1,10 +1,8 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const fs = require('fs'); -const assert = require('assert'); +const fs = require('node:fs'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/colourspace.js b/test/unit/colourspace.js index 33e4e329b..e311f5fe9 100644 --- a/test/unit/colourspace.js +++ b/test/unit/colourspace.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/composite.js b/test/unit/composite.js index d748d8f76..c027b027d 100644 --- a/test/unit/composite.js +++ b/test/unit/composite.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const fixtures = require('../fixtures'); const sharp = require('../../'); @@ -322,7 +320,7 @@ describe('composite', () => { describe('string gravity', () => { Object.keys(sharp.gravity).forEach(gravity => { it(gravity, done => { - const expected = fixtures.expected('overlay-gravity-' + gravity + '.jpg'); + const expected = fixtures.expected(`overlay-gravity-${gravity}.jpg`); sharp(fixtures.inputJpg) .resize(80) .composite([{ @@ -344,7 +342,7 @@ describe('composite', () => { describe('tile and gravity', () => { Object.keys(sharp.gravity).forEach(gravity => { it(gravity, done => { - const expected = fixtures.expected('overlay-tile-gravity-' + gravity + '.jpg'); + const expected = fixtures.expected(`overlay-tile-gravity-${gravity}.jpg`); sharp(fixtures.inputJpg) .resize(80) .composite([{ diff --git a/test/unit/convolve.js b/test/unit/convolve.js index dfb8dd52c..31b2fb3e4 100644 --- a/test/unit/convolve.js +++ b/test/unit/convolve.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/dilate.js b/test/unit/dilate.js index 94588a285..eb092a147 100644 --- a/test/unit/dilate.js +++ b/test/unit/dilate.js @@ -1,6 +1,4 @@ -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/erode.js b/test/unit/erode.js index 4d2da81f0..1a1493053 100644 --- a/test/unit/erode.js +++ b/test/unit/erode.js @@ -1,6 +1,4 @@ -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/extend.js b/test/unit/extend.js index 3ddbd0e14..1c8eb3070 100644 --- a/test/unit/extend.js +++ b/test/unit/extend.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/extract.js b/test/unit/extract.js index c2eae90b4..53e4f8a09 100644 --- a/test/unit/extract.js +++ b/test/unit/extract.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/extractChannel.js b/test/unit/extractChannel.js index 2d19588ae..edb3978c8 100644 --- a/test/unit/extractChannel.js +++ b/test/unit/extractChannel.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/failOn.js b/test/unit/failOn.js index 650ba057f..48e758c0f 100644 --- a/test/unit/failOn.js +++ b/test/unit/failOn.js @@ -1,10 +1,8 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); -const fs = require('fs'); +const assert = require('node:assert'); +const fs = require('node:fs'); const sharp = require('../../lib'); const fixtures = require('../fixtures'); @@ -32,7 +30,7 @@ describe('failOn', () => { isWarningEmitted = true; }) .resize(32, 24) - .toBuffer(function (err, data, info) { + .toBuffer(function (err, _data, info) { if (err) throw err; assert.strictEqual(true, isWarningEmitted); assert.strictEqual('png', info.format); diff --git a/test/unit/fixtures.js b/test/unit/fixtures.js index fb0ee74ee..ee398958c 100644 --- a/test/unit/fixtures.js +++ b/test/unit/fixtures.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const fixtures = require('../fixtures'); describe('Test fixtures', function () { diff --git a/test/unit/gamma.js b/test/unit/gamma.js index 934a4519b..21a333436 100644 --- a/test/unit/gamma.js +++ b/test/unit/gamma.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/gif.js b/test/unit/gif.js index 61a3e199f..8ae20e957 100644 --- a/test/unit/gif.js +++ b/test/unit/gif.js @@ -1,10 +1,8 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const fs = require('fs'); -const assert = require('assert'); +const fs = require('node:fs'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/heif.js b/test/unit/heif.js index be304b3dd..af3ee62eb 100644 --- a/test/unit/heif.js +++ b/test/unit/heif.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); diff --git a/test/unit/io.js b/test/unit/io.js index a2ee4eb55..ed6decafc 100644 --- a/test/unit/io.js +++ b/test/unit/io.js @@ -1,11 +1,9 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const fs = require('fs'); -const path = require('path'); -const assert = require('assert'); +const fs = require('node:fs'); +const path = require('node:path'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); @@ -388,9 +386,8 @@ describe('Input/output', function () { }); it('Fail when output File is input File via Promise', function (done) { - sharp(fixtures.inputJpg).toFile(fixtures.inputJpg).then(function (data) { - assert(false); - done(); + sharp(fixtures.inputJpg).toFile(fixtures.inputJpg).then(function () { + done(new Error('Unexpectedly resolved Promise')); }).catch(function (err) { assert(err instanceof Error); assert.strictEqual('Cannot use same file for input and output', err.message); @@ -409,9 +406,8 @@ describe('Input/output', function () { it('Fail when output File is input File via Promise (relative output, absolute input)', function (done) { const relativePath = path.relative(process.cwd(), fixtures.inputJpg); - sharp(fixtures.inputJpg).toFile(relativePath).then(function (data) { - assert(false); - done(); + sharp(fixtures.inputJpg).toFile(relativePath).then(function () { + done(new Error('Unexpectedly resolved Promise')); }).catch(function (err) { assert(err instanceof Error); assert.strictEqual('Cannot use same file for input and output', err.message); @@ -430,9 +426,8 @@ describe('Input/output', function () { it('Fail when output File is input File via Promise (relative input, absolute output)', function (done) { const relativePath = path.relative(process.cwd(), fixtures.inputJpg); - sharp(relativePath).toFile(fixtures.inputJpg).then(function (data) { - assert(false); - done(); + sharp(relativePath).toFile(fixtures.inputJpg).then(function () { + done(new Error('Unexpectedly resolved Promise')); }).catch(function (err) { assert(err instanceof Error); assert.strictEqual('Cannot use same file for input and output', err.message); @@ -449,9 +444,8 @@ describe('Input/output', function () { }); it('Fail when output File is empty via Promise', function (done) { - sharp(fixtures.inputJpg).toFile('').then(function (data) { - assert(false); - done(); + sharp(fixtures.inputJpg).toFile('').then(function () { + done(new Error('Unexpectedly resolved Promise')); }).catch(function (err) { assert(err instanceof Error); assert.strictEqual('Missing output file path', err.message); @@ -522,7 +516,7 @@ describe('Input/output', function () { try { sharp().toFormat('zoinks'); isValid = true; - } catch (e) {} + } catch (_err) {} assert(!isValid); done(); }); @@ -633,7 +627,7 @@ describe('Input/output', function () { sharp(fixtures.inputJpg) .resize(320, 240) .png({ compressionLevel: 1, force: false }) - .toBuffer(function (err, data, info) { + .toBuffer(function (err, _data, info) { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -1059,7 +1053,7 @@ describe('Input/output', function () { }); const badPipeline = sharp({ raw: { width: 840, height: 500, channels: 3 } }) .toFormat('jpeg') - .toBuffer(function (err, data, info) { + .toBuffer(function (err) { assert.strictEqual(err.message.indexOf('memory area too small') > 0, true); const readable = fs.createReadStream(fixtures.inputJPGBig); const inPipeline = sharp() @@ -1067,10 +1061,7 @@ describe('Input/output', function () { .raw(); const goodPipeline = sharp({ raw: { width: 840, height: 472, channels: 3 } }) .toFormat('jpeg') - .toBuffer(function (err, data, info) { - if (err) throw err; - done(); - }); + .toBuffer(done); readable.pipe(inPipeline).pipe(goodPipeline); }); readable.pipe(inPipeline).pipe(badPipeline); diff --git a/test/unit/join.js b/test/unit/join.js index 0e14e97e4..600ffb9a0 100644 --- a/test/unit/join.js +++ b/test/unit/join.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/joinChannel.js b/test/unit/joinChannel.js index acc0e7676..42bc23830 100644 --- a/test/unit/joinChannel.js +++ b/test/unit/joinChannel.js @@ -1,10 +1,8 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); -const fs = require('fs'); +const assert = require('node:assert'); +const fs = require('node:fs'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/jp2.js b/test/unit/jp2.js index 3fd2f4a65..30b458ac6 100644 --- a/test/unit/jp2.js +++ b/test/unit/jp2.js @@ -1,10 +1,8 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const fs = require('fs'); -const assert = require('assert'); +const fs = require('node:fs'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/jpeg.js b/test/unit/jpeg.js index 6f7ca978f..916d23587 100644 --- a/test/unit/jpeg.js +++ b/test/unit/jpeg.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/jxl.js b/test/unit/jxl.js index 32200407c..7fcfd75fe 100644 --- a/test/unit/jxl.js +++ b/test/unit/jxl.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); diff --git a/test/unit/libvips.js b/test/unit/libvips.js index ded3f8bb7..dfd61b260 100644 --- a/test/unit/libvips.js +++ b/test/unit/libvips.js @@ -1,10 +1,8 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); -const fs = require('fs'); +const assert = require('node:assert'); +const fs = require('node:fs'); const semver = require('semver'); const libvips = require('../../lib/libvips'); diff --git a/test/unit/linear.js b/test/unit/linear.js index d668aabdf..0ac952f22 100644 --- a/test/unit/linear.js +++ b/test/unit/linear.js @@ -1,12 +1,10 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - const sharp = require('../../'); const fixtures = require('../fixtures'); -const assert = require('assert'); +const assert = require('node:assert'); describe('Linear adjustment', function () { const blackPoint = 70; @@ -17,7 +15,7 @@ describe('Linear adjustment', function () { it('applies linear levels adjustment w/o alpha ch', function (done) { sharp(fixtures.inputJpgWithLowContrast) .linear(a, b) - .toBuffer(function (err, data, info) { + .toBuffer(function (err, data) { if (err) throw err; fixtures.assertSimilar(fixtures.expected('low-contrast-linear.jpg'), data, done); }); @@ -26,7 +24,7 @@ describe('Linear adjustment', function () { it('applies slope level adjustment w/o alpha ch', function (done) { sharp(fixtures.inputJpgWithLowContrast) .linear(a) - .toBuffer(function (err, data, info) { + .toBuffer(function (err, data) { if (err) throw err; fixtures.assertSimilar(fixtures.expected('low-contrast-slope.jpg'), data, done); }); @@ -35,7 +33,7 @@ describe('Linear adjustment', function () { it('applies offset level adjustment w/o alpha ch', function (done) { sharp(fixtures.inputJpgWithLowContrast) .linear(null, b) - .toBuffer(function (err, data, info) { + .toBuffer(function (err, data) { if (err) throw err; fixtures.assertSimilar(fixtures.expected('low-contrast-offset.jpg'), data, done); }); @@ -83,7 +81,7 @@ describe('Linear adjustment', function () { it('per channel level adjustment', function (done) { sharp(fixtures.inputWebP) - .linear([0.25, 0.5, 0.75], [150, 100, 50]).toBuffer(function (err, data, info) { + .linear([0.25, 0.5, 0.75], [150, 100, 50]).toBuffer(function (err, data) { if (err) throw err; fixtures.assertSimilar(fixtures.expected('linear-per-channel.jpg'), data, done); }); diff --git a/test/unit/median.js b/test/unit/median.js index b11ab5d4d..227e4c609 100644 --- a/test/unit/median.js +++ b/test/unit/median.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); diff --git a/test/unit/metadata.js b/test/unit/metadata.js index 14f48afa5..4b3ee6c5d 100644 --- a/test/unit/metadata.js +++ b/test/unit/metadata.js @@ -1,10 +1,8 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const fs = require('fs'); -const assert = require('assert'); +const fs = require('node:fs'); +const assert = require('node:assert'); const exifReader = require('exif-reader'); const icc = require('icc'); @@ -756,7 +754,7 @@ describe('Image metadata', function () { sharp(fixtures.inputJpg) .resize(64) .withIccProfile(fixtures.path('hilutite.icm')) - .toFile(output, function (err, info) { + .toFile(output, function (err) { if (err) throw err; fixtures.assertMaxColourDistance(output, fixtures.expected('hilutite.jpg'), 9); done(); diff --git a/test/unit/modulate.js b/test/unit/modulate.js index 988fc0554..04d27281c 100644 --- a/test/unit/modulate.js +++ b/test/unit/modulate.js @@ -1,10 +1,8 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - const sharp = require('../../'); -const assert = require('assert'); +const assert = require('node:assert'); const fixtures = require('../fixtures'); describe('Modulate', function () { diff --git a/test/unit/negate.js b/test/unit/negate.js index 646b9b13f..c442d7cf4 100644 --- a/test/unit/negate.js +++ b/test/unit/negate.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); @@ -104,7 +102,7 @@ describe('Negate', function () { const output = fixtures.path('output.unmodified-by-negate.png'); sharp(fixtures.inputJpgWithLowContrast) .negate(false) - .toFile(output, function (err, info) { + .toFile(output, function (err) { if (err) throw err; fixtures.assertMaxColourDistance(output, fixtures.inputJpgWithLowContrast, 0); done(); diff --git a/test/unit/noise.js b/test/unit/noise.js index ac3a63db0..97b8b16fe 100644 --- a/test/unit/noise.js +++ b/test/unit/noise.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/normalize.js b/test/unit/normalize.js index d9e62d826..843c01df0 100644 --- a/test/unit/normalize.js +++ b/test/unit/normalize.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); @@ -24,7 +22,7 @@ describe('Normalization', function () { sharp(fixtures.inputJpgWithLowContrast) .normalise() .raw() - .toBuffer(function (err, data, info) { + .toBuffer(function (err, data) { if (err) throw err; assertNormalized(data); done(); @@ -36,7 +34,7 @@ describe('Normalization', function () { .greyscale() .normalize() .raw() - .toBuffer(function (err, data, info) { + .toBuffer(function (err, data) { if (err) throw err; assertNormalized(data); done(); @@ -47,7 +45,7 @@ describe('Normalization', function () { sharp(fixtures.inputPngWithGreyAlpha) .normalise() .raw() - .toBuffer(function (err, data, info) { + .toBuffer(function (err, data) { if (err) throw err; assertNormalized(data); done(); @@ -90,7 +88,7 @@ describe('Normalization', function () { const output = fixtures.path('output.unmodified-png-with-one-color.png'); sharp(fixtures.inputPngWithOneColor) .normalize() - .toFile(output, function (err, info) { + .toFile(output, function (err) { if (err) done(err); fixtures.assertMaxColourDistance(output, fixtures.inputPngWithOneColor, 0); done(); @@ -101,7 +99,7 @@ describe('Normalization', function () { sharp(fixtures.inputPngWithTransparency16bit) .normalise() .raw() - .toBuffer(function (err, data, info) { + .toBuffer(function (err, data) { if (err) throw err; assertNormalized(data); done(); @@ -112,7 +110,7 @@ describe('Normalization', function () { sharp(fixtures.inputJpgWithLowContrast) .normalise({ lower: 10, upper: 70 }) .raw() - .toBuffer(function (err, data, info) { + .toBuffer(function (err, data) { if (err) throw err; assertNormalized(data); done(); diff --git a/test/unit/png.js b/test/unit/png.js index 84a74cbc6..9e8b4db4f 100644 --- a/test/unit/png.js +++ b/test/unit/png.js @@ -1,10 +1,8 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const fs = require('fs'); -const assert = require('assert'); +const fs = require('node:fs'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); @@ -137,6 +135,7 @@ describe('PNG', function () { .toBuffer(); const { size, ...metadata } = await sharp(data).metadata(); + void size; assert.deepStrictEqual(metadata, { autoOrient: { height: 68, diff --git a/test/unit/raw.js b/test/unit/raw.js index 4385288c3..28f4d3924 100644 --- a/test/unit/raw.js +++ b/test/unit/raw.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); @@ -200,7 +198,7 @@ describe('Raw pixel data', function () { }); writable .jpeg() - .toBuffer(function (err, data, info) { + .toBuffer(function (err, _data, info) { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(32, info.width); @@ -285,20 +283,20 @@ describe('Raw pixel data', function () { }); }); - for (const { constructor, depth, bits } of [ - { constructor: Uint8Array, depth: undefined, bits: 8 }, - { constructor: Uint8Array, depth: 'uchar', bits: 8 }, - { constructor: Uint8ClampedArray, depth: 'uchar', bits: 8 }, - { constructor: Int8Array, depth: 'char', bits: 8 }, - { constructor: Uint16Array, depth: 'ushort', bits: 16 }, - { constructor: Int16Array, depth: 'short', bits: 16 }, - { constructor: Uint32Array, depth: 'uint', bits: 32 }, - { constructor: Int32Array, depth: 'int', bits: 32 }, - { constructor: Float32Array, depth: 'float', bits: 32 }, - { constructor: Float64Array, depth: 'double', bits: 64 } + for (const { type, depth, bits } of [ + { type: Uint8Array, depth: undefined, bits: 8 }, + { type: Uint8Array, depth: 'uchar', bits: 8 }, + { type: Uint8ClampedArray, depth: 'uchar', bits: 8 }, + { type: Int8Array, depth: 'char', bits: 8 }, + { type: Uint16Array, depth: 'ushort', bits: 16 }, + { type: Int16Array, depth: 'short', bits: 16 }, + { type: Uint32Array, depth: 'uint', bits: 32 }, + { type: Int32Array, depth: 'int', bits: 32 }, + { type: Float32Array, depth: 'float', bits: 32 }, + { type: Float64Array, depth: 'double', bits: 64 } ]) { - it(constructor.name, () => - sharp(new constructor(3), { raw: { width: 1, height: 1, channels: 3 } }) + it(type.name, () => + sharp(new type(3), { raw: { width: 1, height: 1, channels: 3 } }) .raw({ depth }) .toBuffer({ resolveWithObject: true }) .then(({ data, info }) => { diff --git a/test/unit/recomb.js b/test/unit/recomb.js index 499597204..b894371ac 100644 --- a/test/unit/recomb.js +++ b/test/unit/recomb.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/resize-contain.js b/test/unit/resize-contain.js index 6e7f9ccc8..8dcc908ca 100644 --- a/test/unit/resize-contain.js +++ b/test/unit/resize-contain.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/resize-cover.js b/test/unit/resize-cover.js index 95ce1b012..b93670d3e 100644 --- a/test/unit/resize-cover.js +++ b/test/unit/resize-cover.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/resize.js b/test/unit/resize.js index 255fb15ff..b59a049d5 100644 --- a/test/unit/resize.js +++ b/test/unit/resize.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); @@ -129,7 +127,7 @@ describe('Resize dimensions', function () { .resize(0x4000, 0x4000) .extract({ top: 0x2000, left: 0x2000, width: 256, height: 256 }) .webp() - .toBuffer(function (err, data, info) { + .toBuffer(function (err, _data, info) { if (err) throw err; assert.strictEqual('webp', info.format); assert.strictEqual(256, info.width); @@ -149,7 +147,7 @@ describe('Resize dimensions', function () { assert.strictEqual(607, info.height); sharp(data) .resize(233, 131) - .toBuffer(function (err, data, info) { + .toBuffer(function (err, _data, info) { if (err) throw err; assert.strictEqual('webp', info.format); assert.strictEqual(233, info.width); @@ -169,7 +167,7 @@ describe('Resize dimensions', function () { sharp(data) .rotate(90) .resize(533, 800) - .toBuffer(function (err, data, info) { + .toBuffer(function (err, _data, info) { if (err) throw err; assert.strictEqual(533, info.width); assert.strictEqual(800, info.height); @@ -660,7 +658,7 @@ describe('Resize dimensions', function () { sharp(fixtures.inputTiff8BitDepth) .resize(210, 210, { kernel: 'nearest' }) .png() - .toBuffer(function (err, data, info) { + .toBuffer(function (err, _data, info) { if (err) throw err; assert.strictEqual(210, info.width); assert.strictEqual(210, info.height); diff --git a/test/unit/rotate.js b/test/unit/rotate.js index 0a7298b62..25303ce87 100644 --- a/test/unit/rotate.js +++ b/test/unit/rotate.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); @@ -173,8 +171,8 @@ describe('Rotation', function () { }); [-3690, -450, -90, 90, 450, 3690].forEach(function (angle) { - it('Rotate by any 90-multiple angle (' + angle + 'deg)', function (done) { - sharp(fixtures.inputJpg320x240).rotate(angle).toBuffer(function (err, data, info) { + it(`Rotate by any 90-multiple angle (${angle}deg)`, function (done) { + sharp(fixtures.inputJpg320x240).rotate(angle).toBuffer(function (err, _data, info) { if (err) throw err; assert.strictEqual(240, info.width); assert.strictEqual(320, info.height); @@ -184,8 +182,8 @@ describe('Rotation', function () { }); [-3750, -510, -150, 30, 390, 3630].forEach(function (angle) { - it('Rotate by any 30-multiple angle (' + angle + 'deg)', function (done) { - sharp(fixtures.inputJpg320x240).rotate(angle).toBuffer(function (err, data, info) { + it(`Rotate by any 30-multiple angle (${angle}deg)`, function (done) { + sharp(fixtures.inputJpg320x240).rotate(angle).toBuffer(function (err, _data, info) { if (err) throw err; assert.strictEqual(397, info.width); assert.strictEqual(368, info.height); @@ -195,8 +193,8 @@ describe('Rotation', function () { }); [-3780, -540, 0, 180, 540, 3780].forEach(function (angle) { - it('Rotate by any 180-multiple angle (' + angle + 'deg)', function (done) { - sharp(fixtures.inputJpg320x240).rotate(angle).toBuffer(function (err, data, info) { + it(`Rotate by any 180-multiple angle (${angle}deg)`, function (done) { + sharp(fixtures.inputJpg320x240).rotate(angle).toBuffer(function (err, _data, info) { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); @@ -446,7 +444,7 @@ describe('Rotation', function () { sharp(fixtures.inputJpg) .rotate(45) .rotate(90) - .toBuffer(function (err, data, info) { + .toBuffer(function (err, _data, info) { if (err) throw err; assert.strictEqual(2225, info.width); assert.strictEqual(2725, info.height); @@ -458,7 +456,7 @@ describe('Rotation', function () { sharp(fixtures.inputJpg) .rotate(90) .rotate(45) - .toBuffer(function (err, data, info) { + .toBuffer(function (err, _data, info) { if (err) throw err; assert.strictEqual(3500, info.width); assert.strictEqual(3500, info.height); diff --git a/test/unit/sharpen.js b/test/unit/sharpen.js index 8d447ba18..78b6f98fc 100644 --- a/test/unit/sharpen.js +++ b/test/unit/sharpen.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/stats.js b/test/unit/stats.js index 487e37dd4..9f3a73dac 100644 --- a/test/unit/stats.js +++ b/test/unit/stats.js @@ -1,10 +1,8 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const fs = require('fs'); -const assert = require('assert'); +const fs = require('node:fs'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); @@ -711,7 +709,7 @@ describe('Image Stats', function () { it('File input with corrupt header fails gracefully, Promise out', function () { return sharp(fixtures.inputJpgWithCorruptHeader) - .stats().then(function (stats) { + .stats().then(function () { throw new Error('Corrupt Header file'); }).catch(function (err) { assert.ok(!!err); @@ -724,7 +722,7 @@ describe('Image Stats', function () { fs.createReadStream(fixtures.inputJpgWithCorruptHeader).pipe(pipeline); return pipeline - .stats().then(function (stats) { + .stats().then(function () { throw new Error('Corrupt Header file'); }).catch(function (err) { assert.ok(!!err); @@ -740,7 +738,7 @@ describe('Image Stats', function () { }); it('Non-existent file in, Promise out', function (done) { - sharp('fail').stats().then(function (stats) { + sharp('fail').stats().then(function () { throw new Error('Non-existent file'); }, function (err) { assert.ok(!!err); diff --git a/test/unit/svg.js b/test/unit/svg.js index 6591cf2dc..f79f3efae 100644 --- a/test/unit/svg.js +++ b/test/unit/svg.js @@ -1,10 +1,8 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const fs = require('fs'); -const assert = require('assert'); +const fs = require('node:fs'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/text.js b/test/unit/text.js index 0efe05bca..258859976 100644 --- a/test/unit/text.js +++ b/test/unit/text.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/threshold.js b/test/unit/threshold.js index 1f93d659e..acd8add28 100644 --- a/test/unit/threshold.js +++ b/test/unit/threshold.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); @@ -64,7 +62,7 @@ describe('Threshold', function () { it('threshold false (=0)', function (done) { sharp(fixtures.inputJpg) .threshold(false) - .toBuffer(function (err, data, info) { + .toBuffer(function (err, data) { if (err) throw err; fixtures.assertSimilar(fixtures.inputJpg, data, done); }); diff --git a/test/unit/tiff.js b/test/unit/tiff.js index dab8948af..d4243aa50 100644 --- a/test/unit/tiff.js +++ b/test/unit/tiff.js @@ -1,10 +1,8 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const fs = require('fs'); -const assert = require('assert'); +const fs = require('node:fs'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/tile.js b/test/unit/tile.js index 53e91bf5d..90381f667 100644 --- a/test/unit/tile.js +++ b/test/unit/tile.js @@ -1,11 +1,9 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const fs = require('fs'); -const path = require('path'); -const assert = require('assert'); +const fs = require('node:fs'); +const path = require('node:path'); +const assert = require('node:assert'); const extractZip = require('extract-zip'); @@ -47,7 +45,7 @@ const assertDeepZoomTiles = function (directory, expectedSize, expectedLevels, d .catch(done); }; -const assertZoomifyTiles = function (directory, expectedTileSize, expectedLevels, done) { +const assertZoomifyTiles = function (directory, expectedLevels, done) { fs.stat(path.join(directory, 'ImageProperties.xml'), function (err, stat) { if (err) throw err; assert.ok(stat.isFile()); @@ -57,7 +55,7 @@ const assertZoomifyTiles = function (directory, expectedTileSize, expectedLevels fs.readdirSync(path.join(directory, 'TileGroup0')).forEach(function (tile) { // Verify tile file name assert.ok(/^[0-9]+-[0-9]+-[0-9]+\.jpg$/.test(tile)); - const level = parseInt(tile.split('-')[0]); + const level = Number(tile.split('-')[0]); maxTileLevel = Math.max(maxTileLevel, level); }); @@ -67,7 +65,7 @@ const assertZoomifyTiles = function (directory, expectedTileSize, expectedLevels }); }; -const assertGoogleTiles = function (directory, expectedTileSize, expectedLevels, done) { +const assertGoogleTiles = function (directory, expectedLevels, done) { // Get levels const dirents = fs.readdirSync(directory, { withFileTypes: true }); const levels = dirents.filter(dirent => dirent.isDirectory()).map(dirent => dirent.name); @@ -411,7 +409,7 @@ describe('Tile', function () { size: 512, depth: 'one' }) - .toFile(fixtures.path('output.512_depth_one.dzi'), function (err, info) { + .toFile(fixtures.path('output.512_depth_one.dzi'), function (err) { if (err) throw err; // Verify only one depth generated assertDeepZoomTiles(directory, 512, 1, done); @@ -427,7 +425,7 @@ describe('Tile', function () { size: 512, depth: 'onepixel' }) - .toFile(fixtures.path('output.512_depth_onepixel.dzi'), function (err, info) { + .toFile(fixtures.path('output.512_depth_onepixel.dzi'), function (err) { if (err) throw err; // Verify only one depth generated assertDeepZoomTiles(directory, 512, 13, done); @@ -443,7 +441,7 @@ describe('Tile', function () { size: 256, depth: 'onetile' }) - .toFile(fixtures.path('output.256_depth_onetile.dzi'), function (err, info) { + .toFile(fixtures.path('output.256_depth_onetile.dzi'), function (err) { if (err) throw err; // Verify only one depth generated assertDeepZoomTiles(directory, 256, 5, done); @@ -459,7 +457,7 @@ describe('Tile', function () { size: 256, skipBlanks: 0 }) - .toFile(fixtures.path('output.256_skip_blanks.dzi'), function (err, info) { + .toFile(fixtures.path('output.256_skip_blanks.dzi'), function (err) { if (err) throw err; // assert them 0_0.jpeg doesn't exist because it's a white tile const whiteTilePath = path.join(directory, '11', '0_0.jpeg'); @@ -510,7 +508,7 @@ describe('Tile', function () { assert.strictEqual(2225, info.height); assert.strictEqual(3, info.channels); assert.strictEqual(undefined, info.size); - assertZoomifyTiles(directory, 256, 1, done); + assertZoomifyTiles(directory, 1, done); }); }); }); @@ -531,7 +529,7 @@ describe('Tile', function () { assert.strictEqual(2225, info.height); assert.strictEqual(3, info.channels); assert.strictEqual(undefined, info.size); - assertZoomifyTiles(directory, 256, 5, done); + assertZoomifyTiles(directory, 5, done); }); }); }); @@ -552,7 +550,7 @@ describe('Tile', function () { assert.strictEqual(2225, info.height); assert.strictEqual(3, info.channels); assert.strictEqual(undefined, info.size); - assertZoomifyTiles(directory, 256, 13, done); + assertZoomifyTiles(directory, 13, done); }); }); }); @@ -576,7 +574,7 @@ describe('Tile', function () { assert.strictEqual(1536, info.height); assert.strictEqual(3, info.channels); assert.strictEqual(undefined, info.size); - assertZoomifyTiles(directory, 256, 4, done); + assertZoomifyTiles(directory, 4, done); }); }); }); @@ -733,7 +731,7 @@ describe('Tile', function () { assert.strictEqual(2225, info.height); assert.strictEqual(3, info.channels); assert.strictEqual(undefined, info.size); - assertGoogleTiles(directory, 256, 1, done); + assertGoogleTiles(directory, 1, done); }); }); }); @@ -754,7 +752,7 @@ describe('Tile', function () { assert.strictEqual(2225, info.height); assert.strictEqual(3, info.channels); assert.strictEqual(undefined, info.size); - assertGoogleTiles(directory, 256, 5, done); + assertGoogleTiles(directory, 5, done); }); }); }); @@ -778,7 +776,7 @@ describe('Tile', function () { assert.strictEqual(2074, info.height); assert.strictEqual(3, info.channels); assert.strictEqual(undefined, info.size); - assertGoogleTiles(directory, 256, 5, done); + assertGoogleTiles(directory, 5, done); }); }); }); diff --git a/test/unit/timeout.js b/test/unit/timeout.js index b80ef263e..21782917b 100644 --- a/test/unit/timeout.js +++ b/test/unit/timeout.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/tint.js b/test/unit/tint.js index 19f4ae2db..93cf17778 100644 --- a/test/unit/tint.js +++ b/test/unit/tint.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/toBuffer.js b/test/unit/toBuffer.js index 4db428b93..163f284bc 100644 --- a/test/unit/toBuffer.js +++ b/test/unit/toBuffer.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/toFormat.js b/test/unit/toFormat.js index a48742db2..089a797e3 100644 --- a/test/unit/toFormat.js +++ b/test/unit/toFormat.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/trim.js b/test/unit/trim.js index aa559d5a8..6261a8667 100644 --- a/test/unit/trim.js +++ b/test/unit/trim.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const sharp = require('../../'); const inRange = require('../../lib/is').inRange; diff --git a/test/unit/unflatten.js b/test/unit/unflatten.js index 68147b240..b7941cf5b 100644 --- a/test/unit/unflatten.js +++ b/test/unit/unflatten.js @@ -1,8 +1,6 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/util.js b/test/unit/util.js index ecec8a06a..e29109cac 100644 --- a/test/unit/util.js +++ b/test/unit/util.js @@ -1,9 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const assert = require('assert'); +const assert = require('node:assert'); const semver = require('semver'); const sharp = require('../../'); diff --git a/test/unit/webp.js b/test/unit/webp.js index c9aae0dd1..32f45f4e1 100644 --- a/test/unit/webp.js +++ b/test/unit/webp.js @@ -1,10 +1,8 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -'use strict'; - -const fs = require('fs'); -const assert = require('assert'); +const fs = require('node:fs'); +const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); From 30099571204a410b853196aaf8bbc42af6d48833 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Fri, 19 Sep 2025 13:13:53 +0100 Subject: [PATCH 086/115] Docs: Add note about libvips thread pool sizing --- docs/src/content/docs/performance.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/src/content/docs/performance.md b/docs/src/content/docs/performance.md index 9b5001bcd..b7613cacf 100644 --- a/docs/src/content/docs/performance.md +++ b/docs/src/content/docs/performance.md @@ -24,6 +24,10 @@ except when using glibc-based Linux without jemalloc, where the default is `1` t Use [`sharp.concurrency()`](/api-utility/#concurrency) to manage the number of threads per image. +The size of the shared thread pool will grow on demand and shrink when idle. +For control over this, set the `VIPS_MAX_THREADS` environment variable +to a value between 4 and 1024 to pre-allocate the thread pool at process start. + To reduce memory fragmentation when using the default Linux glibc memory allocator, set the [`MALLOC_ARENA_MAX`](https://www.gnu.org/software/libc/manual/html_node/Memory-Allocation-Tunables.html) environment variable before the Node.js process starts to reduce the number of memory pools. From 3498eb63e394e4b4bed1b7053c4648ffe7f1f8bb Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Sat, 20 Sep 2025 10:47:43 +0100 Subject: [PATCH 087/115] Docs: partially-revert 3009957, fix link to glibc malloc tunables --- docs/src/content/docs/performance.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/docs/src/content/docs/performance.md b/docs/src/content/docs/performance.md index b7613cacf..b244dbe5f 100644 --- a/docs/src/content/docs/performance.md +++ b/docs/src/content/docs/performance.md @@ -18,18 +18,15 @@ export UV_THREADPOOL_SIZE="$(lscpu -p | egrep -v "^#" | sort -u -t, -k 2,4 | wc ``` libvips uses a glib-managed thread pool to avoid the overhead of spawning new threads. +The size of the shared thread pool will grow on demand and shrink when idle. The default number of threads used to concurrently process each image is the same as the number of CPU cores, except when using glibc-based Linux without jemalloc, where the default is `1` to help reduce memory fragmentation. Use [`sharp.concurrency()`](/api-utility/#concurrency) to manage the number of threads per image. -The size of the shared thread pool will grow on demand and shrink when idle. -For control over this, set the `VIPS_MAX_THREADS` environment variable -to a value between 4 and 1024 to pre-allocate the thread pool at process start. - To reduce memory fragmentation when using the default Linux glibc memory allocator, set the -[`MALLOC_ARENA_MAX`](https://www.gnu.org/software/libc/manual/html_node/Memory-Allocation-Tunables.html) +[`MALLOC_ARENA_MAX`](https://sourceware.org/glibc/manual/latest/html_node/Memory-Allocation-Tunables.html) environment variable before the Node.js process starts to reduce the number of memory pools. ```sh frame="none" From c446d743a2dbde91512da725d8e3b301413b01dc Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Sat, 20 Sep 2025 14:03:38 +0200 Subject: [PATCH 088/115] Docs: libvips manages its own thread pool (#4455) --- docs/src/content/docs/performance.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/content/docs/performance.md b/docs/src/content/docs/performance.md index b244dbe5f..19aead63d 100644 --- a/docs/src/content/docs/performance.md +++ b/docs/src/content/docs/performance.md @@ -17,8 +17,8 @@ before the Node.js process starts to increase the thread pool size. export UV_THREADPOOL_SIZE="$(lscpu -p | egrep -v "^#" | sort -u -t, -k 2,4 | wc -l)" ``` -libvips uses a glib-managed thread pool to avoid the overhead of spawning new threads. -The size of the shared thread pool will grow on demand and shrink when idle. +libvips uses a shared thread pool to avoid the overhead of spawning new threads. +The size of this thread pool will grow on demand and shrink when idle. The default number of threads used to concurrently process each image is the same as the number of CPU cores, except when using glibc-based Linux without jemalloc, where the default is `1` to help reduce memory fragmentation. From f2978651f03670c94afc4fd666ecefc1992f8e5c Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Sun, 21 Sep 2025 11:04:55 +0100 Subject: [PATCH 089/115] Migrate from mocha to Node.js native test runner Includes coverage reports when using Node.js 22 onwards --- .cirrus.yml | 2 +- .github/CONTRIBUTING.md | 3 -- .github/workflows/ci.yml | 2 +- .mocharc.jsonc | 7 --- lib/input.js | 2 - lib/libvips.js | 36 ++++++++------- lib/output.js | 3 +- lib/sharp.js | 5 +- lib/utility.js | 6 +-- package.json | 14 +----- test/beforeEach.js | 22 --------- test/leak/leak.sh | 2 +- test/unit.mjs | 16 +++++++ test/unit/affine.js | 1 + test/unit/alpha.js | 13 +++--- test/unit/avif.js | 10 ++-- test/unit/bandbool.js | 5 +- test/unit/blur.js | 13 +++--- test/unit/boolean.js | 7 +-- test/unit/clahe.js | 17 +++---- test/unit/clone.js | 3 +- test/unit/colourspace.js | 19 ++++---- test/unit/composite.js | 1 + test/unit/convolve.js | 7 +-- test/unit/dilate.js | 5 +- test/unit/erode.js | 5 +- test/unit/extend.js | 15 +++--- test/unit/extract.js | 33 +++++++------- test/unit/extractChannel.js | 13 +++--- test/unit/failOn.js | 11 +++-- test/unit/fixtures.js | 1 + test/unit/gamma.js | 11 +++-- test/unit/gif.js | 5 +- test/unit/heif.js | 1 + test/unit/io.js | 91 +++++++++++++++++++++---------------- test/unit/join.js | 1 + test/unit/joinChannel.js | 15 +++--- test/unit/jp2.js | 1 + test/unit/jpeg.js | 19 ++++---- test/unit/jxl.js | 1 + test/unit/libvips.js | 5 +- test/unit/linear.js | 17 +++---- test/unit/median.js | 1 + test/unit/metadata.js | 53 ++++++++++----------- test/unit/modulate.js | 1 + test/unit/negate.js | 29 ++++++------ test/unit/noise.js | 9 ++-- test/unit/normalize.js | 17 +++---- test/unit/png.js | 7 +-- test/unit/raw.js | 15 +++--- test/unit/recomb.js | 11 +++-- test/unit/resize-contain.js | 91 +++++++++++++++++++------------------ test/unit/resize-cover.js | 23 +++++----- test/unit/resize.js | 87 +++++++++++++++++------------------ test/unit/rotate.js | 63 ++++++++++++------------- test/unit/sharpen.js | 17 +++---- test/unit/stats.js | 27 +++++------ test/unit/svg.js | 13 +++--- test/unit/text.js | 27 ++++++----- test/unit/threshold.js | 23 +++++----- test/unit/tiff.js | 31 +++++++------ test/unit/tile.js | 59 ++++++++++++------------ test/unit/timeout.js | 1 + test/unit/tint.js | 15 +++--- test/unit/toBuffer.js | 1 + test/unit/toFormat.js | 1 + test/unit/trim.js | 9 ++-- test/unit/unflatten.js | 7 +-- test/unit/util.js | 5 +- test/unit/webp.js | 15 +++--- 70 files changed, 583 insertions(+), 541 deletions(-) delete mode 100644 .mocharc.jsonc delete mode 100644 test/beforeEach.js create mode 100644 test/unit.mjs diff --git a/.cirrus.yml b/.cirrus.yml index eb240b5b8..0dbadc400 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -14,4 +14,4 @@ task: install_script: - npm install --build-from-source test_script: - - npx mocha --no-config --spec=test/unit/io.js --timeout=30000 + - node --test test/unit/io.js diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index c806fc5e7..eeb6dd191 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -6,8 +6,6 @@ Hello, thank you for your interest in helping! Please create a [new issue](https://github.com/lovell/sharp/issues/new) containing the steps to reproduce the problem. -If you're having installation problems, please include the output of running `npm install --verbose sharp`. - New bugs are assigned a `triage` label whilst under investigation. ## Submit a new feature request @@ -32,7 +30,6 @@ To test C++ changes, you can compile the module using `npm install --build-from- ## Submit a Pull Request with a new feature Please add JavaScript [unit tests](https://github.com/lovell/sharp/tree/main/test/unit) to cover your new feature. -A test coverage report for the JavaScript code is generated in the `coverage/lcov-report` directory. Please also update the [TypeScript definitions](https://github.com/lovell/sharp/tree/main/lib/index.d.ts), along with the [type definition tests](https://github.com/lovell/sharp/tree/main/test/types/sharp.test-d.ts). Where possible, the functional tests use gradient-based perceptual hashes diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c815127ff..25fb7c2d3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -267,7 +267,7 @@ jobs: curl --silent https://${{ matrix.nodejs_hostname }}/download/release/v${{ matrix.nodejs_version}}/node-v${{ matrix.nodejs_version}}-linux-${{ matrix.nodejs_arch }}.tar.xz | tar xJC /opt/nodejs --strip-components=1 export PATH=$PATH:/opt/nodejs/bin npm install --build-from-source - npx mocha --no-config --spec=test/unit/io.js --timeout=30000 + node --test test/unit/io.js npm run package-from-local-build - uses: actions/upload-artifact@v4 with: diff --git a/.mocharc.jsonc b/.mocharc.jsonc deleted file mode 100644 index 06df4ac9f..000000000 --- a/.mocharc.jsonc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "parallel": true, - "slow": 1000, - "timeout": 30000, - "require": "./test/beforeEach.js", - "spec": "./test/unit/*.js" -} diff --git a/lib/input.js b/lib/input.js index f6a869227..403ee31e3 100644 --- a/lib/input.js +++ b/lib/input.js @@ -524,9 +524,7 @@ function _createInputDescriptor (input, inputOptions, containerOptions) { * @param {Function} callback */ function _write (chunk, _encoding, callback) { - /* istanbul ignore else */ if (Array.isArray(this.options.input.buffer)) { - /* istanbul ignore else */ if (is.buffer(chunk)) { if (this.options.input.buffer.length === 0) { this.on('finish', () => { diff --git a/lib/libvips.js b/lib/libvips.js index 96edde12a..9c2917fcf 100644 --- a/lib/libvips.js +++ b/lib/libvips.js @@ -10,8 +10,8 @@ const detectLibc = require('detect-libc'); const { config, engines, optionalDependencies } = require('../package.json'); -const minimumLibvipsVersionLabelled = process.env.npm_package_config_libvips || /* istanbul ignore next */ - config.libvips; +/* node:coverage ignore next */ +const minimumLibvipsVersionLabelled = process.env.npm_package_config_libvips || config.libvips; const minimumLibvipsVersion = semverCoerce(minimumLibvipsVersionLabelled).version; const prebuiltPlatforms = [ @@ -34,17 +34,16 @@ const log = (item) => { } }; -/* istanbul ignore next */ +/* node:coverage ignore next */ const runtimeLibc = () => detectLibc.isNonGlibcLinuxSync() ? detectLibc.familySync() : ''; const runtimePlatformArch = () => `${process.platform}${runtimeLibc()}-${process.arch}`; -/* istanbul ignore next */ const buildPlatformArch = () => { + /* node:coverage ignore next 3 */ if (isEmscripten()) { return 'wasm32'; } - /* eslint camelcase: ["error", { allow: ["^npm_config_"] }] */ const { npm_config_arch, npm_config_platform, npm_config_libc } = process.env; const libc = typeof npm_config_libc === 'string' ? npm_config_libc : runtimeLibc(); return `${npm_config_platform || process.platform}${libc}-${npm_config_arch || process.arch}`; @@ -54,19 +53,19 @@ const buildSharpLibvipsIncludeDir = () => { try { return require(`@img/sharp-libvips-dev-${buildPlatformArch()}/include`); } catch { + /* node:coverage ignore next 5 */ try { return require('@img/sharp-libvips-dev/include'); } catch {} } - /* istanbul ignore next */ return ''; }; const buildSharpLibvipsCPlusPlusDir = () => { + /* node:coverage ignore next 4 */ try { return require('@img/sharp-libvips-dev/cplusplus'); } catch {} - /* istanbul ignore next */ return ''; }; @@ -74,16 +73,17 @@ const buildSharpLibvipsLibDir = () => { try { return require(`@img/sharp-libvips-dev-${buildPlatformArch()}/lib`); } catch { + /* node:coverage ignore next 5 */ try { return require(`@img/sharp-libvips-${buildPlatformArch()}/lib`); } catch {} } - /* istanbul ignore next */ return ''; }; +/* node:coverage disable */ + const isUnsupportedNodeRuntime = () => { - /* istanbul ignore next */ if (process.release?.name === 'node' && process.versions) { if (!semverSatisfies(process.versions.node, engines.node)) { return { found: process.versions.node, expected: engines.node }; @@ -91,14 +91,12 @@ const isUnsupportedNodeRuntime = () => { } }; -/* istanbul ignore next */ const isEmscripten = () => { const { CC } = process.env; return Boolean(CC?.endsWith('/emcc')); }; const isRosetta = () => { - /* istanbul ignore next */ if (process.platform === 'darwin' && process.arch === 'x64') { const translated = spawnSync('sysctl sysctl.proc_translated', spawnSyncOptions).stdout; return (translated || '').trim() === 'sysctl.proc_translated: 1'; @@ -106,6 +104,8 @@ const isRosetta = () => { return false; }; +/* node:coverage enable */ + const sha512 = (s) => createHash('sha512').update(s).digest('hex'); const yarnLocator = () => { @@ -119,7 +119,8 @@ const yarnLocator = () => { return ''; }; -/* istanbul ignore next */ +/* node:coverage disable */ + const spawnRebuild = () => spawnSync(`node-gyp rebuild --directory=src ${isEmscripten() ? '--nodedir=emscripten' : ''}`, { ...spawnSyncOptions, @@ -135,16 +136,17 @@ const globalLibvipsVersion = () => { PKG_CONFIG_PATH: pkgConfigPath() } }).stdout; - /* istanbul ignore next */ return (globalLibvipsVersion || '').trim(); } else { return ''; } }; -/* istanbul ignore next */ +/* node:coverage enable */ + const pkgConfigPath = () => { if (process.platform !== 'win32') { + /* node:coverage ignore next 4 */ const brewPkgConfigPath = spawnSync( 'which brew >/dev/null 2>&1 && brew environment --plain | grep PKG_CONFIG_LIBDIR | cut -d" " -f2', spawnSyncOptions @@ -176,13 +178,13 @@ const useGlobalLibvips = (logger) => { if (Boolean(process.env.SHARP_FORCE_GLOBAL_LIBVIPS) === true) { return skipSearch(true, 'SHARP_FORCE_GLOBAL_LIBVIPS', logger); } - /* istanbul ignore next */ + /* node:coverage ignore next 3 */ if (isRosetta()) { return skipSearch(false, 'Rosetta', logger); } const globalVipsVersion = globalLibvipsVersion(); - return !!globalVipsVersion && /* istanbul ignore next */ - semverGreaterThanOrEqualTo(globalVipsVersion, minimumLibvipsVersion); + /* node:coverage ignore next */ + return !!globalVipsVersion && semverGreaterThanOrEqualTo(globalVipsVersion, minimumLibvipsVersion); }; module.exports = { diff --git a/lib/output.js b/lib/output.js index 653215596..1178d6259 100644 --- a/lib/output.js +++ b/lib/output.js @@ -843,7 +843,6 @@ function gif (options) { return this._updateFormatOut('gif', options); } -/* istanbul ignore next */ /** * Use these JP2 options for output image. * @@ -878,6 +877,7 @@ function gif (options) { * @throws {Error} Invalid options */ function jp2 (options) { + /* node:coverage ignore next 41 */ if (!this.constructor.format.jp2k.output.buffer) { throw errJp2Save(); } @@ -1500,7 +1500,6 @@ function _setBooleanOption (key, val) { * @private */ function _read () { - /* istanbul ignore else */ if (!this.options.streamOut) { this.options.streamOut = true; const stack = Error(); diff --git a/lib/sharp.js b/lib/sharp.js index 8a90d826a..5cd4a40fb 100644 --- a/lib/sharp.js +++ b/lib/sharp.js @@ -15,6 +15,8 @@ const paths = [ '@img/sharp-wasm32/sharp.node' ]; +/* node:coverage disable */ + let path, sharp; const errors = []; for (path of paths) { @@ -22,12 +24,10 @@ for (path of paths) { sharp = require(path); break; } catch (err) { - /* istanbul ignore next */ errors.push(err); } } -/* istanbul ignore next */ if (sharp && path.startsWith('@img/sharp-linux-x64') && !sharp._isUsingX64V2()) { const err = new Error('Prebuilt binaries for linux-x64 require v2 microarchitecture'); err.code = 'Unsupported CPU'; @@ -35,7 +35,6 @@ if (sharp && path.startsWith('@img/sharp-linux-x64') && !sharp._isUsingX64V2()) sharp = null; } -/* istanbul ignore next */ if (sharp) { module.exports = sharp; } else { diff --git a/lib/utility.js b/lib/utility.js index d91605e53..6dd9b19f5 100644 --- a/lib/utility.js +++ b/lib/utility.js @@ -55,7 +55,7 @@ const interpolators = { let versions = { vips: libvipsVersion.semver }; -/* istanbul ignore next */ +/* node:coverage ignore next 15 */ if (!libvipsVersion.isGlobal) { if (!libvipsVersion.isWasm) { try { @@ -73,7 +73,7 @@ if (!libvipsVersion.isGlobal) { } versions.sharp = require('../package.json').version; -/* istanbul ignore next */ +/* node:coverage ignore next 5 */ if (versions.heif && format.heif) { // Prebuilt binaries provide AV1 format.heif.input.fileSuffix = ['.avif']; @@ -148,7 +148,7 @@ cache(true); function concurrency (concurrency) { return sharp.concurrency(is.integer(concurrency) ? concurrency : null); } -/* istanbul ignore next */ +/* node:coverage ignore next 7 */ if (detectLibc.familySync() === detectLibc.GLIBC && !sharp._isUsingJemalloc()) { // Reduce default concurrency to 1 when using glibc memory allocator sharp.concurrency(1); diff --git a/package.json b/package.json index 4dd623861..115e3c4f8 100644 --- a/package.json +++ b/package.json @@ -99,9 +99,9 @@ "lint-cpp": "cpplint", "lint-js": "biome lint", "lint-licensing": "license-checker --production --summary --onlyAllow=\"Apache-2.0;BSD;ISC;LGPL-3.0-or-later;MIT\"", - "lint-types": "tsd", + "lint-types": "tsd --files ./test/types/sharp.test-d.ts", "test-leak": "./test/leak/leak.sh", - "test-unit": "nyc --reporter=lcov --reporter=text --check-coverage --branches=100 mocha", + "test-unit": "node --experimental-test-coverage test/unit.mjs", "package-from-local-build": "node npm/from-local-build.js", "package-release-notes": "node npm/release-notes.js", "docs-build": "node docs/build.mjs", @@ -183,10 +183,8 @@ "icc": "^3.0.0", "jsdoc-to-markdown": "^9.1.2", "license-checker": "^25.0.1", - "mocha": "^11.7.2", "node-addon-api": "^8.5.0", "node-gyp": "^11.4.2", - "nyc": "^17.1.0", "tar-fs": "^3.1.1", "tsd": "^0.33.0" }, @@ -205,13 +203,5 @@ "filter": [ "build/include" ] - }, - "nyc": { - "include": [ - "lib" - ] - }, - "tsd": { - "directory": "test/types/" } } diff --git a/test/beforeEach.js b/test/beforeEach.js deleted file mode 100644 index 586869fe3..000000000 --- a/test/beforeEach.js +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 - -const sharp = require('../'); - -const usingCache = !process.env.G_DEBUG; -const usingSimd = !process.env.VIPS_NOVECTOR; -const concurrency = Number(process.env.VIPS_CONCURRENCY) || 0; - -exports.mochaHooks = { - beforeEach () { - sharp.cache(usingCache); - sharp.simd(usingSimd); - sharp.concurrency(concurrency); - }, - - afterEach () { - if (global.gc) { - global.gc(); - } - } -}; diff --git a/test/leak/leak.sh b/test/leak/leak.sh index c707a6a43..c1e5a0a33 100755 --- a/test/leak/leak.sh +++ b/test/leak/leak.sh @@ -18,5 +18,5 @@ for test in $TESTS; do --show-leak-kinds=definite,indirect \ --num-callers=20 \ --trace-children=yes \ - node --expose-gc --zero-fill-buffers node_modules/.bin/mocha --no-config --slow=60000 --timeout=120000 --require test/beforeEach.js "test/unit/$test"; + node --zero-fill-buffers --test "test/unit/$test"; done diff --git a/test/unit.mjs b/test/unit.mjs new file mode 100644 index 000000000..0a1aa3c0f --- /dev/null +++ b/test/unit.mjs @@ -0,0 +1,16 @@ +import { readdir } from 'node:fs/promises'; +import { run } from 'node:test'; +import { spec } from 'node:test/reporters'; + +const files = (await readdir('./test/unit')).map((f) => `./test/unit/${f}`); + +run({ + files, + concurrency: true, + timeout: 60000, + coverage: true, + coverageIncludeGlobs: ['lib/*.js'], + branchCoverage: 100, +}) + .compose(new spec()) + .pipe(process.stdout); diff --git a/test/unit/affine.js b/test/unit/affine.js index 6ff523be8..7c76776c1 100644 --- a/test/unit/affine.js +++ b/test/unit/affine.js @@ -1,6 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); diff --git a/test/unit/alpha.js b/test/unit/alpha.js index 13b3bc279..3cb61aaa9 100644 --- a/test/unit/alpha.js +++ b/test/unit/alpha.js @@ -1,12 +1,13 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const fixtures = require('../fixtures'); const sharp = require('../../'); describe('Alpha transparency', function () { - it('Flatten to black', function (done) { + it('Flatten to black', function (_t, done) { sharp(fixtures.inputPngWithTransparency) .flatten() .resize(400, 300) @@ -18,7 +19,7 @@ describe('Alpha transparency', function () { }); }); - it('Flatten to RGB orange', function (done) { + it('Flatten to RGB orange', function (_t, done) { sharp(fixtures.inputPngWithTransparency) .resize(400, 300) .flatten({ @@ -33,7 +34,7 @@ describe('Alpha transparency', function () { }); }); - it('Flatten to CSS/hex orange', function (done) { + it('Flatten to CSS/hex orange', function (_t, done) { sharp(fixtures.inputPngWithTransparency) .resize(400, 300) .flatten({ background: '#ff6600' }) @@ -46,7 +47,7 @@ describe('Alpha transparency', function () { }); }); - it('Flatten 16-bit PNG with transparency to orange', function (done) { + it('Flatten 16-bit PNG with transparency to orange', function (_t, done) { const output = fixtures.path('output.flatten-rgb16-orange.jpg'); sharp(fixtures.inputPngWithTransparency16bit) .flatten({ @@ -62,7 +63,7 @@ describe('Alpha transparency', function () { }); }); - it('Do not flatten', function (done) { + it('Do not flatten', function (_t, done) { sharp(fixtures.inputPngWithTransparency) .flatten(false) .toBuffer(function (err, _data, info) { @@ -73,7 +74,7 @@ describe('Alpha transparency', function () { }); }); - it('Ignored for JPEG', function (done) { + it('Ignored for JPEG', function (_t, done) { sharp(fixtures.inputJpg) .flatten({ background: '#ff0000' }) .toBuffer(function (err, _data, info) { diff --git a/test/unit/avif.js b/test/unit/avif.js index 8f3cb606d..1c28a975a 100644 --- a/test/unit/avif.js +++ b/test/unit/avif.js @@ -1,6 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); @@ -172,9 +173,10 @@ describe('AVIF', () => { ) ); - it('Invalid bitdepth value throws error', async () => { - assert.rejects( + it('Invalid bitdepth value throws error', () => + assert.throws( () => sharp().avif({ bitdepth: 11 }), - /Error: Expected 8, 10 or 12 for bitdepth but received 11 of type number/); - }); + /Expected 8, 10 or 12 for bitdepth but received 11 of type number/ + ) + ); }); diff --git a/test/unit/bandbool.js b/test/unit/bandbool.js index 5fad6590a..67574522e 100644 --- a/test/unit/bandbool.js +++ b/test/unit/bandbool.js @@ -1,6 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const fixtures = require('../fixtures'); const sharp = require('../../'); @@ -12,7 +13,7 @@ describe('Bandbool per-channel boolean operations', function () { sharp.bool.eor ] .forEach(function (op) { - it(`${op} operation`, function (done) { + it(`${op} operation`, function (_t, done) { sharp(fixtures.inputPngBooleanNoAlpha) .bandbool(op) .toColourspace('b-w') @@ -26,7 +27,7 @@ describe('Bandbool per-channel boolean operations', function () { }); }); - it('sRGB image retains 3 channels', function (done) { + it('sRGB image retains 3 channels', function (_t, done) { sharp(fixtures.inputJpg) .bandbool('and') .toBuffer(function (err, _data, info) { diff --git a/test/unit/blur.js b/test/unit/blur.js index efa7163e5..41414bf2e 100644 --- a/test/unit/blur.js +++ b/test/unit/blur.js @@ -1,13 +1,14 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); describe('Blur', function () { - it('specific radius 1', function (done) { + it('specific radius 1', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .blur(1) @@ -20,7 +21,7 @@ describe('Blur', function () { }); }); - it('specific radius 10', function (done) { + it('specific radius 10', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .blur(10) @@ -33,7 +34,7 @@ describe('Blur', function () { }); }); - it('specific options.sigma 10', function (done) { + it('specific options.sigma 10', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .blur({ sigma: 10 }) @@ -46,7 +47,7 @@ describe('Blur', function () { }); }); - it('specific radius 0.3', function (done) { + it('specific radius 0.3', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .blur(0.3) @@ -59,7 +60,7 @@ describe('Blur', function () { }); }); - it('mild blur', function (done) { + it('mild blur', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .blur() @@ -78,7 +79,7 @@ describe('Blur', function () { }); }); - it('blurred image is smaller than non-blurred', function (done) { + it('blurred image is smaller than non-blurred', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .blur(false) diff --git a/test/unit/boolean.js b/test/unit/boolean.js index e1c3e3f23..c7fcdb4df 100644 --- a/test/unit/boolean.js +++ b/test/unit/boolean.js @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 const fs = require('node:fs'); +const { describe, it } = require('node:test'); const assert = require('node:assert'); const fixtures = require('../fixtures'); @@ -16,7 +17,7 @@ describe('Boolean operation between two images', function () { sharp.bool.eor ] .forEach(function (op) { - it(`${op} operation, file`, function (done) { + it(`${op} operation, file`, function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .boolean(fixtures.inputJpgBooleanTest, op) @@ -28,7 +29,7 @@ describe('Boolean operation between two images', function () { }); }); - it(`${op} operation, buffer`, function (done) { + it(`${op} operation, buffer`, function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .boolean(inputJpgBooleanTestBuffer, op) @@ -40,7 +41,7 @@ describe('Boolean operation between two images', function () { }); }); - it(`${op} operation, raw`, function (done) { + it(`${op} operation, raw`, function (_t, done) { sharp(fixtures.inputJpgBooleanTest) .raw() .toBuffer(function (err, data, info) { diff --git a/test/unit/clahe.js b/test/unit/clahe.js index 8f459c4bd..a72770252 100644 --- a/test/unit/clahe.js +++ b/test/unit/clahe.js @@ -1,13 +1,14 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../lib'); const fixtures = require('../fixtures'); describe('Clahe', function () { - it('width 5 width 5 maxSlope 0', function (done) { + it('width 5 width 5 maxSlope 0', function (_t, done) { sharp(fixtures.inputJpgClahe) .clahe({ width: 5, height: 5, maxSlope: 0 }) .toBuffer(function (err, data, info) { @@ -17,7 +18,7 @@ describe('Clahe', function () { }); }); - it('width 5 width 5 maxSlope 5', function (done) { + it('width 5 width 5 maxSlope 5', function (_t, done) { sharp(fixtures.inputJpgClahe) .clahe({ width: 5, height: 5, maxSlope: 5 }) .toBuffer(function (err, data, info) { @@ -27,7 +28,7 @@ describe('Clahe', function () { }); }); - it('width 11 width 25 maxSlope 14', function (done) { + it('width 11 width 25 maxSlope 14', function (_t, done) { sharp(fixtures.inputJpgClahe) .clahe({ width: 11, height: 25, maxSlope: 14 }) .toBuffer(function (err, data, info) { @@ -37,7 +38,7 @@ describe('Clahe', function () { }); }); - it('width 50 width 50 maxSlope 0', function (done) { + it('width 50 width 50 maxSlope 0', function (_t, done) { sharp(fixtures.inputJpgClahe) .clahe({ width: 50, height: 50, maxSlope: 0 }) .toBuffer(function (err, data, info) { @@ -47,7 +48,7 @@ describe('Clahe', function () { }); }); - it('width 50 width 50 maxSlope 14', function (done) { + it('width 50 width 50 maxSlope 14', function (_t, done) { sharp(fixtures.inputJpgClahe) .clahe({ width: 50, height: 50, maxSlope: 14 }) .toBuffer(function (err, data, info) { @@ -57,7 +58,7 @@ describe('Clahe', function () { }); }); - it('width 100 width 50 maxSlope 3', function (done) { + it('width 100 width 50 maxSlope 3', function (_t, done) { sharp(fixtures.inputJpgClahe) .clahe({ width: 100, height: 50, maxSlope: 3 }) .toBuffer(function (err, data, info) { @@ -67,7 +68,7 @@ describe('Clahe', function () { }); }); - it('width 100 width 100 maxSlope 0', function (done) { + it('width 100 width 100 maxSlope 0', function (_t, done) { sharp(fixtures.inputJpgClahe) .clahe({ width: 100, height: 100, maxSlope: 0 }) .toBuffer(function (err, data, info) { @@ -128,7 +129,7 @@ describe('Clahe', function () { }); }); - it('uses default maxSlope of 3', function (done) { + it('uses default maxSlope of 3', function (_t, done) { sharp(fixtures.inputJpgClahe) .clahe({ width: 100, height: 50 }) .toBuffer(function (err, data, info) { diff --git a/test/unit/clone.js b/test/unit/clone.js index 3ac46cee0..2075c5602 100644 --- a/test/unit/clone.js +++ b/test/unit/clone.js @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 const fs = require('node:fs'); +const { afterEach, beforeEach, describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); @@ -15,7 +16,7 @@ describe('Clone', function () { sharp.cache(true); }); - it('Read from Stream and write to multiple Streams', function (done) { + it('Read from Stream and write to multiple Streams', function (_t, done) { let finishEventsExpected = 2; // Output stream 1 const output1 = fixtures.path('output.multi-stream.1.jpg'); diff --git a/test/unit/colourspace.js b/test/unit/colourspace.js index e311f5fe9..f373db341 100644 --- a/test/unit/colourspace.js +++ b/test/unit/colourspace.js @@ -1,20 +1,21 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); describe('Colour space conversion', function () { - it('To greyscale', function (done) { + it('To greyscale', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .greyscale() .toFile(fixtures.path('output.greyscale-gamma-0.0.jpg'), done); }); - it('To greyscale with gamma correction', function (done) { + it('To greyscale with gamma correction', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .gamma() @@ -22,14 +23,14 @@ describe('Colour space conversion', function () { .toFile(fixtures.path('output.greyscale-gamma-2.2.jpg'), done); }); - it('Not to greyscale', function (done) { + it('Not to greyscale', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .greyscale(false) .toFile(fixtures.path('output.greyscale-not.jpg'), done); }); - it('Greyscale with single channel output', function (done) { + it('Greyscale with single channel output', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .greyscale() @@ -53,7 +54,7 @@ describe('Colour space conversion', function () { assert.strictEqual(format, 'webp'); }); - it('From CMYK to sRGB', function (done) { + it('From CMYK to sRGB', function (_t, done) { sharp(fixtures.inputJpgWithCmykProfile) .resize(320) .toBuffer(function (err, data, info) { @@ -65,7 +66,7 @@ describe('Colour space conversion', function () { }); }); - it('From CMYK to sRGB with white background, not yellow', function (done) { + it('From CMYK to sRGB with white background, not yellow', function (_t, done) { sharp(fixtures.inputJpgWithCmykProfile) .resize(320, 240, { fit: sharp.fit.contain, @@ -80,7 +81,7 @@ describe('Colour space conversion', function () { }); }); - it('From profile-less CMYK to sRGB', function (done) { + it('From profile-less CMYK to sRGB', function (_t, done) { sharp(fixtures.inputJpgWithCmykNoProfile) .resize(320) .toBuffer(function (err, data, info) { @@ -120,7 +121,7 @@ describe('Colour space conversion', function () { ); }); - it('CMYK profile to CMYK profile with negate', (done) => { + it('CMYK profile to CMYK profile with negate', (_t, done) => { sharp(fixtures.inputTiffFogra) .resize(320, 240) .toColourspace('cmyk') @@ -141,7 +142,7 @@ describe('Colour space conversion', function () { }); }); - it('From sRGB with RGB16 pipeline, resize with gamma, to sRGB', function (done) { + it('From sRGB with RGB16 pipeline, resize with gamma, to sRGB', function (_t, done) { sharp(fixtures.inputPngGradients) .pipelineColourspace('rgb16') .resize(320) diff --git a/test/unit/composite.js b/test/unit/composite.js index c027b027d..c442c8298 100644 --- a/test/unit/composite.js +++ b/test/unit/composite.js @@ -1,6 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const fixtures = require('../fixtures'); diff --git a/test/unit/convolve.js b/test/unit/convolve.js index 31b2fb3e4..29c7a8f63 100644 --- a/test/unit/convolve.js +++ b/test/unit/convolve.js @@ -1,13 +1,14 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); describe('Convolve', function () { - it('specific convolution kernel 1', function (done) { + it('specific convolution kernel 1', function (_t, done) { sharp(fixtures.inputPngStripesV) .convolve({ width: 3, @@ -29,7 +30,7 @@ describe('Convolve', function () { }); }); - it('specific convolution kernel 2', function (done) { + it('specific convolution kernel 2', function (_t, done) { sharp(fixtures.inputPngStripesH) .convolve({ width: 3, @@ -49,7 +50,7 @@ describe('Convolve', function () { }); }); - it('horizontal Sobel operator', function (done) { + it('horizontal Sobel operator', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .convolve({ diff --git a/test/unit/dilate.js b/test/unit/dilate.js index eb092a147..d3de3b47b 100644 --- a/test/unit/dilate.js +++ b/test/unit/dilate.js @@ -1,10 +1,11 @@ +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); describe('Dilate', function () { - it('dilate 1 png', function (done) { + it('dilate 1 png', function (_t, done) { sharp(fixtures.inputPngDotAndLines) .dilate(1) .toBuffer(function (err, data, info) { @@ -16,7 +17,7 @@ describe('Dilate', function () { }); }); - it('dilate 1 png - default width', function (done) { + it('dilate 1 png - default width', function (_t, done) { sharp(fixtures.inputPngDotAndLines) .dilate() .toBuffer(function (err, data, info) { diff --git a/test/unit/erode.js b/test/unit/erode.js index 1a1493053..60d10e893 100644 --- a/test/unit/erode.js +++ b/test/unit/erode.js @@ -1,10 +1,11 @@ +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); describe('Erode', function () { - it('erode 1 png', function (done) { + it('erode 1 png', function (_t, done) { sharp(fixtures.inputPngDotAndLines) .erode(1) .toBuffer(function (err, data, info) { @@ -16,7 +17,7 @@ describe('Erode', function () { }); }); - it('erode 1 png - default width', function (done) { + it('erode 1 png - default width', function (_t, done) { sharp(fixtures.inputPngDotAndLines) .erode() .toBuffer(function (err, data, info) { diff --git a/test/unit/extend.js b/test/unit/extend.js index 1c8eb3070..c36424d25 100644 --- a/test/unit/extend.js +++ b/test/unit/extend.js @@ -1,6 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); @@ -8,7 +9,7 @@ const fixtures = require('../fixtures'); describe('Extend', function () { describe('extend all sides equally via a single value', function () { - it('JPEG', function (done) { + it('JPEG', function (_t, done) { sharp(fixtures.inputJpg) .resize(120) .extend(10) @@ -20,7 +21,7 @@ describe('Extend', function () { }); }); - it('Animated WebP', function (done) { + it('Animated WebP', function (_t, done) { sharp(fixtures.inputWebPAnimated, { pages: -1 }) .resize(120) .extend(10) @@ -34,7 +35,7 @@ describe('Extend', function () { }); ['background', 'copy', 'mirror', 'repeat'].forEach(extendWith => { - it(`extends all sides with animated WebP (${extendWith})`, function (done) { + it(`extends all sides with animated WebP (${extendWith})`, function (_t, done) { sharp(fixtures.inputWebPAnimated, { pages: -1 }) .resize(120) .extend({ @@ -52,7 +53,7 @@ describe('Extend', function () { }); }); - it(`extend all sides equally with RGB (${extendWith})`, function (done) { + it(`extend all sides equally with RGB (${extendWith})`, function (_t, done) { sharp(fixtures.inputJpg) .resize(120) .extend({ @@ -71,7 +72,7 @@ describe('Extend', function () { }); }); - it(`extend sides unequally with RGBA (${extendWith})`, function (done) { + it(`extend sides unequally with RGBA (${extendWith})`, function (_t, done) { sharp(fixtures.inputPngWithTransparency16bit) .resize(120) .extend({ @@ -89,7 +90,7 @@ describe('Extend', function () { }); }); - it(`PNG with 2 channels (${extendWith})`, function (done) { + it(`PNG with 2 channels (${extendWith})`, function (_t, done) { sharp(fixtures.inputPngWithGreyAlpha) .extend({ extendWith, @@ -188,7 +189,7 @@ describe('Extend', function () { assert.doesNotThrow(() => sharp().extend({ top: 1, left: 2, bottom: 3 })); }); - it('should add alpha channel before extending with a transparent Background', function (done) { + it('should add alpha channel before extending with a transparent Background', function (_t, done) { sharp(fixtures.inputJpgWithLandscapeExif1) .extend({ bottom: 10, diff --git a/test/unit/extract.js b/test/unit/extract.js index 53e4f8a09..d1e14ecb3 100644 --- a/test/unit/extract.js +++ b/test/unit/extract.js @@ -1,13 +1,14 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); describe('Partial image extraction', function () { - it('JPEG', function (done) { + it('JPEG', function (_t, done) { sharp(fixtures.inputJpg) .extract({ left: 2, top: 2, width: 20, height: 20 }) .toBuffer(function (err, data, info) { @@ -18,7 +19,7 @@ describe('Partial image extraction', function () { }); }); - it('PNG', function (done) { + it('PNG', function (_t, done) { sharp(fixtures.inputPng) .extract({ left: 200, top: 300, width: 400, height: 200 }) .toBuffer(function (err, data, info) { @@ -29,7 +30,7 @@ describe('Partial image extraction', function () { }); }); - it('WebP', function (done) { + it('WebP', function (_t, done) { sharp(fixtures.inputWebP) .extract({ left: 100, top: 50, width: 125, height: 200 }) .toBuffer(function (err, data, info) { @@ -41,7 +42,7 @@ describe('Partial image extraction', function () { }); describe('Animated WebP', function () { - it('Before resize', function (done) { + it('Before resize', function (_t, done) { sharp(fixtures.inputWebPAnimated, { pages: -1 }) .extract({ left: 0, top: 30, width: 80, height: 20 }) .resize(320, 80) @@ -53,7 +54,7 @@ describe('Partial image extraction', function () { }); }); - it('After resize', function (done) { + it('After resize', function (_t, done) { sharp(fixtures.inputWebPAnimated, { pages: -1 }) .resize(320, 320) .extract({ left: 0, top: 120, width: 320, height: 80 }) @@ -66,7 +67,7 @@ describe('Partial image extraction', function () { }); }); - it('TIFF', function (done) { + it('TIFF', function (_t, done) { sharp(fixtures.inputTiff) .extract({ left: 34, top: 63, width: 341, height: 529 }) .toBuffer(function (err, data, info) { @@ -77,7 +78,7 @@ describe('Partial image extraction', function () { }); }); - it('Before resize', function (done) { + it('Before resize', function (_t, done) { sharp(fixtures.inputJpg) .extract({ left: 10, top: 10, width: 10, height: 500 }) .resize(100, 100) @@ -89,7 +90,7 @@ describe('Partial image extraction', function () { }); }); - it('After resize and crop', function (done) { + it('After resize and crop', function (_t, done) { sharp(fixtures.inputJpg) .resize(500, 500, { position: sharp.gravity.north @@ -103,7 +104,7 @@ describe('Partial image extraction', function () { }); }); - it('Before and after resize and crop', function (done) { + it('Before and after resize and crop', function (_t, done) { sharp(fixtures.inputJpg) .extract({ left: 0, top: 0, width: 700, height: 700 }) .resize(500, 500, { @@ -118,7 +119,7 @@ describe('Partial image extraction', function () { }); }); - it('Extract then rotate', function (done) { + it('Extract then rotate', function (_t, done) { sharp(fixtures.inputPngWithGreyAlpha) .extract({ left: 20, top: 10, width: 380, height: 280 }) .rotate(90) @@ -131,7 +132,7 @@ describe('Partial image extraction', function () { }); }); - it('Rotate then extract', function (done) { + it('Rotate then extract', function (_t, done) { sharp(fixtures.inputPngWithGreyAlpha) .rotate(90) .extract({ left: 20, top: 10, width: 280, height: 380 }) @@ -143,7 +144,7 @@ describe('Partial image extraction', function () { }); }); - it('Extract then rotate then extract', function (done) { + it('Extract then rotate then extract', function (_t, done) { sharp(fixtures.inputPngWithGreyAlpha) .extract({ left: 20, top: 10, width: 180, height: 280 }) .rotate(90) @@ -156,7 +157,7 @@ describe('Partial image extraction', function () { }); }); - it('Extract then rotate non-90 anagle', function (done) { + it('Extract then rotate non-90 anagle', function (_t, done) { sharp(fixtures.inputPngWithGreyAlpha) .extract({ left: 20, top: 10, width: 380, height: 280 }) .rotate(45) @@ -169,7 +170,7 @@ describe('Partial image extraction', function () { }); }); - it('Rotate then extract non-90 angle', function (done) { + it('Rotate then extract non-90 angle', function (_t, done) { sharp(fixtures.inputPngWithGreyAlpha) .rotate(45) .extract({ left: 20, top: 10, width: 380, height: 280 }) @@ -217,7 +218,7 @@ describe('Partial image extraction', function () { image: fixtures.inputJpgWithLandscapeExif8 } ].forEach(({ name, image }) => { - it(name, function (done) { + it(name, function (_t, done) { sharp(image) .rotate() .extract({ left: 0, top: 208, width: 60, height: 40 }) @@ -286,7 +287,7 @@ describe('Partial image extraction', function () { }); }); - it('Bad image area', function (done) { + it('Bad image area', function (_t, done) { sharp(fixtures.inputJpg) .extract({ left: 3000, top: 10, width: 10, height: 10 }) .toBuffer(function (err) { diff --git a/test/unit/extractChannel.js b/test/unit/extractChannel.js index edb3978c8..4f05c1ac8 100644 --- a/test/unit/extractChannel.js +++ b/test/unit/extractChannel.js @@ -1,13 +1,14 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); describe('Image channel extraction', function () { - it('Red channel', function (done) { + it('Red channel', function (_t, done) { sharp(fixtures.inputJpg) .extractChannel('red') .resize(320, 240) @@ -19,7 +20,7 @@ describe('Image channel extraction', function () { }); }); - it('Green channel', function (done) { + it('Green channel', function (_t, done) { sharp(fixtures.inputJpg) .extractChannel('green') .resize(320, 240) @@ -31,7 +32,7 @@ describe('Image channel extraction', function () { }); }); - it('Blue channel', function (done) { + it('Blue channel', function (_t, done) { sharp(fixtures.inputJpg) .extractChannel('blue') .resize(320, 240) @@ -43,7 +44,7 @@ describe('Image channel extraction', function () { }); }); - it('Blue channel by number', function (done) { + it('Blue channel by number', function (_t, done) { sharp(fixtures.inputJpg) .extractChannel(2) .resize(320, 240) @@ -64,7 +65,7 @@ describe('Image channel extraction', function () { assert.strictEqual(chroma, 104); }); - it('Alpha from 16-bit PNG', function (done) { + it('Alpha from 16-bit PNG', function (_t, done) { const output = fixtures.path('output.extract-alpha-16bit.png'); sharp(fixtures.inputPngWithTransparency16bit) .resize(16) @@ -76,7 +77,7 @@ describe('Image channel extraction', function () { }); }); - it('Alpha from 2-channel input', function (done) { + it('Alpha from 2-channel input', function (_t, done) { const output = fixtures.path('output.extract-alpha-2-channel.png'); sharp(fixtures.inputPngWithGreyAlpha) .extractChannel('alpha') diff --git a/test/unit/failOn.js b/test/unit/failOn.js index 48e758c0f..3e0dbabf1 100644 --- a/test/unit/failOn.js +++ b/test/unit/failOn.js @@ -1,6 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const fs = require('node:fs'); @@ -8,7 +9,7 @@ const sharp = require('../../lib'); const fixtures = require('../fixtures'); describe('failOn', () => { - it('handles truncated JPEG', function (done) { + it('handles truncated JPEG', function (_t, done) { sharp(fixtures.inputJpgTruncated, { failOn: 'none' }) .resize(32, 24) .toBuffer(function (err, data, info) { @@ -20,7 +21,7 @@ describe('failOn', () => { }); }); - it('handles truncated PNG, emits warnings', function (done) { + it('handles truncated PNG, emits warnings', function (_t, done) { let isWarningEmitted = false; sharp(fixtures.inputPngTruncated, { failOn: 'none' }) .on('warning', function (warning) { @@ -68,7 +69,7 @@ describe('failOn', () => { ); }); - it('returns errors to callback for truncated JPEG', function (done) { + it('returns errors to callback for truncated JPEG', function (_t, done) { sharp(fixtures.inputJpgTruncated, { failOn: 'truncated' }).toBuffer(function (err, data, info) { assert.ok(err.message.includes('VipsJpeg: premature end of'), err); assert.strictEqual(data, undefined); @@ -77,7 +78,7 @@ describe('failOn', () => { }); }); - it('returns errors to callback for truncated PNG', function (done) { + it('returns errors to callback for truncated PNG', function (_t, done) { sharp(fixtures.inputPngTruncated, { failOn: 'truncated' }).toBuffer(function (err, data, info) { assert.ok(err.message.includes('read error'), err); assert.strictEqual(data, undefined); @@ -86,7 +87,7 @@ describe('failOn', () => { }); }); - it('rejects promises for truncated JPEG', function (done) { + it('rejects promises for truncated JPEG', function (_t, done) { sharp(fixtures.inputJpgTruncated, { failOn: 'error' }) .toBuffer() .then(() => { diff --git a/test/unit/fixtures.js b/test/unit/fixtures.js index ee398958c..ca975627a 100644 --- a/test/unit/fixtures.js +++ b/test/unit/fixtures.js @@ -1,6 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const fixtures = require('../fixtures'); diff --git a/test/unit/gamma.js b/test/unit/gamma.js index 21a333436..b58567c7a 100644 --- a/test/unit/gamma.js +++ b/test/unit/gamma.js @@ -1,13 +1,14 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); describe('Gamma correction', function () { - it('value of 0.0 (disabled)', function (done) { + it('value of 0.0 (disabled)', function (_t, done) { sharp(fixtures.inputJpgWithGammaHoliness) .resize(129, 111) .toBuffer(function (err, data, info) { @@ -19,7 +20,7 @@ describe('Gamma correction', function () { }); }); - it('value of 2.2 (default)', function (done) { + it('value of 2.2 (default)', function (_t, done) { sharp(fixtures.inputJpgWithGammaHoliness) .resize(129, 111) .gamma() @@ -32,7 +33,7 @@ describe('Gamma correction', function () { }); }); - it('value of 3.0', function (done) { + it('value of 3.0', function (_t, done) { sharp(fixtures.inputJpgWithGammaHoliness) .resize(129, 111) .gamma(3) @@ -45,7 +46,7 @@ describe('Gamma correction', function () { }); }); - it('input value of 2.2, output value of 3.0', function (done) { + it('input value of 2.2, output value of 3.0', function (_t, done) { sharp(fixtures.inputJpgWithGammaHoliness) .resize(129, 111) .gamma(2.2, 3.0) @@ -58,7 +59,7 @@ describe('Gamma correction', function () { }); }); - it('alpha transparency', function (done) { + it('alpha transparency', function (_t, done) { sharp(fixtures.inputPngOverlayLayer1) .resize(320) .gamma() diff --git a/test/unit/gif.js b/test/unit/gif.js index 8ae20e957..4921be725 100644 --- a/test/unit/gif.js +++ b/test/unit/gif.js @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 const fs = require('node:fs'); +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); @@ -196,7 +197,7 @@ describe('GIF input', () => { ); }); - it('should work with streams when only animated is set', function (done) { + it('should work with streams when only animated is set', function (_t, done) { fs.createReadStream(fixtures.inputGifAnimated) .pipe(sharp({ animated: true })) .gif() @@ -208,7 +209,7 @@ describe('GIF input', () => { }); }); - it('should work with streams when only pages is set', function (done) { + it('should work with streams when only pages is set', function (_t, done) { fs.createReadStream(fixtures.inputGifAnimated) .pipe(sharp({ pages: -1 })) .gif() diff --git a/test/unit/heif.js b/test/unit/heif.js index af3ee62eb..9cb5355b1 100644 --- a/test/unit/heif.js +++ b/test/unit/heif.js @@ -1,6 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); diff --git a/test/unit/io.js b/test/unit/io.js index ed6decafc..75a7959f5 100644 --- a/test/unit/io.js +++ b/test/unit/io.js @@ -3,6 +3,7 @@ const fs = require('node:fs'); const path = require('node:path'); +const { afterEach, beforeEach, describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); @@ -18,7 +19,7 @@ describe('Input/output', function () { sharp.cache(true); }); - it('Read from File and write to Stream', function (done) { + it('Read from File and write to Stream', function (_t, done) { const writable = fs.createWriteStream(outputJpg); writable.on('close', function () { sharp(outputJpg).toBuffer(function (err, data, info) { @@ -34,7 +35,7 @@ describe('Input/output', function () { sharp(fixtures.inputJpg).resize(320, 240).pipe(writable); }); - it('Read from Buffer and write to Stream', function (done) { + it('Read from Buffer and write to Stream', function (_t, done) { const inputJpgBuffer = fs.readFileSync(fixtures.inputJpg); const writable = fs.createWriteStream(outputJpg); writable.on('close', function () { @@ -51,7 +52,7 @@ describe('Input/output', function () { sharp(inputJpgBuffer).resize(320, 240).pipe(writable); }); - it('Read from Stream and write to File', function (done) { + it('Read from Stream and write to File', function (_t, done) { const readable = fs.createReadStream(fixtures.inputJpg); const pipeline = sharp().resize(320, 240).toFile(outputJpg, function (err, info) { if (err) throw err; @@ -64,7 +65,7 @@ describe('Input/output', function () { readable.pipe(pipeline); }); - it('Read from Stream and write to Buffer', function (done) { + it('Read from Stream and write to Buffer', function (_t, done) { const readable = fs.createReadStream(fixtures.inputJpg); const pipeline = sharp().resize(320, 240).toBuffer(function (err, data, info) { if (err) throw err; @@ -132,7 +133,7 @@ describe('Input/output', function () { }); }); - it('Read from Stream and write to Stream', function (done) { + it('Read from Stream and write to Stream', function (_t, done) { const readable = fs.createReadStream(fixtures.inputJpg); const writable = fs.createWriteStream(outputJpg); writable.on('close', function () { @@ -217,7 +218,7 @@ describe('Input/output', function () { assert.strictEqual(info.height, 1); }); - it('Stream should emit info event', function (done) { + it('Stream should emit info event', function (_t, done) { const readable = fs.createReadStream(fixtures.inputJpg); const writable = fs.createWriteStream(outputJpg); const pipeline = sharp().resize(320, 240); @@ -236,7 +237,7 @@ describe('Input/output', function () { readable.pipe(pipeline).pipe(writable); }); - it('Stream should emit close event', function (done) { + it('Stream should emit close event', function (_t, done) { const readable = fs.createReadStream(fixtures.inputJpg); const writable = fs.createWriteStream(outputJpg); const pipeline = sharp().resize(320, 240); @@ -251,7 +252,7 @@ describe('Input/output', function () { readable.pipe(pipeline).pipe(writable); }); - it('Handle Stream to Stream error ', function (done) { + it('Handle Stream to Stream error ', function (_t, done) { const pipeline = sharp().resize(320, 240); let anErrorWasEmitted = false; pipeline.on('error', function (err) { @@ -265,7 +266,7 @@ describe('Input/output', function () { readableButNotAnImage.pipe(pipeline).pipe(writable); }); - it('Handle File to Stream error', function (done) { + it('Handle File to Stream error', function (_t, done) { const readableButNotAnImage = sharp(__filename).resize(320, 240); let anErrorWasEmitted = false; readableButNotAnImage.on('error', function (err) { @@ -278,7 +279,7 @@ describe('Input/output', function () { readableButNotAnImage.pipe(writable); }); - it('Readable side of Stream can start flowing after Writable side has finished', function (done) { + it('Readable side of Stream can start flowing after Writable side has finished', function (_t, done) { const readable = fs.createReadStream(fixtures.inputJpg); const writable = fs.createWriteStream(outputJpg); writable.on('close', function () { @@ -299,6 +300,20 @@ describe('Input/output', function () { }); }); + it('Non-Stream input generates error when provided Stream-like data', (_t, done) => { + sharp('input')._write('fail', null, (err) => { + assert.strictEqual(err.message, 'Unexpected data on Writable Stream'); + done(); + }); + }); + + it('Non-Buffer chunk on Stream input generates error', (_t, done) => { + sharp()._write('fail', null, (err) => { + assert.strictEqual(err.message, 'Non-Buffer data on Writable Stream'); + done(); + }); + }); + it('Invalid sequential read option throws', () => { assert.throws(() => { sharp({ sequentialRead: 'fail' }); @@ -333,7 +348,7 @@ describe('Input/output', function () { }) ); - it('Support output to jpg format', function (done) { + it('Support output to jpg format', function (_t, done) { sharp(fixtures.inputPng) .resize(320, 240) .toFormat('jpg') @@ -348,7 +363,7 @@ describe('Input/output', function () { }); }); - it('Support output to tif format', function (done) { + it('Support output to tif format', function (_t, done) { sharp(fixtures.inputTiff) .resize(320, 240) .toFormat('tif') @@ -377,7 +392,7 @@ describe('Input/output', function () { assert.strictEqual(Buffer.isBuffer(data), true); }); - it('Fail when output File is input File', function (done) { + it('Fail when output File is input File', function (_t, done) { sharp(fixtures.inputJpg).toFile(fixtures.inputJpg, function (err) { assert(err instanceof Error); assert.strictEqual('Cannot use same file for input and output', err.message); @@ -385,7 +400,7 @@ describe('Input/output', function () { }); }); - it('Fail when output File is input File via Promise', function (done) { + it('Fail when output File is input File via Promise', function (_t, done) { sharp(fixtures.inputJpg).toFile(fixtures.inputJpg).then(function () { done(new Error('Unexpectedly resolved Promise')); }).catch(function (err) { @@ -395,7 +410,7 @@ describe('Input/output', function () { }); }); - it('Fail when output File is input File (relative output, absolute input)', function (done) { + it('Fail when output File is input File (relative output, absolute input)', function (_t, done) { const relativePath = path.relative(process.cwd(), fixtures.inputJpg); sharp(fixtures.inputJpg).toFile(relativePath, function (err) { assert(err instanceof Error); @@ -404,7 +419,7 @@ describe('Input/output', function () { }); }); - it('Fail when output File is input File via Promise (relative output, absolute input)', function (done) { + it('Fail when output File is input File via Promise (relative output, absolute input)', function (_t, done) { const relativePath = path.relative(process.cwd(), fixtures.inputJpg); sharp(fixtures.inputJpg).toFile(relativePath).then(function () { done(new Error('Unexpectedly resolved Promise')); @@ -415,7 +430,7 @@ describe('Input/output', function () { }); }); - it('Fail when output File is input File (relative input, absolute output)', function (done) { + it('Fail when output File is input File (relative input, absolute output)', function (_t, done) { const relativePath = path.relative(process.cwd(), fixtures.inputJpg); sharp(relativePath).toFile(fixtures.inputJpg, function (err) { assert(err instanceof Error); @@ -424,7 +439,7 @@ describe('Input/output', function () { }); }); - it('Fail when output File is input File via Promise (relative input, absolute output)', function (done) { + it('Fail when output File is input File via Promise (relative input, absolute output)', function (_t, done) { const relativePath = path.relative(process.cwd(), fixtures.inputJpg); sharp(relativePath).toFile(fixtures.inputJpg).then(function () { done(new Error('Unexpectedly resolved Promise')); @@ -435,7 +450,7 @@ describe('Input/output', function () { }); }); - it('Fail when output File is empty', function (done) { + it('Fail when output File is empty', function (_t, done) { sharp(fixtures.inputJpg).toFile('', function (err) { assert(err instanceof Error); assert.strictEqual('Missing output file path', err.message); @@ -443,7 +458,7 @@ describe('Input/output', function () { }); }); - it('Fail when output File is empty via Promise', function (done) { + it('Fail when output File is empty via Promise', function (_t, done) { sharp(fixtures.inputJpg).toFile('').then(function () { done(new Error('Unexpectedly resolved Promise')); }).catch(function (err) { @@ -511,7 +526,7 @@ describe('Input/output', function () { .toBuffer(); }); - it('Invalid output format', function (done) { + it('Invalid output format', function (_t, done) { let isValid = false; try { sharp().toFormat('zoinks'); @@ -521,7 +536,7 @@ describe('Input/output', function () { done(); }); - it('File input with corrupt header fails gracefully', function (done) { + it('File input with corrupt header fails gracefully', function (_t, done) { sharp(fixtures.inputJpgWithCorruptHeader) .toBuffer(function (err) { assert.strictEqual(true, !!err); @@ -529,7 +544,7 @@ describe('Input/output', function () { }); }); - it('Buffer input with corrupt header fails gracefully', function (done) { + it('Buffer input with corrupt header fails gracefully', function (_t, done) { sharp(fs.readFileSync(fixtures.inputJpgWithCorruptHeader)) .toBuffer(function (err) { assert.strictEqual(true, !!err); @@ -537,7 +552,7 @@ describe('Input/output', function () { }); }); - it('Stream input with corrupt header fails gracefully', function (done) { + it('Stream input with corrupt header fails gracefully', function (_t, done) { const transformer = sharp(); transformer .toBuffer() @@ -556,7 +571,7 @@ describe('Input/output', function () { describe('Output filename with unknown extension', function () { const outputZoinks = fixtures.path('output.zoinks'); - it('Match JPEG input', function (done) { + it('Match JPEG input', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 80) .toFile(outputZoinks, function (err, info) { @@ -569,7 +584,7 @@ describe('Input/output', function () { }); }); - it('Match PNG input', function (done) { + it('Match PNG input', function (_t, done) { sharp(fixtures.inputPng) .resize(320, 80) .toFile(outputZoinks, function (err, info) { @@ -582,7 +597,7 @@ describe('Input/output', function () { }); }); - it('Match WebP input', function (done) { + it('Match WebP input', function (_t, done) { sharp(fixtures.inputWebP) .resize(320, 80) .toFile(outputZoinks, function (err, info) { @@ -595,7 +610,7 @@ describe('Input/output', function () { }); }); - it('Match TIFF input', function (done) { + it('Match TIFF input', function (_t, done) { sharp(fixtures.inputTiff) .resize(320, 80) .toFile(outputZoinks, function (err, info) { @@ -608,7 +623,7 @@ describe('Input/output', function () { }); }); - it('Force JPEG format for PNG input', function (done) { + it('Force JPEG format for PNG input', function (_t, done) { sharp(fixtures.inputPng) .resize(320, 80) .jpeg() @@ -623,7 +638,7 @@ describe('Input/output', function () { }); }); - it('Input and output formats match when not forcing', function (done) { + it('Input and output formats match when not forcing', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .png({ compressionLevel: 1, force: false }) @@ -647,7 +662,7 @@ describe('Input/output', function () { }); }); - it('toFormat=JPEG takes precedence over WebP extension', function (done) { + it('toFormat=JPEG takes precedence over WebP extension', function (_t, done) { const outputWebP = fixtures.path('output.webp'); sharp(fixtures.inputPng) .resize(8) @@ -659,7 +674,7 @@ describe('Input/output', function () { }); }); - it('toFormat=WebP takes precedence over JPEG extension', function (done) { + it('toFormat=WebP takes precedence over JPEG extension', function (_t, done) { sharp(fixtures.inputPng) .resize(8) .webp() @@ -670,7 +685,7 @@ describe('Input/output', function () { }); }); - it('Load Vips V file', function (done) { + it('Load Vips V file', function (_t, done) { sharp(fixtures.inputV) .jpeg() .toBuffer(function (err, data, info) { @@ -683,7 +698,7 @@ describe('Input/output', function () { }); }); - it('Save Vips V file', function (done) { + it('Save Vips V file', function (_t, done) { const outputV = fixtures.path('output.v'); sharp(fixtures.inputJpg) .extract({ left: 910, top: 1105, width: 70, height: 60 }) @@ -963,7 +978,7 @@ describe('Input/output', function () { }); describe('create new image', function () { - it('RGB', function (done) { + it('RGB', function (_t, done) { const create = { width: 10, height: 20, @@ -981,7 +996,7 @@ describe('Input/output', function () { fixtures.assertSimilar(fixtures.expected('create-rgb.jpg'), data, done); }); }); - it('RGBA', function (done) { + it('RGBA', function (_t, done) { const create = { width: 20, height: 10, @@ -1022,7 +1037,7 @@ describe('Input/output', function () { }); }); - it('Queue length change events', function (done) { + it('Queue length change events', function (_t, done) { let eventCounter = 0; const queueListener = function (queueLength) { assert.strictEqual(true, queueLength === 0 || queueLength === 1); @@ -1041,7 +1056,7 @@ describe('Input/output', function () { }); }); - it('Info event data', function (done) { + it('Info event data', function (_t, done) { const readable = fs.createReadStream(fixtures.inputJPGBig); const inPipeline = sharp() .resize(840, 472) diff --git a/test/unit/join.js b/test/unit/join.js index 600ffb9a0..6538346ff 100644 --- a/test/unit/join.js +++ b/test/unit/join.js @@ -1,6 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); diff --git a/test/unit/joinChannel.js b/test/unit/joinChannel.js index 42bc23830..814565ebf 100644 --- a/test/unit/joinChannel.js +++ b/test/unit/joinChannel.js @@ -1,6 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const fs = require('node:fs'); @@ -8,7 +9,7 @@ const sharp = require('../../'); const fixtures = require('../fixtures'); describe('Image channel insertion', function () { - it('Grayscale to RGB, buffer', function (done) { + it('Grayscale to RGB, buffer', function (_t, done) { sharp(fixtures.inputPng) // gray -> red .resize(320, 240) .joinChannel(fixtures.inputPngTestJoinChannel) // new green channel @@ -22,7 +23,7 @@ describe('Image channel insertion', function () { }); }); - it('Grayscale to RGB, file', function (done) { + it('Grayscale to RGB, file', function (_t, done) { sharp(fixtures.inputPng) // gray -> red .resize(320, 240) .joinChannel(fs.readFileSync(fixtures.inputPngTestJoinChannel)) // new green channel @@ -36,7 +37,7 @@ describe('Image channel insertion', function () { }); }); - it('Grayscale to RGBA, buffer', function (done) { + it('Grayscale to RGBA, buffer', function (_t, done) { sharp(fixtures.inputPng) // gray -> red .resize(320, 240) .joinChannel([ @@ -54,7 +55,7 @@ describe('Image channel insertion', function () { }); }); - it('Grayscale to RGBA, file', function (done) { + it('Grayscale to RGBA, file', function (_t, done) { sharp(fixtures.inputPng) // gray -> red .resize(320, 240) .joinChannel([ @@ -72,7 +73,7 @@ describe('Image channel insertion', function () { }); }); - it('Grayscale to CMYK, buffers', function (done) { + it('Grayscale to CMYK, buffers', function (_t, done) { sharp(fixtures.inputPng) // gray -> magenta .resize(320, 240) .joinChannel([ @@ -91,7 +92,7 @@ describe('Image channel insertion', function () { }); }); - it('Join raw buffers to RGB', function (done) { + it('Join raw buffers to RGB', function (_t, done) { Promise.all([ sharp(fixtures.inputPngTestJoinChannel).toColourspace('b-w').raw().toBuffer(), sharp(fixtures.inputPngStripesH).toColourspace('b-w').raw().toBuffer() @@ -119,7 +120,7 @@ describe('Image channel insertion', function () { }); }); - it('Grayscale to RGBA, files, two arrays', function (done) { + it('Grayscale to RGBA, files, two arrays', function (_t, done) { sharp(fixtures.inputPng) // gray -> red .resize(320, 240) .joinChannel([fs.readFileSync(fixtures.inputPngTestJoinChannel)]) // new green channel diff --git a/test/unit/jp2.js b/test/unit/jp2.js index 30b458ac6..3445c90f7 100644 --- a/test/unit/jp2.js +++ b/test/unit/jp2.js @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 const fs = require('node:fs'); +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); diff --git a/test/unit/jpeg.js b/test/unit/jpeg.js index 916d23587..0954439e8 100644 --- a/test/unit/jpeg.js +++ b/test/unit/jpeg.js @@ -1,13 +1,14 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); describe('JPEG', function () { - it('JPEG quality', function (done) { + it('JPEG quality', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .jpeg({ quality: 70 }) @@ -50,7 +51,7 @@ describe('JPEG', function () { }); }); - it('Progressive JPEG image', function (done) { + it('Progressive JPEG image', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .jpeg({ progressive: false }) @@ -77,7 +78,7 @@ describe('JPEG', function () { }); }); - it('Without chroma subsampling generates larger file', function (done) { + it('Without chroma subsampling generates larger file', function (_t, done) { // First generate with chroma subsampling (default) sharp(fixtures.inputJpg) .resize(320, 240) @@ -112,7 +113,7 @@ describe('JPEG', function () { }); }); - it('Trellis quantisation', function (done) { + it('Trellis quantisation', function (_t, done) { // First generate without sharp(fixtures.inputJpg) .resize(320, 240) @@ -142,7 +143,7 @@ describe('JPEG', function () { }); }); - it('Overshoot deringing', function (done) { + it('Overshoot deringing', function (_t, done) { // First generate without sharp(fixtures.inputJpg) .resize(320, 240) @@ -170,7 +171,7 @@ describe('JPEG', function () { }); }); - it('Optimise scans generates different output length', function (done) { + it('Optimise scans generates different output length', function (_t, done) { // First generate without sharp(fixtures.inputJpg) .resize(320, 240) @@ -200,7 +201,7 @@ describe('JPEG', function () { }); }); - it('Optimise coding generates smaller output length', function (done) { + it('Optimise coding generates smaller output length', function (_t, done) { // First generate with optimize coding enabled (default) sharp(fixtures.inputJpg) .resize(320, 240) @@ -230,7 +231,7 @@ describe('JPEG', function () { }); }); - it('Specifying quantisation table provides different JPEG', function (done) { + it('Specifying quantisation table provides different JPEG', function (_t, done) { // First generate with default quantisation table sharp(fixtures.inputJpg) .resize(320, 240) @@ -261,7 +262,7 @@ describe('JPEG', function () { }); }); - it('Specifying quantization table provides different JPEG', function (done) { + it('Specifying quantization table provides different JPEG', function (_t, done) { // First generate with default quantization table sharp(fixtures.inputJpg) .resize(320, 240) diff --git a/test/unit/jxl.js b/test/unit/jxl.js index 7fcfd75fe..20af7de0c 100644 --- a/test/unit/jxl.js +++ b/test/unit/jxl.js @@ -1,6 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); diff --git a/test/unit/libvips.js b/test/unit/libvips.js index dfd61b260..79f70dc46 100644 --- a/test/unit/libvips.js +++ b/test/unit/libvips.js @@ -1,6 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { after, before, describe, it } = require('node:test'); const assert = require('node:assert'); const fs = require('node:fs'); const semver = require('semver'); @@ -152,7 +153,7 @@ describe('libvips binaries', function () { console.error = consoleError; }); - it('logs an info message', function (done) { + it('logs an info message', function (_t, done) { console.log = function (msg) { assert.strictEqual(msg, 'sharp: progress'); done(); @@ -160,7 +161,7 @@ describe('libvips binaries', function () { libvips.log('progress'); }); - it('logs an error message', function (done) { + it('logs an error message', function (_t, done) { console.error = function (msg) { assert.strictEqual(msg, 'sharp: Installation error: problem'); done(); diff --git a/test/unit/linear.js b/test/unit/linear.js index 0ac952f22..dba44a2e3 100644 --- a/test/unit/linear.js +++ b/test/unit/linear.js @@ -4,6 +4,7 @@ const sharp = require('../../'); const fixtures = require('../fixtures'); +const { describe, it } = require('node:test'); const assert = require('node:assert'); describe('Linear adjustment', function () { @@ -12,7 +13,7 @@ describe('Linear adjustment', function () { const a = 255 / (whitePoint - blackPoint); const b = -blackPoint * a; - it('applies linear levels adjustment w/o alpha ch', function (done) { + it('applies linear levels adjustment w/o alpha ch', function (_t, done) { sharp(fixtures.inputJpgWithLowContrast) .linear(a, b) .toBuffer(function (err, data) { @@ -21,7 +22,7 @@ describe('Linear adjustment', function () { }); }); - it('applies slope level adjustment w/o alpha ch', function (done) { + it('applies slope level adjustment w/o alpha ch', function (_t, done) { sharp(fixtures.inputJpgWithLowContrast) .linear(a) .toBuffer(function (err, data) { @@ -30,7 +31,7 @@ describe('Linear adjustment', function () { }); }); - it('applies offset level adjustment w/o alpha ch', function (done) { + it('applies offset level adjustment w/o alpha ch', function (_t, done) { sharp(fixtures.inputJpgWithLowContrast) .linear(null, b) .toBuffer(function (err, data) { @@ -39,7 +40,7 @@ describe('Linear adjustment', function () { }); }); - it('applies linear levels adjustment w alpha ch', function (done) { + it('applies linear levels adjustment w alpha ch', function (_t, done) { sharp(fixtures.inputPngOverlayLayer1) .resize(240) .linear(a, b) @@ -49,7 +50,7 @@ describe('Linear adjustment', function () { }); }); - it('applies linear levels adjustment to 16-bit w alpha ch', function (done) { + it('applies linear levels adjustment to 16-bit w alpha ch', function (_t, done) { sharp(fixtures.inputPngWithTransparency16bit) .linear(a, b) .png({ compressionLevel: 0 }) @@ -59,7 +60,7 @@ describe('Linear adjustment', function () { }); }); - it('applies slope level adjustment w alpha ch', function (done) { + it('applies slope level adjustment w alpha ch', function (_t, done) { sharp(fixtures.inputPngOverlayLayer1) .resize(240) .linear(a) @@ -69,7 +70,7 @@ describe('Linear adjustment', function () { }); }); - it('applies offset level adjustment w alpha ch', function (done) { + it('applies offset level adjustment w alpha ch', function (_t, done) { sharp(fixtures.inputPngOverlayLayer1) .resize(240) .linear(null, b) @@ -79,7 +80,7 @@ describe('Linear adjustment', function () { }); }); - it('per channel level adjustment', function (done) { + it('per channel level adjustment', function (_t, done) { sharp(fixtures.inputWebP) .linear([0.25, 0.5, 0.75], [150, 100, 50]).toBuffer(function (err, data) { if (err) throw err; diff --git a/test/unit/median.js b/test/unit/median.js index 227e4c609..5a2f6b3d3 100644 --- a/test/unit/median.js +++ b/test/unit/median.js @@ -1,6 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); diff --git a/test/unit/metadata.js b/test/unit/metadata.js index 4b3ee6c5d..73875a54c 100644 --- a/test/unit/metadata.js +++ b/test/unit/metadata.js @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 const fs = require('node:fs'); +const { describe, it } = require('node:test'); const assert = require('node:assert'); const exifReader = require('exif-reader'); const icc = require('icc'); @@ -12,7 +13,7 @@ const fixtures = require('../fixtures'); const create = { width: 1, height: 1, channels: 3, background: 'red' }; describe('Image metadata', function () { - it('JPEG', function (done) { + it('JPEG', function (_t, done) { sharp(fixtures.inputJpg).metadata(function (err, metadata) { if (err) throw err; assert.strictEqual('jpeg', metadata.format); @@ -34,7 +35,7 @@ describe('Image metadata', function () { }); }); - it('JPEG with EXIF/ICC', function (done) { + it('JPEG with EXIF/ICC', function (_t, done) { sharp(fixtures.inputJpgWithExif).metadata(function (err, metadata) { if (err) throw err; assert.strictEqual('jpeg', metadata.format); @@ -67,7 +68,7 @@ describe('Image metadata', function () { }); }); - it('JPEG with IPTC/XMP', function (done) { + it('JPEG with IPTC/XMP', function (_t, done) { sharp(fixtures.inputJpgWithIptcAndXmp).metadata(function (err, metadata) { if (err) throw err; // IPTC @@ -85,7 +86,7 @@ describe('Image metadata', function () { }); }); - it('TIFF', function (done) { + it('TIFF', function (_t, done) { sharp(fixtures.inputTiff).metadata(function (err, metadata) { if (err) throw err; assert.strictEqual('tiff', metadata.format); @@ -112,7 +113,7 @@ describe('Image metadata', function () { }); }); - it('Multipage TIFF', function (done) { + it('Multipage TIFF', function (_t, done) { sharp(fixtures.inputTiffMultipage).metadata(function (err, metadata) { if (err) throw err; assert.strictEqual('tiff', metadata.format); @@ -135,7 +136,7 @@ describe('Image metadata', function () { }); }); - it('PNG', function (done) { + it('PNG', function (_t, done) { sharp(fixtures.inputPng).metadata(function (err, metadata) { if (err) throw err; assert.strictEqual('png', metadata.format); @@ -159,7 +160,7 @@ describe('Image metadata', function () { }); }); - it('PNG with comment', function (done) { + it('PNG with comment', function (_t, done) { sharp(fixtures.inputPngTestJoinChannel).metadata(function (err, metadata) { if (err) throw err; assert.strictEqual('png', metadata.format); @@ -184,7 +185,7 @@ describe('Image metadata', function () { }); }); - it('Transparent PNG', function (done) { + it('Transparent PNG', function (_t, done) { sharp(fixtures.inputPngWithTransparency).metadata(function (err, metadata) { if (err) throw err; assert.strictEqual('png', metadata.format); @@ -256,7 +257,7 @@ describe('Image metadata', function () { }); }); - it('WebP', function (done) { + it('WebP', function (_t, done) { sharp(fixtures.inputWebP).metadata(function (err, metadata) { if (err) throw err; assert.strictEqual('webp', metadata.format); @@ -348,7 +349,7 @@ describe('Image metadata', function () { }) ); - it('GIF', function (done) { + it('GIF', function (_t, done) { sharp(fixtures.inputGif).metadata(function (err, metadata) { if (err) throw err; assert.strictEqual('gif', metadata.format); @@ -368,7 +369,7 @@ describe('Image metadata', function () { done(); }); }); - it('GIF grey+alpha', function (done) { + it('GIF grey+alpha', function (_t, done) { sharp(fixtures.inputGifGreyPlusAlpha).metadata(function (err, metadata) { if (err) throw err; assert.strictEqual('gif', metadata.format); @@ -456,7 +457,7 @@ describe('Image metadata', function () { }) ); - it('File in, Promise out', function (done) { + it('File in, Promise out', function (_t, done) { sharp(fixtures.inputJpg).metadata().then(function (metadata) { assert.strictEqual('jpeg', metadata.format); assert.strictEqual('undefined', typeof metadata.size); @@ -489,7 +490,7 @@ describe('Image metadata', function () { ) ); - it('Invalid stream in, callback out', (done) => { + it('Invalid stream in, callback out', (_t, done) => { fs.createReadStream(__filename).pipe( sharp().metadata((err) => { assert.strictEqual(err.message, 'Input buffer contains unsupported image format'); @@ -500,7 +501,7 @@ describe('Image metadata', function () { ); }); - it('Stream in, Promise out', function (done) { + it('Stream in, Promise out', function (_t, done) { const readable = fs.createReadStream(fixtures.inputJpg); const pipeline = sharp(); pipeline.metadata().then(function (metadata) { @@ -520,7 +521,7 @@ describe('Image metadata', function () { assert.strictEqual('undefined', typeof metadata.exif); assert.strictEqual('undefined', typeof metadata.icc); done(); - }).catch(done); + }).catch(_t, done); readable.pipe(pipeline); }); @@ -538,7 +539,7 @@ describe('Image metadata', function () { ); }); - it('Stream in, finish event fires before metadata is requested', (done) => { + it('Stream in, finish event fires before metadata is requested', (_t, done) => { const create = { width: 1, height: 1, channels: 3, background: 'red' }; const image1 = sharp({ create }).png().pipe(sharp()); const image2 = sharp({ create }).png().pipe(sharp()); @@ -551,7 +552,7 @@ describe('Image metadata', function () { }, 500); }); - it('Stream', function (done) { + it('Stream', function (_t, done) { const readable = fs.createReadStream(fixtures.inputJpg); const pipeline = sharp().metadata(function (err, metadata) { if (err) throw err; @@ -575,7 +576,7 @@ describe('Image metadata', function () { readable.pipe(pipeline); }); - it('Resize to half width using metadata', function (done) { + it('Resize to half width using metadata', function (_t, done) { const image = sharp(fixtures.inputJpg); image.metadata(function (err, metadata) { if (err) throw err; @@ -604,7 +605,7 @@ describe('Image metadata', function () { }); }); - it('Keep EXIF metadata and add sRGB profile after a resize', function (done) { + it('Keep EXIF metadata and add sRGB profile after a resize', function (_t, done) { sharp(fixtures.inputJpgWithExif) .resize(320, 240) .withMetadata() @@ -724,7 +725,7 @@ describe('Image metadata', function () { assert.strictEqual(undefined, metadata.icc); }); - it('Apply CMYK output ICC profile', function (done) { + it('Apply CMYK output ICC profile', function (_t, done) { const output = fixtures.path('output.icc-cmyk.jpg'); sharp(fixtures.inputJpg) .resize(64) @@ -749,7 +750,7 @@ describe('Image metadata', function () { }); }); - it('Apply custom output ICC profile', function (done) { + it('Apply custom output ICC profile', function (_t, done) { const output = fixtures.path('output.hilutite.jpg'); sharp(fixtures.inputJpg) .resize(64) @@ -789,7 +790,7 @@ describe('Image metadata', function () { ) ); - it('Remove EXIF metadata after a resize', function (done) { + it('Remove EXIF metadata after a resize', function (_t, done) { sharp(fixtures.inputJpgWithExif) .resize(320, 240) .toBuffer(function (err, buffer) { @@ -805,7 +806,7 @@ describe('Image metadata', function () { }); }); - it('Remove metadata from PNG output', function (done) { + it('Remove metadata from PNG output', function (_t, done) { sharp(fixtures.inputJpgWithExif) .png() .toBuffer(function (err, buffer) { @@ -992,7 +993,7 @@ describe('Image metadata', function () { assert.strictEqual(description, 'sP3C'); }); - it('File input with corrupt header fails gracefully', function (done) { + it('File input with corrupt header fails gracefully', function (_t, done) { sharp(fixtures.inputJpgWithCorruptHeader) .metadata(function (err) { assert.strictEqual(true, !!err); @@ -1001,7 +1002,7 @@ describe('Image metadata', function () { }); }); - it('Buffer input with corrupt header fails gracefully', function (done) { + it('Buffer input with corrupt header fails gracefully', function (_t, done) { sharp(fs.readFileSync(fixtures.inputJpgWithCorruptHeader)) .metadata(function (err) { assert.strictEqual(true, !!err); @@ -1010,7 +1011,7 @@ describe('Image metadata', function () { }); }); - it('Unsupported lossless JPEG passes underlying error message', function (done) { + it('Unsupported lossless JPEG passes underlying error message', function (_t, done) { sharp(fixtures.inputJpgLossless) .metadata(function (err) { assert.strictEqual(true, !!err); diff --git a/test/unit/modulate.js b/test/unit/modulate.js index 04d27281c..502677629 100644 --- a/test/unit/modulate.js +++ b/test/unit/modulate.js @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 const sharp = require('../../'); +const { describe, it } = require('node:test'); const assert = require('node:assert'); const fixtures = require('../fixtures'); diff --git a/test/unit/negate.js b/test/unit/negate.js index c442d7cf4..bd0c0a941 100644 --- a/test/unit/negate.js +++ b/test/unit/negate.js @@ -1,13 +1,14 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); describe('Negate', function () { - it('negate (jpeg)', function (done) { + it('negate (jpeg)', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .negate() @@ -20,7 +21,7 @@ describe('Negate', function () { }); }); - it('negate (png)', function (done) { + it('negate (png)', function (_t, done) { sharp(fixtures.inputPng) .resize(320, 240) .negate() @@ -33,7 +34,7 @@ describe('Negate', function () { }); }); - it('negate (png, trans)', function (done) { + it('negate (png, trans)', function (_t, done) { sharp(fixtures.inputPngWithTransparency) .resize(320, 240) .negate() @@ -46,7 +47,7 @@ describe('Negate', function () { }); }); - it('negate (png, alpha)', function (done) { + it('negate (png, alpha)', function (_t, done) { sharp(fixtures.inputPngWithGreyAlpha) .resize(320, 240) .negate() @@ -59,7 +60,7 @@ describe('Negate', function () { }); }); - it('negate (webp)', function (done) { + it('negate (webp)', function (_t, done) { sharp(fixtures.inputWebP) .resize(320, 240) .negate() @@ -72,7 +73,7 @@ describe('Negate', function () { }); }); - it('negate (webp, trans)', function (done) { + it('negate (webp, trans)', function (_t, done) { sharp(fixtures.inputWebPWithTransparency) .resize(320, 240) .negate() @@ -85,7 +86,7 @@ describe('Negate', function () { }); }); - it('negate (true)', function (done) { + it('negate (true)', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .negate(true) @@ -98,7 +99,7 @@ describe('Negate', function () { }); }); - it('negate (false)', function (done) { + it('negate (false)', function (_t, done) { const output = fixtures.path('output.unmodified-by-negate.png'); sharp(fixtures.inputJpgWithLowContrast) .negate(false) @@ -109,7 +110,7 @@ describe('Negate', function () { }); }); - it('negate ({alpha: true})', function (done) { + it('negate ({alpha: true})', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .negate({ alpha: true }) @@ -122,7 +123,7 @@ describe('Negate', function () { }); }); - it('negate non-alpha channels (png)', function (done) { + it('negate non-alpha channels (png)', function (_t, done) { sharp(fixtures.inputPng) .resize(320, 240) .negate({ alpha: false }) @@ -135,7 +136,7 @@ describe('Negate', function () { }); }); - it('negate non-alpha channels (png, trans)', function (done) { + it('negate non-alpha channels (png, trans)', function (_t, done) { sharp(fixtures.inputPngWithTransparency) .resize(320, 240) .negate({ alpha: false }) @@ -148,7 +149,7 @@ describe('Negate', function () { }); }); - it('negate non-alpha channels (png, alpha)', function (done) { + it('negate non-alpha channels (png, alpha)', function (_t, done) { sharp(fixtures.inputPngWithGreyAlpha) .resize(320, 240) .negate({ alpha: false }) @@ -161,7 +162,7 @@ describe('Negate', function () { }); }); - it('negate non-alpha channels (webp)', function (done) { + it('negate non-alpha channels (webp)', function (_t, done) { sharp(fixtures.inputWebP) .resize(320, 240) .negate({ alpha: false }) @@ -174,7 +175,7 @@ describe('Negate', function () { }); }); - it('negate non-alpha channels (webp, trans)', function (done) { + it('negate non-alpha channels (webp, trans)', function (_t, done) { sharp(fixtures.inputWebPWithTransparency) .resize(320, 240) .negate({ alpha: false }) diff --git a/test/unit/noise.js b/test/unit/noise.js index 97b8b16fe..3578fbec7 100644 --- a/test/unit/noise.js +++ b/test/unit/noise.js @@ -1,13 +1,14 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); describe('Gaussian noise', function () { - it('generate single-channel gaussian noise', function (done) { + it('generate single-channel gaussian noise', function (_t, done) { const output = fixtures.path('output.noise-1-channel.png'); const noise = sharp({ create: { @@ -36,7 +37,7 @@ describe('Gaussian noise', function () { }); }); - it('generate 3-channels gaussian noise', function (done) { + it('generate 3-channels gaussian noise', function (_t, done) { const output = fixtures.path('output.noise-3-channels.png'); const noise = sharp({ create: { @@ -65,7 +66,7 @@ describe('Gaussian noise', function () { }); }); - it('overlay 3-channels gaussian noise over image', function (done) { + it('overlay 3-channels gaussian noise over image', function (_t, done) { const output = fixtures.path('output.noise-image.jpg'); const noise = sharp({ create: { @@ -110,7 +111,7 @@ describe('Gaussian noise', function () { }); }); - it('overlay strong single-channel (sRGB) gaussian noise with 25% transparency over transparent png image', function (done) { + it('overlay strong single-channel (sRGB) gaussian noise with 25% transparency over transparent png image', function (_t, done) { const output = fixtures.path('output.noise-image-transparent.png'); const width = 320; const height = 240; diff --git a/test/unit/normalize.js b/test/unit/normalize.js index 843c01df0..0c9a9b280 100644 --- a/test/unit/normalize.js +++ b/test/unit/normalize.js @@ -1,6 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); @@ -18,7 +19,7 @@ const assertNormalized = function (data) { }; describe('Normalization', function () { - it('spreads rgb image values between 0 and 255', function (done) { + it('spreads rgb image values between 0 and 255', function (_t, done) { sharp(fixtures.inputJpgWithLowContrast) .normalise() .raw() @@ -29,7 +30,7 @@ describe('Normalization', function () { }); }); - it('spreads grayscaled image values between 0 and 255', function (done) { + it('spreads grayscaled image values between 0 and 255', function (_t, done) { sharp(fixtures.inputJpgWithLowContrast) .greyscale() .normalize() @@ -41,7 +42,7 @@ describe('Normalization', function () { }); }); - it('stretches greyscale images with alpha channel', function (done) { + it('stretches greyscale images with alpha channel', function (_t, done) { sharp(fixtures.inputPngWithGreyAlpha) .normalise() .raw() @@ -52,7 +53,7 @@ describe('Normalization', function () { }); }); - it('keeps an existing alpha channel', function (done) { + it('keeps an existing alpha channel', function (_t, done) { sharp(fixtures.inputPngWithTransparency) .resize(8, 8) .normalize() @@ -68,7 +69,7 @@ describe('Normalization', function () { }); }); - it('keeps the alpha channel of greyscale images intact', function (done) { + it('keeps the alpha channel of greyscale images intact', function (_t, done) { sharp(fixtures.inputPngWithGreyAlpha) .resize(8, 8) .normalise() @@ -84,7 +85,7 @@ describe('Normalization', function () { }); }); - it('does not alter images with only one color', function (done) { + it('does not alter images with only one color', function (_t, done) { const output = fixtures.path('output.unmodified-png-with-one-color.png'); sharp(fixtures.inputPngWithOneColor) .normalize() @@ -95,7 +96,7 @@ describe('Normalization', function () { }); }); - it('works with 16-bit RGBA images', function (done) { + it('works with 16-bit RGBA images', function (_t, done) { sharp(fixtures.inputPngWithTransparency16bit) .normalise() .raw() @@ -106,7 +107,7 @@ describe('Normalization', function () { }); }); - it('should handle luminance range', function (done) { + it('should handle luminance range', function (_t, done) { sharp(fixtures.inputJpgWithLowContrast) .normalise({ lower: 10, upper: 70 }) .raw() diff --git a/test/unit/png.js b/test/unit/png.js index 9e8b4db4f..d5f487ae6 100644 --- a/test/unit/png.js +++ b/test/unit/png.js @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 const fs = require('node:fs'); +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); @@ -20,7 +21,7 @@ describe('PNG', function () { }); }); - it('default compressionLevel generates smaller file than compressionLevel=0', function (done) { + it('default compressionLevel generates smaller file than compressionLevel=0', function (_t, done) { // First generate with default compressionLevel sharp(fixtures.inputPng) .resize(320, 240) @@ -43,7 +44,7 @@ describe('PNG', function () { }); }); - it('without adaptiveFiltering generates smaller file', function (done) { + it('without adaptiveFiltering generates smaller file', function (_t, done) { // First generate with adaptive filtering sharp(fixtures.inputPng) .resize(320, 240) @@ -78,7 +79,7 @@ describe('PNG', function () { }); }); - it('Progressive PNG image', function (done) { + it('Progressive PNG image', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .png({ progressive: false }) diff --git a/test/unit/raw.js b/test/unit/raw.js index 28f4d3924..3d9c1b77b 100644 --- a/test/unit/raw.js +++ b/test/unit/raw.js @@ -1,6 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); @@ -82,7 +83,7 @@ describe('Raw pixel data', function () { ); }); - it('RGB', function (done) { + it('RGB', function (_t, done) { // Convert to raw pixel data sharp(fixtures.inputJpg) .resize(256) @@ -111,7 +112,7 @@ describe('Raw pixel data', function () { }); }); - it('RGBA', function (done) { + it('RGBA', function (_t, done) { // Convert to raw pixel data sharp(fixtures.inputPngOverlayLayer1) .resize(256) @@ -140,7 +141,7 @@ describe('Raw pixel data', function () { }); }); - it('RGBA premultiplied', function (done) { + it('RGBA premultiplied', function (_t, done) { // Convert to raw pixel data sharp(fixtures.inputPngSolidAlpha) .resize(256) @@ -186,7 +187,7 @@ describe('Raw pixel data', function () { }); }); - it('JPEG to raw Stream and back again', function (done) { + it('JPEG to raw Stream and back again', function (_t, done) { const width = 32; const height = 24; const writable = sharp({ @@ -213,7 +214,7 @@ describe('Raw pixel data', function () { }); describe('Output raw, uncompressed image data', function () { - it('1 channel greyscale image', function (done) { + it('1 channel greyscale image', function (_t, done) { sharp(fixtures.inputJpg) .greyscale() .resize(32, 24) @@ -230,7 +231,7 @@ describe('Raw pixel data', function () { }); }); - it('3 channel colour image without transparency', function (done) { + it('3 channel colour image without transparency', function (_t, done) { sharp(fixtures.inputJpg) .resize(32, 24) .toFormat('raw') @@ -245,7 +246,7 @@ describe('Raw pixel data', function () { }); }); - it('4 channel colour image with transparency', function (done) { + it('4 channel colour image with transparency', function (_t, done) { sharp(fixtures.inputPngWithTransparency) .resize(32, 24) .toFormat(sharp.format.raw) diff --git a/test/unit/recomb.js b/test/unit/recomb.js index b894371ac..78d1bf429 100644 --- a/test/unit/recomb.js +++ b/test/unit/recomb.js @@ -1,6 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); @@ -13,7 +14,7 @@ const sepia = [ ]; describe('Recomb', function () { - it('applies a sepia filter using recomb', function (done) { + it('applies a sepia filter using recomb', function (_t, done) { const output = fixtures.path('output.recomb-sepia.jpg'); sharp(fixtures.inputJpgWithLandscapeExif1) .recomb(sepia) @@ -31,7 +32,7 @@ describe('Recomb', function () { }); }); - it('applies a sepia filter using recomb to an PNG with Alpha', function (done) { + it('applies a sepia filter using recomb to an PNG with Alpha', function (_t, done) { const output = fixtures.path('output.recomb-sepia.png'); sharp(fixtures.inputPngAlphaPremultiplicationSmall) .recomb(sepia) @@ -63,7 +64,7 @@ describe('Recomb', function () { assert.strictEqual(3, info.channels); }); - it('applies a different sepia filter using recomb', function (done) { + it('applies a different sepia filter using recomb', function (_t, done) { const output = fixtures.path('output.recomb-sepia2.jpg'); sharp(fixtures.inputJpgWithLandscapeExif1) .recomb([ @@ -84,7 +85,7 @@ describe('Recomb', function () { done(); }); }); - it('increases the saturation of the image', function (done) { + it('increases the saturation of the image', function (_t, done) { const saturationLevel = 1; const output = fixtures.path('output.recomb-saturation.jpg'); sharp(fixtures.inputJpgWithLandscapeExif1) @@ -119,7 +120,7 @@ describe('Recomb', function () { }); }); - it('applies opacity 30% to the image', function (done) { + it('applies opacity 30% to the image', function (_t, done) { const output = fixtures.path('output.recomb-opacity.png'); sharp(fixtures.inputPngWithTransparent) .recomb([ diff --git a/test/unit/resize-contain.js b/test/unit/resize-contain.js index 8dcc908ca..ec5424c8d 100644 --- a/test/unit/resize-contain.js +++ b/test/unit/resize-contain.js @@ -1,13 +1,14 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); describe('Resize fit=contain', function () { - it('Allows specifying the position as a string', function (done) { + it('Allows specifying the position as a string', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240, { fit: 'contain', @@ -22,7 +23,7 @@ describe('Resize fit=contain', function () { }); }); - it('JPEG within PNG, no alpha channel', function (done) { + it('JPEG within PNG, no alpha channel', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240, { fit: 'contain' }) .png() @@ -37,7 +38,7 @@ describe('Resize fit=contain', function () { }); }); - it('JPEG within WebP, to include alpha channel', function (done) { + it('JPEG within WebP, to include alpha channel', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240, { fit: 'contain', @@ -55,7 +56,7 @@ describe('Resize fit=contain', function () { }); }); - it('PNG with alpha channel', function (done) { + it('PNG with alpha channel', function (_t, done) { sharp(fixtures.inputPngWithTransparency) .resize(50, 50, { fit: 'contain' }) .toBuffer(function (err, data, info) { @@ -69,7 +70,7 @@ describe('Resize fit=contain', function () { }); }); - it('16-bit PNG with alpha channel', function (done) { + it('16-bit PNG with alpha channel', function (_t, done) { sharp(fixtures.inputPngWithTransparency16bit) .resize(32, 16, { fit: 'contain' }) .toBuffer(function (err, data, info) { @@ -83,7 +84,7 @@ describe('Resize fit=contain', function () { }); }); - it('16-bit PNG with alpha channel onto RGBA', function (done) { + it('16-bit PNG with alpha channel onto RGBA', function (_t, done) { sharp(fixtures.inputPngWithTransparency16bit) .resize(32, 16, { fit: 'contain', @@ -100,7 +101,7 @@ describe('Resize fit=contain', function () { }); }); - it('PNG with 2 channels', function (done) { + it('PNG with 2 channels', function (_t, done) { sharp(fixtures.inputPngWithGreyAlpha) .resize(32, 16, { fit: 'contain', @@ -117,7 +118,7 @@ describe('Resize fit=contain', function () { }); }); - it('TIFF in LAB colourspace onto RGBA background', function (done) { + it('TIFF in LAB colourspace onto RGBA background', function (_t, done) { sharp(fixtures.inputTiffCielab) .resize(64, 128, { fit: 'contain', @@ -135,7 +136,7 @@ describe('Resize fit=contain', function () { }); }); - it('Enlarge', function (done) { + it('Enlarge', function (_t, done) { sharp(fixtures.inputPngWithOneColor) .resize(320, 240, { fit: 'contain' }) .toBuffer(function (err, data, info) { @@ -150,7 +151,7 @@ describe('Resize fit=contain', function () { }); describe('Animated WebP', function () { - it('Width only', function (done) { + it('Width only', function (_t, done) { sharp(fixtures.inputWebPAnimated, { pages: -1 }) .resize(320, 240, { fit: 'contain', @@ -167,7 +168,7 @@ describe('Resize fit=contain', function () { }); }); - it('Height only', function (done) { + it('Height only', function (_t, done) { sharp(fixtures.inputWebPAnimated, { pages: -1 }) .resize(240, 320, { fit: 'contain', @@ -193,7 +194,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal top', function (done) { + it('Position horizontal top', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, @@ -211,7 +212,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal right top', function (done) { + it('Position horizontal right top', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, @@ -229,7 +230,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal right', function (done) { + it('Position horizontal right', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, @@ -247,7 +248,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal right bottom', function (done) { + it('Position horizontal right bottom', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, @@ -265,7 +266,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal bottom', function (done) { + it('Position horizontal bottom', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, @@ -283,7 +284,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal left bottom', function (done) { + it('Position horizontal left bottom', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, @@ -301,7 +302,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal left', function (done) { + it('Position horizontal left', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, @@ -319,7 +320,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal left top', function (done) { + it('Position horizontal left top', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, @@ -337,7 +338,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal north', function (done) { + it('Position horizontal north', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, @@ -355,7 +356,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal northeast', function (done) { + it('Position horizontal northeast', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, @@ -373,7 +374,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal east', function (done) { + it('Position horizontal east', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, @@ -391,7 +392,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal southeast', function (done) { + it('Position horizontal southeast', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, @@ -409,7 +410,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal south', function (done) { + it('Position horizontal south', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, @@ -427,7 +428,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal southwest', function (done) { + it('Position horizontal southwest', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, @@ -445,7 +446,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal west', function (done) { + it('Position horizontal west', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, @@ -463,7 +464,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal northwest', function (done) { + it('Position horizontal northwest', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, @@ -481,7 +482,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal center', function (done) { + it('Position horizontal center', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, @@ -499,7 +500,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical top', function (done) { + it('Position vertical top', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, @@ -517,7 +518,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical right top', function (done) { + it('Position vertical right top', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, @@ -535,7 +536,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical right', function (done) { + it('Position vertical right', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, @@ -553,7 +554,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical right bottom', function (done) { + it('Position vertical right bottom', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, @@ -571,7 +572,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical bottom', function (done) { + it('Position vertical bottom', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, @@ -589,7 +590,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical left bottom', function (done) { + it('Position vertical left bottom', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, @@ -607,7 +608,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical left', function (done) { + it('Position vertical left', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, @@ -625,7 +626,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical left top', function (done) { + it('Position vertical left top', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, @@ -643,7 +644,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical north', function (done) { + it('Position vertical north', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, @@ -661,7 +662,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical northeast', function (done) { + it('Position vertical northeast', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, @@ -679,7 +680,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical east', function (done) { + it('Position vertical east', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, @@ -697,7 +698,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical southeast', function (done) { + it('Position vertical southeast', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, @@ -715,7 +716,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical south', function (done) { + it('Position vertical south', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, @@ -733,7 +734,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical southwest', function (done) { + it('Position vertical southwest', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, @@ -751,7 +752,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical west', function (done) { + it('Position vertical west', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, @@ -769,7 +770,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical northwest', function (done) { + it('Position vertical northwest', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, @@ -787,7 +788,7 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical center', function (done) { + it('Position vertical center', function (_t, done) { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, diff --git a/test/unit/resize-cover.js b/test/unit/resize-cover.js index b93670d3e..f5bdd5150 100644 --- a/test/unit/resize-cover.js +++ b/test/unit/resize-cover.js @@ -1,6 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); @@ -200,7 +201,7 @@ describe('Resize fit=cover', function () { fixture: 'gravity-west.jpg' } ].forEach(function (settings) { - it(settings.name, function (done) { + it(settings.name, function (_t, done) { sharp(fixtures.inputJpg) .resize(settings.width, settings.height, { fit: sharp.fit.cover, @@ -215,7 +216,7 @@ describe('Resize fit=cover', function () { }); }); - it('Allows specifying the gravity as a string', function (done) { + it('Allows specifying the gravity as a string', function (_t, done) { sharp(fixtures.inputJpg) .resize(80, 320, { fit: sharp.fit.cover, @@ -271,7 +272,7 @@ describe('Resize fit=cover', function () { }); describe('Animated WebP', function () { - it('Width only', function (done) { + it('Width only', function (_t, done) { sharp(fixtures.inputWebPAnimated, { pages: -1 }) .resize(80, 320, { fit: sharp.fit.cover }) .toBuffer(function (err, data, info) { @@ -282,7 +283,7 @@ describe('Resize fit=cover', function () { }); }); - it('Height only', function (done) { + it('Height only', function (_t, done) { sharp(fixtures.inputWebPAnimated, { pages: -1 }) .resize(320, 80, { fit: sharp.fit.cover }) .toBuffer(function (err, data, info) { @@ -295,7 +296,7 @@ describe('Resize fit=cover', function () { }); describe('Entropy-based strategy', function () { - it('JPEG', function (done) { + it('JPEG', function (_t, done) { sharp(fixtures.inputJpg) .resize(80, 320, { fit: 'cover', @@ -313,7 +314,7 @@ describe('Resize fit=cover', function () { }); }); - it('PNG', function (done) { + it('PNG', function (_t, done) { sharp(fixtures.inputPngWithTransparency) .resize(320, 80, { fit: 'cover', @@ -331,7 +332,7 @@ describe('Resize fit=cover', function () { }); }); - it('supports the strategy passed as a string', function (done) { + it('supports the strategy passed as a string', function (_t, done) { sharp(fixtures.inputPngWithTransparency) .resize(320, 80, { fit: 'cover', @@ -363,7 +364,7 @@ describe('Resize fit=cover', function () { }); describe('Attention strategy', function () { - it('JPEG', function (done) { + it('JPEG', function (_t, done) { sharp(fixtures.inputJpg) .resize(80, 320, { fit: 'cover', @@ -383,7 +384,7 @@ describe('Resize fit=cover', function () { }); }); - it('PNG', function (done) { + it('PNG', function (_t, done) { sharp(fixtures.inputPngWithTransparency) .resize(320, 80, { fit: 'cover', @@ -403,7 +404,7 @@ describe('Resize fit=cover', function () { }); }); - it('WebP', function (done) { + it('WebP', function (_t, done) { sharp(fixtures.inputWebP) .resize(320, 80, { fit: 'cover', @@ -423,7 +424,7 @@ describe('Resize fit=cover', function () { }); }); - it('supports the strategy passed as a string', function (done) { + it('supports the strategy passed as a string', function (_t, done) { sharp(fixtures.inputPngWithTransparency) .resize(320, 80, { fit: 'cover', diff --git a/test/unit/resize.js b/test/unit/resize.js index b59a049d5..ce59d4d5e 100644 --- a/test/unit/resize.js +++ b/test/unit/resize.js @@ -1,13 +1,14 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); describe('Resize dimensions', function () { - it('Exact crop', function (done) { + it('Exact crop', function (_t, done) { sharp(fixtures.inputJpg).resize(320, 240).toBuffer(function (err, data, info) { if (err) throw err; assert.strictEqual(true, data.length > 0); @@ -18,7 +19,7 @@ describe('Resize dimensions', function () { }); }); - it('Fixed width', function (done) { + it('Fixed width', function (_t, done) { sharp(fixtures.inputJpg).resize(320).toBuffer(function (err, data, info) { if (err) throw err; assert.strictEqual(true, data.length > 0); @@ -29,7 +30,7 @@ describe('Resize dimensions', function () { }); }); - it('Fixed height', function (done) { + it('Fixed height', function (_t, done) { sharp(fixtures.inputJpg).resize(null, 320).toBuffer(function (err, data, info) { if (err) throw err; assert.strictEqual(true, data.length > 0); @@ -40,7 +41,7 @@ describe('Resize dimensions', function () { }); }); - it('Identity transform', function (done) { + it('Identity transform', function (_t, done) { sharp(fixtures.inputJpg).toBuffer(function (err, data, info) { if (err) throw err; assert.strictEqual(true, data.length > 0); @@ -51,7 +52,7 @@ describe('Resize dimensions', function () { }); }); - it('Upscale', function (done) { + it('Upscale', function (_t, done) { sharp(fixtures.inputJpg) .resize(3000) .toBuffer(function (err, data, info) { @@ -100,7 +101,7 @@ describe('Resize dimensions', function () { }, /Expected positive integer for height but received 1.5 of type number/); }); - it('Invalid width - too large', function (done) { + it('Invalid width - too large', function (_t, done) { sharp(fixtures.inputJpg) .resize(0x4000, 1) .webp() @@ -111,7 +112,7 @@ describe('Resize dimensions', function () { }); }); - it('Invalid height - too large', function (done) { + it('Invalid height - too large', function (_t, done) { sharp(fixtures.inputJpg) .resize(1, 0x4000) .webp() @@ -122,7 +123,7 @@ describe('Resize dimensions', function () { }); }); - it('Webp resize then extract large image', function (done) { + it('Webp resize then extract large image', function (_t, done) { sharp(fixtures.inputWebP) .resize(0x4000, 0x4000) .extract({ top: 0x2000, left: 0x2000, width: 256, height: 256 }) @@ -136,7 +137,7 @@ describe('Resize dimensions', function () { }); }); - it('WebP shrink-on-load rounds to zero, ensure recalculation is correct', function (done) { + it('WebP shrink-on-load rounds to zero, ensure recalculation is correct', function (_t, done) { sharp(fixtures.inputJpg) .resize(1080, 607) .webp() @@ -157,7 +158,7 @@ describe('Resize dimensions', function () { }); }); - it('JPEG shrink-on-load with 90 degree rotation, ensure recalculation is correct', function (done) { + it('JPEG shrink-on-load with 90 degree rotation, ensure recalculation is correct', function (_t, done) { sharp(fixtures.inputJpg) .resize(1920, 1280) .toBuffer(function (err, data, info) { @@ -176,7 +177,7 @@ describe('Resize dimensions', function () { }); }); - it('TIFF embed known to cause rounding errors', function (done) { + it('TIFF embed known to cause rounding errors', function (_t, done) { sharp(fixtures.inputTiff) .resize(240, 320, { fit: sharp.fit.contain }) .jpeg() @@ -190,7 +191,7 @@ describe('Resize dimensions', function () { }); }); - it('TIFF known to cause rounding errors', function (done) { + it('TIFF known to cause rounding errors', function (_t, done) { sharp(fixtures.inputTiff) .resize(240, 320) .jpeg() @@ -204,7 +205,7 @@ describe('Resize dimensions', function () { }); }); - it('fit=inside, portrait', function (done) { + it('fit=inside, portrait', function (_t, done) { sharp(fixtures.inputTiff) .resize(320, 320, { fit: sharp.fit.inside }) .jpeg() @@ -218,7 +219,7 @@ describe('Resize dimensions', function () { }); }); - it('fit=outside, portrait', function (done) { + it('fit=outside, portrait', function (_t, done) { sharp(fixtures.inputTiff) .resize(320, 320, { fit: sharp.fit.outside }) .jpeg() @@ -232,7 +233,7 @@ describe('Resize dimensions', function () { }); }); - it('fit=inside, landscape', function (done) { + it('fit=inside, landscape', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 320, { fit: sharp.fit.inside }) .toBuffer(function (err, data, info) { @@ -245,7 +246,7 @@ describe('Resize dimensions', function () { }); }); - it('fit=outside, landscape', function (done) { + it('fit=outside, landscape', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 320, { fit: sharp.fit.outside }) .toBuffer(function (err, data, info) { @@ -258,7 +259,7 @@ describe('Resize dimensions', function () { }); }); - it('fit=inside, provide only one dimension', function (done) { + it('fit=inside, provide only one dimension', function (_t, done) { sharp(fixtures.inputJpg) .resize({ width: 320, @@ -274,7 +275,7 @@ describe('Resize dimensions', function () { }); }); - it('fit=outside, provide only one dimension', function (done) { + it('fit=outside, provide only one dimension', function (_t, done) { sharp(fixtures.inputJpg) .resize({ width: 320, @@ -290,7 +291,7 @@ describe('Resize dimensions', function () { }); }); - it('Do not enlarge when input width is already less than output width', function (done) { + it('Do not enlarge when input width is already less than output width', function (_t, done) { sharp(fixtures.inputJpg) .resize({ width: 2800, @@ -306,7 +307,7 @@ describe('Resize dimensions', function () { }); }); - it('Do not enlarge when input height is already less than output height', function (done) { + it('Do not enlarge when input height is already less than output height', function (_t, done) { sharp(fixtures.inputJpg) .resize({ height: 2300, @@ -322,7 +323,7 @@ describe('Resize dimensions', function () { }); }); - it('Do crop when fit = cover and withoutEnlargement = true and width >= outputWidth, and height < outputHeight', function (done) { + it('Do crop when fit = cover and withoutEnlargement = true and width >= outputWidth, and height < outputHeight', function (_t, done) { sharp(fixtures.inputJpg) .resize({ width: 3000, @@ -339,7 +340,7 @@ describe('Resize dimensions', function () { }); }); - it('Do crop when fit = cover and withoutEnlargement = true and width < outputWidth, and height >= outputHeight', function (done) { + it('Do crop when fit = cover and withoutEnlargement = true and width < outputWidth, and height >= outputHeight', function (_t, done) { sharp(fixtures.inputJpg) .resize({ width: 1500, @@ -356,7 +357,7 @@ describe('Resize dimensions', function () { }); }); - it('Do enlarge when input width is less than output width', function (done) { + it('Do enlarge when input width is less than output width', function (_t, done) { sharp(fixtures.inputJpg) .resize({ width: 2800, @@ -372,7 +373,7 @@ describe('Resize dimensions', function () { }); }); - it('Do enlarge when input width is less than output width', function (done) { + it('Do enlarge when input width is less than output width', function (_t, done) { sharp(fixtures.inputJpg) .resize({ width: 2800, @@ -388,7 +389,7 @@ describe('Resize dimensions', function () { }); }); - it('Do enlarge when input height is less than output height', function (done) { + it('Do enlarge when input height is less than output height', function (_t, done) { sharp(fixtures.inputJpg) .resize({ height: 2300, @@ -404,7 +405,7 @@ describe('Resize dimensions', function () { }); }); - it('Do enlarge when input width is less than output width', function (done) { + it('Do enlarge when input width is less than output width', function (_t, done) { sharp(fixtures.inputJpg) .resize({ width: 2800, @@ -420,7 +421,7 @@ describe('Resize dimensions', function () { }); }); - it('Do not resize when both withoutEnlargement and withoutReduction are true', function (done) { + it('Do not resize when both withoutEnlargement and withoutReduction are true', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 320, { fit: 'fill', withoutEnlargement: true, withoutReduction: true }) .toBuffer(function (err, data, info) { @@ -433,7 +434,7 @@ describe('Resize dimensions', function () { }); }); - it('Do not reduce size when fit = outside and withoutReduction are true and height > outputHeight and width > outputWidth', function (done) { + it('Do not reduce size when fit = outside and withoutReduction are true and height > outputHeight and width > outputWidth', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 320, { fit: 'outside', withoutReduction: true }) .toBuffer(function (err, data, info) { @@ -446,7 +447,7 @@ describe('Resize dimensions', function () { }); }); - it('Do resize when fit = outside and withoutReduction are true and input height > height and input width > width ', function (done) { + it('Do resize when fit = outside and withoutReduction are true and input height > height and input width > width ', function (_t, done) { sharp(fixtures.inputJpg) .resize(3000, 3000, { fit: 'outside', withoutReduction: true }) .toBuffer(function (err, data, info) { @@ -459,7 +460,7 @@ describe('Resize dimensions', function () { }); }); - it('fit=fill, downscale width and height', function (done) { + it('fit=fill, downscale width and height', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 320, { fit: 'fill' }) .toBuffer(function (err, data, info) { @@ -472,7 +473,7 @@ describe('Resize dimensions', function () { }); }); - it('fit=fill, downscale width', function (done) { + it('fit=fill, downscale width', function (_t, done) { sharp(fixtures.inputJpg) .resize({ width: 320, @@ -488,7 +489,7 @@ describe('Resize dimensions', function () { }); }); - it('fit=fill, downscale height', function (done) { + it('fit=fill, downscale height', function (_t, done) { sharp(fixtures.inputJpg) .resize({ height: 320, @@ -504,7 +505,7 @@ describe('Resize dimensions', function () { }); }); - it('fit=fill, upscale width and height', function (done) { + it('fit=fill, upscale width and height', function (_t, done) { sharp(fixtures.inputJpg) .resize(3000, 3000, { fit: 'fill' }) .toBuffer(function (err, data, info) { @@ -517,7 +518,7 @@ describe('Resize dimensions', function () { }); }); - it('fit=fill, upscale width', function (done) { + it('fit=fill, upscale width', function (_t, done) { sharp(fixtures.inputJpg) .resize(3000, null, { fit: 'fill' }) .toBuffer(function (err, data, info) { @@ -530,7 +531,7 @@ describe('Resize dimensions', function () { }); }); - it('fit=fill, upscale height', function (done) { + it('fit=fill, upscale height', function (_t, done) { sharp(fixtures.inputJpg) .resize(null, 3000, { fit: 'fill' }) .toBuffer(function (err, data, info) { @@ -543,7 +544,7 @@ describe('Resize dimensions', function () { }); }); - it('fit=fill, downscale width, upscale height', function (done) { + it('fit=fill, downscale width, upscale height', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 3000, { fit: 'fill' }) .toBuffer(function (err, data, info) { @@ -556,7 +557,7 @@ describe('Resize dimensions', function () { }); }); - it('fit=fill, upscale width, downscale height', function (done) { + it('fit=fill, upscale width, downscale height', function (_t, done) { sharp(fixtures.inputJpg) .resize(3000, 320, { fit: 'fill' }) .toBuffer(function (err, data, info) { @@ -569,7 +570,7 @@ describe('Resize dimensions', function () { }); }); - it('fit=fill, identity transform', function (done) { + it('fit=fill, identity transform', function (_t, done) { sharp(fixtures.inputJpg) .resize(null, null, { fit: 'fill' }) .toBuffer(function (err, data, info) { @@ -582,7 +583,7 @@ describe('Resize dimensions', function () { }); }); - it('Dimensions that result in differing even shrinks on each axis', function (done) { + it('Dimensions that result in differing even shrinks on each axis', function (_t, done) { sharp(fixtures.inputJpg) .resize(645, 399) .toBuffer(function (err, data, info) { @@ -600,7 +601,7 @@ describe('Resize dimensions', function () { }); }); - it('Dimensions that result in differing odd shrinks on each axis', function (done) { + it('Dimensions that result in differing odd shrinks on each axis', function (_t, done) { return sharp(fixtures.inputJpg) .resize(600, 399) .toBuffer(function (err, data, info) { @@ -622,7 +623,7 @@ describe('Resize dimensions', function () { true, false ].forEach(function (value) { - it(`fastShrinkOnLoad: ${value} does not causes image shifts`, function (done) { + it(`fastShrinkOnLoad: ${value} does not causes image shifts`, function (_t, done) { sharp(fixtures.inputJpgCenteredImage) .resize(9, 8, { fastShrinkOnLoad: value }) .png() @@ -642,7 +643,7 @@ describe('Resize dimensions', function () { sharp.kernel.lanczos2, sharp.kernel.lanczos3 ].forEach(function (kernel) { - it(`kernel ${kernel}`, function (done) { + it(`kernel ${kernel}`, function (_t, done) { sharp(fixtures.inputJpg) .resize(320, null, { kernel }) .toBuffer(function (err, data, info) { @@ -654,7 +655,7 @@ describe('Resize dimensions', function () { }); }); - it('nearest upsampling with integral factor', function (done) { + it('nearest upsampling with integral factor', function (_t, done) { sharp(fixtures.inputTiff8BitDepth) .resize(210, 210, { kernel: 'nearest' }) .png() diff --git a/test/unit/rotate.js b/test/unit/rotate.js index 25303ce87..6d8422c4f 100644 --- a/test/unit/rotate.js +++ b/test/unit/rotate.js @@ -1,6 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); @@ -15,7 +16,7 @@ describe('Rotation', function () { [1, 2, 3, 4, 5, 6, 7, 8].forEach(function (exifTag) { const input = fixtures[`inputJpgWith${orientation}Exif${exifTag}`]; const expectedOutput = fixtures.expected(`${orientation}_${exifTag}-out.jpg`); - it(`${orientation} image with EXIF Orientation ${exifTag}: Auto-rotate`, function (done) { + it(`${orientation} image with EXIF Orientation ${exifTag}: Auto-rotate`, function (_t, done) { const [expectedWidth, expectedHeight] = orientation === 'Landscape' ? [600, 450] : [450, 600]; const img = sharp(input, options); @@ -29,7 +30,7 @@ describe('Rotation', function () { }); }); - it(`${orientation} image with EXIF Orientation ${exifTag}: Auto-rotate then resize`, function (done) { + it(`${orientation} image with EXIF Orientation ${exifTag}: Auto-rotate then resize`, function (_t, done) { const [expectedWidth, expectedHeight] = orientation === 'Landscape' ? [320, 240] : [320, 427]; const img = sharp(input, options); @@ -45,7 +46,7 @@ describe('Rotation', function () { }); if (rotateMethod !== 'constructor') { - it(`${orientation} image with EXIF Orientation ${exifTag}: Resize then auto-rotate`, function (done) { + it(`${orientation} image with EXIF Orientation ${exifTag}: Resize then auto-rotate`, function (_t, done) { const [expectedWidth, expectedHeight] = orientation === 'Landscape' ? (exifTag < 5) ? [320, 240] : [320, 240] : [320, 427]; @@ -67,7 +68,7 @@ describe('Rotation', function () { [90, 180, 270, 45].forEach(function (angle) { const [inputWidth, inputHeight] = orientation === 'Landscape' ? [600, 450] : [450, 600]; const expectedOutput = fixtures.expected(`${orientation}_${exifTag}_rotate${angle}-out.jpg`); - it(`${orientation} image with EXIF Orientation ${exifTag}: Auto-rotate then rotate ${angle} ${doResize ? 'and resize' : ''}`, function (done) { + it(`${orientation} image with EXIF Orientation ${exifTag}: Auto-rotate then rotate ${angle} ${doResize ? 'and resize' : ''}`, function (_t, done) { const [width, height] = (angle === 45 ? [742, 742] : [inputWidth, inputHeight]).map((x) => doResize ? Math.floor(x / 1.875) : x); const [expectedWidth, expectedHeight] = angle % 180 === 0 ? [width, height] : [height, width]; @@ -90,7 +91,7 @@ describe('Rotation', function () { const [inputWidth, inputHeight] = orientation === 'Landscape' ? [600, 450] : [450, 600]; const flipFlopFileName = [flip && 'flip', flop && 'flop'].filter(Boolean).join('_'); const flipFlopTestName = [flip && 'flip', flop && 'flop'].filter(Boolean).join(' & '); - it(`${orientation} image with EXIF Orientation ${exifTag}: Auto-rotate then ${flipFlopTestName} ${doResize ? 'and resize' : ''}`, function (done) { + it(`${orientation} image with EXIF Orientation ${exifTag}: Auto-rotate then ${flipFlopTestName} ${doResize ? 'and resize' : ''}`, function (_t, done) { const expectedOutput = fixtures.expected(`${orientation}_${exifTag}_${flipFlopFileName}-out.jpg`); const img = sharp(input, options); @@ -115,7 +116,7 @@ describe('Rotation', function () { }); }); - it('Rotate by 30 degrees with semi-transparent background', function (done) { + it('Rotate by 30 degrees with semi-transparent background', function (_t, done) { sharp(fixtures.inputJpg) .resize(320) .rotate(30, { background: { r: 255, g: 0, b: 0, alpha: 0.5 } }) @@ -129,7 +130,7 @@ describe('Rotation', function () { }); }); - it('Rotate by 30 degrees with solid background', function (done) { + it('Rotate by 30 degrees with solid background', function (_t, done) { sharp(fixtures.inputJpg) .resize(320) .rotate(30, { background: { r: 255, g: 0, b: 0 } }) @@ -142,7 +143,7 @@ describe('Rotation', function () { }); }); - it('Rotate by 90 degrees, respecting output input size', function (done) { + it('Rotate by 90 degrees, respecting output input size', function (_t, done) { sharp(fixtures.inputJpg) .rotate(90) .resize(320, 240) @@ -156,7 +157,7 @@ describe('Rotation', function () { }); }); - it('Resize then rotate by 30 degrees, respecting output input size', function (done) { + it('Resize then rotate by 30 degrees, respecting output input size', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .rotate(30) @@ -171,7 +172,7 @@ describe('Rotation', function () { }); [-3690, -450, -90, 90, 450, 3690].forEach(function (angle) { - it(`Rotate by any 90-multiple angle (${angle}deg)`, function (done) { + it(`Rotate by any 90-multiple angle (${angle}deg)`, function (_t, done) { sharp(fixtures.inputJpg320x240).rotate(angle).toBuffer(function (err, _data, info) { if (err) throw err; assert.strictEqual(240, info.width); @@ -182,7 +183,7 @@ describe('Rotation', function () { }); [-3750, -510, -150, 30, 390, 3630].forEach(function (angle) { - it(`Rotate by any 30-multiple angle (${angle}deg)`, function (done) { + it(`Rotate by any 30-multiple angle (${angle}deg)`, function (_t, done) { sharp(fixtures.inputJpg320x240).rotate(angle).toBuffer(function (err, _data, info) { if (err) throw err; assert.strictEqual(397, info.width); @@ -193,7 +194,7 @@ describe('Rotation', function () { }); [-3780, -540, 0, 180, 540, 3780].forEach(function (angle) { - it(`Rotate by any 180-multiple angle (${angle}deg)`, function (done) { + it(`Rotate by any 180-multiple angle (${angle}deg)`, function (_t, done) { sharp(fixtures.inputJpg320x240).rotate(angle).toBuffer(function (err, _data, info) { if (err) throw err; assert.strictEqual(320, info.width); @@ -203,7 +204,7 @@ describe('Rotation', function () { }); }); - it('Rotate by 270 degrees, square output ignoring aspect ratio', function (done) { + it('Rotate by 270 degrees, square output ignoring aspect ratio', function (_t, done) { sharp(fixtures.inputJpg) .resize(240, 240, { fit: sharp.fit.fill }) .rotate(270) @@ -220,7 +221,7 @@ describe('Rotation', function () { }); }); - it('Rotate by 315 degrees, square output ignoring aspect ratio', function (done) { + it('Rotate by 315 degrees, square output ignoring aspect ratio', function (_t, done) { sharp(fixtures.inputJpg) .resize(240, 240, { fit: sharp.fit.fill }) .rotate(315) @@ -237,7 +238,7 @@ describe('Rotation', function () { }); }); - it('Rotate by 270 degrees, rectangular output ignoring aspect ratio', function (done) { + it('Rotate by 270 degrees, rectangular output ignoring aspect ratio', function (_t, done) { sharp(fixtures.inputJpg) .rotate(270) .resize(320, 240, { fit: sharp.fit.fill }) @@ -254,7 +255,7 @@ describe('Rotation', function () { }); }); - it('Auto-rotate by 270 degrees, rectangular output ignoring aspect ratio', function (done) { + it('Auto-rotate by 270 degrees, rectangular output ignoring aspect ratio', function (_t, done) { sharp(fixtures.inputJpgWithLandscapeExif8) .resize(320, 240, { fit: sharp.fit.fill }) .rotate() @@ -271,7 +272,7 @@ describe('Rotation', function () { }); }); - it('Rotate by 30 degrees, rectangular output ignoring aspect ratio', function (done) { + it('Rotate by 30 degrees, rectangular output ignoring aspect ratio', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240, { fit: sharp.fit.fill }) .rotate(30) @@ -288,7 +289,7 @@ describe('Rotation', function () { }); }); - it('Input image has Orientation EXIF tag but do not rotate output', function (done) { + it('Input image has Orientation EXIF tag but do not rotate output', function (_t, done) { sharp(fixtures.inputJpgWithExif) .resize(320) .withMetadata() @@ -306,7 +307,7 @@ describe('Rotation', function () { }); }); - it('Input image has Orientation EXIF tag value of 8 (270 degrees), auto-rotate', function (done) { + it('Input image has Orientation EXIF tag value of 8 (270 degrees), auto-rotate', function (_t, done) { sharp(fixtures.inputJpgWithExif) .rotate() .resize(320) @@ -319,7 +320,7 @@ describe('Rotation', function () { }); }); - it('Override EXIF Orientation tag metadata after auto-rotate', function (done) { + it('Override EXIF Orientation tag metadata after auto-rotate', function (_t, done) { sharp(fixtures.inputJpgWithExif) .rotate() .resize(320) @@ -337,7 +338,7 @@ describe('Rotation', function () { }); }); - it('Input image has Orientation EXIF tag value of 5 (270 degrees + flip), auto-rotate', function (done) { + it('Input image has Orientation EXIF tag value of 5 (270 degrees + flip), auto-rotate', function (_t, done) { sharp(fixtures.inputJpgWithExifMirroring) .rotate() .resize(320) @@ -355,7 +356,7 @@ describe('Rotation', function () { }); }); - it('Attempt to auto-rotate using image that has no EXIF', function (done) { + it('Attempt to auto-rotate using image that has no EXIF', function (_t, done) { sharp(fixtures.inputJpg).rotate().resize(320).toBuffer(function (err, data, info) { if (err) throw err; assert.strictEqual(true, data.length > 0); @@ -366,7 +367,7 @@ describe('Rotation', function () { }); }); - it('Attempt to auto-rotate image format without EXIF support', function (done) { + it('Attempt to auto-rotate image format without EXIF support', function (_t, done) { sharp(fixtures.inputPng) .rotate() .resize(320) @@ -440,7 +441,7 @@ describe('Rotation', function () { assert.strictEqual(warningMessage, 'ignoring previous rotate options'); }); - it('Multiple rotate: last one wins (cardinal)', function (done) { + it('Multiple rotate: last one wins (cardinal)', function (_t, done) { sharp(fixtures.inputJpg) .rotate(45) .rotate(90) @@ -452,7 +453,7 @@ describe('Rotation', function () { }); }); - it('Multiple rotate: last one wins (non cardinal)', function (done) { + it('Multiple rotate: last one wins (non cardinal)', function (_t, done) { sharp(fixtures.inputJpg) .rotate(90) .rotate(45) @@ -464,7 +465,7 @@ describe('Rotation', function () { }); }); - it('Flip - vertical', function (done) { + it('Flip - vertical', function (_t, done) { sharp(fixtures.inputJpg) .resize(320) .flip() @@ -482,7 +483,7 @@ describe('Rotation', function () { }); }); - it('Flop - horizontal', function (done) { + it('Flop - horizontal', function (_t, done) { sharp(fixtures.inputJpg) .resize(320) .flop() @@ -500,7 +501,7 @@ describe('Rotation', function () { }); }); - it('Flip and flop', function (done) { + it('Flip and flop', function (_t, done) { sharp(fixtures.inputJpg) .resize(320) .flip() @@ -514,7 +515,7 @@ describe('Rotation', function () { }); }); - it('Neither flip nor flop', function (done) { + it('Neither flip nor flop', function (_t, done) { sharp(fixtures.inputJpg) .resize(320) .flip(false) @@ -528,7 +529,7 @@ describe('Rotation', function () { }); }); - it('Auto-rotate and flip', function (done) { + it('Auto-rotate and flip', function (_t, done) { sharp(fixtures.inputJpgWithExif) .rotate() .flip() @@ -542,7 +543,7 @@ describe('Rotation', function () { }); }); - it('Auto-rotate and flop', function (done) { + it('Auto-rotate and flop', function (_t, done) { sharp(fixtures.inputJpgWithExif) .rotate() .flop() diff --git a/test/unit/sharpen.js b/test/unit/sharpen.js index 78b6f98fc..28b3db547 100644 --- a/test/unit/sharpen.js +++ b/test/unit/sharpen.js @@ -1,13 +1,14 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); describe('Sharpen', function () { - it('specific radius 10 (sigma 6)', function (done) { + it('specific radius 10 (sigma 6)', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .sharpen(6) @@ -20,7 +21,7 @@ describe('Sharpen', function () { }); }); - it('specific radius 3 (sigma 1.5) and levels 0.5, 2.5', function (done) { + it('specific radius 3 (sigma 1.5) and levels 0.5, 2.5', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .sharpen(1.5, 0.5, 2.5) @@ -33,7 +34,7 @@ describe('Sharpen', function () { }); }); - it('specific radius 5 (sigma 3.5) and levels 2, 4', function (done) { + it('specific radius 5 (sigma 3.5) and levels 2, 4', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .sharpen(3.5, 2, 4) @@ -46,7 +47,7 @@ describe('Sharpen', function () { }); }); - it('sigma=3.5, m1=2, m2=4', (done) => { + it('sigma=3.5, m1=2, m2=4', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .sharpen({ sigma: 3.5, m1: 2, m2: 4 }) @@ -54,7 +55,7 @@ describe('Sharpen', function () { .then(data => fixtures.assertSimilar(fixtures.expected('sharpen-5-2-4.jpg'), data, done)); }); - it('sigma=3.5, m1=2, m2=4, x1=2, y2=5, y3=25', (done) => { + it('sigma=3.5, m1=2, m2=4, x1=2, y2=5, y3=25', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .sharpen({ sigma: 3.5, m1: 2, m2: 4, x1: 2, y2: 5, y3: 25 }) @@ -63,7 +64,7 @@ describe('Sharpen', function () { }); if (!process.env.SHARP_TEST_WITHOUT_CACHE) { - it('specific radius/levels with alpha channel', function (done) { + it('specific radius/levels with alpha channel', function (_t, done) { sharp(fixtures.inputPngWithTransparency) .resize(320, 240) .sharpen(5, 4, 8) @@ -78,7 +79,7 @@ describe('Sharpen', function () { }); } - it('mild sharpen', function (done) { + it('mild sharpen', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .sharpen() @@ -139,7 +140,7 @@ describe('Sharpen', function () { /Expected number between 0 and 1000000 for options\.y3 but received -1 of type number/ )); - it('sharpened image is larger than non-sharpened', function (done) { + it('sharpened image is larger than non-sharpened', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .sharpen(false) diff --git a/test/unit/stats.js b/test/unit/stats.js index 9f3a73dac..89102cd65 100644 --- a/test/unit/stats.js +++ b/test/unit/stats.js @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 const fs = require('node:fs'); +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); @@ -20,7 +21,7 @@ function isInteger (val) { } describe('Image Stats', function () { - it('JPEG', function (done) { + it('JPEG', function (_t, done) { sharp(fixtures.inputJpg).stats(function (err, stats) { if (err) throw err; @@ -85,7 +86,7 @@ describe('Image Stats', function () { }); }); - it('PNG without transparency', function (done) { + it('PNG without transparency', function (_t, done) { sharp(fixtures.inputPng).stats(function (err, stats) { if (err) throw err; @@ -117,7 +118,7 @@ describe('Image Stats', function () { }); }); - it('PNG with transparency', function (done) { + it('PNG with transparency', function (_t, done) { sharp(fixtures.inputPngWithTransparency).stats(function (err, stats) { if (err) throw err; @@ -198,7 +199,7 @@ describe('Image Stats', function () { }); }); - it('PNG fully transparent', function (done) { + it('PNG fully transparent', function (_t, done) { sharp(fixtures.inputPngCompleteTransparency).stats(function (err, stats) { if (err) throw err; @@ -231,7 +232,7 @@ describe('Image Stats', function () { }); }); - it('Tiff', function (done) { + it('Tiff', function (_t, done) { sharp(fixtures.inputTiff).stats(function (err, stats) { if (err) throw err; @@ -264,7 +265,7 @@ describe('Image Stats', function () { }); }); - it('WebP', function (done) { + it('WebP', function (_t, done) { sharp(fixtures.inputWebP).stats(function (err, stats) { if (err) throw err; @@ -329,7 +330,7 @@ describe('Image Stats', function () { }); }); - it('GIF', function (done) { + it('GIF', function (_t, done) { sharp(fixtures.inputGif).stats(function (err, stats) { if (err) throw err; @@ -394,7 +395,7 @@ describe('Image Stats', function () { }); }); - it('Grayscale GIF with alpha', function (done) { + it('Grayscale GIF with alpha', function (_t, done) { sharp(fixtures.inputGifGreyPlusAlpha).stats(function (err, stats) { if (err) throw err; @@ -476,7 +477,7 @@ describe('Image Stats', function () { assert.strictEqual(sharpness, 0); }); - it('Stream in, Callback out', function (done) { + it('Stream in, Callback out', function (_t, done) { const readable = fs.createReadStream(fixtures.inputJpg); const pipeline = sharp().stats(function (err, stats) { if (err) throw err; @@ -685,7 +686,7 @@ describe('Image Stats', function () { }); }); - it('File input with corrupt header fails gracefully', function (done) { + it('File input with corrupt header fails gracefully', function (_t, done) { sharp(fixtures.inputJpgWithCorruptHeader) .stats(function (err) { assert(err.message.includes('Input file has corrupt header')); @@ -695,7 +696,7 @@ describe('Image Stats', function () { }); }); - it('Stream input with corrupt header fails gracefully', function (done) { + it('Stream input with corrupt header fails gracefully', function (_t, done) { fs.createReadStream(fixtures.inputJpgWithCorruptHeader).pipe( sharp() .stats(function (err) { @@ -729,7 +730,7 @@ describe('Image Stats', function () { }); }); - it('Buffer input with corrupt header fails gracefully', function (done) { + it('Buffer input with corrupt header fails gracefully', function (_t, done) { sharp(fs.readFileSync(fixtures.inputJpgWithCorruptHeader)) .stats(function (err) { assert.strictEqual(true, !!err); @@ -737,7 +738,7 @@ describe('Image Stats', function () { }); }); - it('Non-existent file in, Promise out', function (done) { + it('Non-existent file in, Promise out', function (_t, done) { sharp('fail').stats().then(function () { throw new Error('Non-existent file'); }, function (err) { diff --git a/test/unit/svg.js b/test/unit/svg.js index f79f3efae..a12932ac5 100644 --- a/test/unit/svg.js +++ b/test/unit/svg.js @@ -2,13 +2,14 @@ // SPDX-License-Identifier: Apache-2.0 const fs = require('node:fs'); +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); describe('SVG input', function () { - it('Convert SVG to PNG at default 72DPI', function (done) { + it('Convert SVG to PNG at default 72DPI', function (_t, done) { sharp(fixtures.inputSvg) .resize(1024) .extract({ left: 290, top: 760, width: 40, height: 40 }) @@ -29,7 +30,7 @@ describe('SVG input', function () { }); }); - it('Convert SVG to PNG at 1200DPI', function (done) { + it('Convert SVG to PNG at 1200DPI', function (_t, done) { sharp(fixtures.inputSvg, { density: 1200 }) .resize(1024) .extract({ left: 290, top: 760, width: 40, height: 40 }) @@ -50,7 +51,7 @@ describe('SVG input', function () { }); }); - it('Convert SVG to PNG at DPI larger than 2400', function (done) { + it('Convert SVG to PNG at DPI larger than 2400', function (_t, done) { const size = 1024; sharp(fixtures.inputSvgSmallViewBox).metadata(function (err, metadata) { if (err) throw err; @@ -75,7 +76,7 @@ describe('SVG input', function () { }); }); - it('Convert SVG to PNG utilizing scale-on-load', function (done) { + it('Convert SVG to PNG utilizing scale-on-load', function (_t, done) { const size = 1024; sharp(fixtures.inputSvgSmallViewBox) .resize(size) @@ -96,7 +97,7 @@ describe('SVG input', function () { }); }); - it('Convert SVG to PNG at 14.4DPI', function (done) { + it('Convert SVG to PNG at 14.4DPI', function (_t, done) { sharp(fixtures.inputSvg, { density: 14.4 }) .toFormat('png') .toBuffer(function (err, data, info) { @@ -111,7 +112,7 @@ describe('SVG input', function () { }); }); - it('Convert SVG with embedded images to PNG, respecting dimensions, autoconvert to PNG', function (done) { + it('Convert SVG with embedded images to PNG, respecting dimensions, autoconvert to PNG', function (_t, done) { sharp(fixtures.inputSvgWithEmbeddedImages) .toBuffer(function (err, data, info) { if (err) throw err; diff --git a/test/unit/text.js b/test/unit/text.js index 258859976..3e5c0a92a 100644 --- a/test/unit/text.js +++ b/test/unit/text.js @@ -1,6 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); @@ -8,9 +9,7 @@ const fixtures = require('../fixtures'); const { inRange } = require('../../lib/is'); describe('Text to image', function () { - this.retries(3); - - it('text with default values', async function () { + it('text with default values', async function (t) { const output = fixtures.path('output.text-default.png'); const text = sharp({ text: { @@ -18,7 +17,7 @@ describe('Text to image', function () { } }); if (!sharp.versions.pango) { - return this.skip(); + return t.skip(); } const info = await text.png().toFile(output); assert.strictEqual('png', info.format); @@ -40,7 +39,7 @@ describe('Text to image', function () { assert.ok(info.textAutofitDpi > 0); }); - it('text with width and height', function (done) { + it('text with width and height', function (t, done) { const output = fixtures.path('output.text-width-height.png'); const text = sharp({ text: { @@ -50,7 +49,7 @@ describe('Text to image', function () { } }); if (!sharp.versions.pango) { - return this.skip(); + return t.skip(); } text.toFile(output, function (err, info) { if (err) throw err; @@ -63,7 +62,7 @@ describe('Text to image', function () { }); }); - it('text with dpi', function (done) { + it('text with dpi', function (t, done) { const output = fixtures.path('output.text-dpi.png'); const dpi = 300; const text = sharp({ @@ -73,7 +72,7 @@ describe('Text to image', function () { } }); if (!sharp.versions.pango) { - return this.skip(); + return t.skip(); } text.toFile(output, function (err, info) { if (err) throw err; @@ -86,7 +85,7 @@ describe('Text to image', function () { }); }); - it('text with color and pango markup', function (done) { + it('text with color and pango markup', function (t, done) { const output = fixtures.path('output.text-color-pango.png'); const dpi = 300; const text = sharp({ @@ -97,7 +96,7 @@ describe('Text to image', function () { } }); if (!sharp.versions.pango) { - return this.skip(); + return t.skip(); } text.toFile(output, function (err, info) { if (err) throw err; @@ -113,7 +112,7 @@ describe('Text to image', function () { }); }); - it('text with font', function (done) { + it('text with font', function (t, done) { const output = fixtures.path('output.text-with-font.png'); const text = sharp({ text: { @@ -122,7 +121,7 @@ describe('Text to image', function () { } }); if (!sharp.versions.pango) { - return this.skip(); + return t.skip(); } text.toFile(output, function (err, info) { if (err) throw err; @@ -134,7 +133,7 @@ describe('Text to image', function () { }); }); - it('text with justify and composite', function (done) { + it('text with justify and composite', function (t, done) { const output = fixtures.path('output.text-composite.png'); const width = 500; const dpi = 300; @@ -166,7 +165,7 @@ describe('Text to image', function () { top: 250 }]); if (!sharp.versions.pango) { - return this.skip(); + return t.skip(); } text.toFile(output, function (err, info) { if (err) throw err; diff --git a/test/unit/threshold.js b/test/unit/threshold.js index acd8add28..350bf0b46 100644 --- a/test/unit/threshold.js +++ b/test/unit/threshold.js @@ -1,13 +1,14 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); describe('Threshold', function () { - it('threshold 1 jpeg', function (done) { + it('threshold 1 jpeg', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .threshold(1) @@ -20,7 +21,7 @@ describe('Threshold', function () { }); }); - it('threshold 40 jpeg', function (done) { + it('threshold 40 jpeg', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .threshold(40) @@ -33,7 +34,7 @@ describe('Threshold', function () { }); }); - it('threshold 128', function (done) { + it('threshold 128', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .threshold(128) @@ -46,7 +47,7 @@ describe('Threshold', function () { }); }); - it('threshold true (=128)', function (done) { + it('threshold true (=128)', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .threshold(true) @@ -59,7 +60,7 @@ describe('Threshold', function () { }); }); - it('threshold false (=0)', function (done) { + it('threshold false (=0)', function (_t, done) { sharp(fixtures.inputJpg) .threshold(false) .toBuffer(function (err, data) { @@ -68,7 +69,7 @@ describe('Threshold', function () { }); }); - it('threshold grayscale: true (=128)', function (done) { + it('threshold grayscale: true (=128)', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .threshold(128, { grayscale: true }) @@ -81,7 +82,7 @@ describe('Threshold', function () { }); }); - it('threshold default jpeg', function (done) { + it('threshold default jpeg', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .threshold() @@ -94,7 +95,7 @@ describe('Threshold', function () { }); }); - it('threshold default png transparency', function (done) { + it('threshold default png transparency', function (_t, done) { sharp(fixtures.inputPngWithTransparency) .resize(320, 240) .threshold() @@ -107,7 +108,7 @@ describe('Threshold', function () { }); }); - it('threshold default png alpha', function (done) { + it('threshold default png alpha', function (_t, done) { sharp(fixtures.inputPngWithGreyAlpha) .resize(320, 240) .threshold() @@ -120,7 +121,7 @@ describe('Threshold', function () { }); }); - it('threshold default webp transparency', function (done) { + it('threshold default webp transparency', function (_t, done) { sharp(fixtures.inputWebPWithTransparency) .threshold() .toBuffer(function (err, data, info) { @@ -130,7 +131,7 @@ describe('Threshold', function () { }); }); - it('color threshold', function (done) { + it('color threshold', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .threshold(128, { grayscale: false }) diff --git a/test/unit/tiff.js b/test/unit/tiff.js index d4243aa50..8113d5a16 100644 --- a/test/unit/tiff.js +++ b/test/unit/tiff.js @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 const fs = require('node:fs'); +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); @@ -10,7 +11,7 @@ const fixtures = require('../fixtures'); const outputTiff = fixtures.path('output.tiff'); describe('TIFF', function () { - it('Load TIFF from Buffer', function (done) { + it('Load TIFF from Buffer', function (_t, done) { const inputTiffBuffer = fs.readFileSync(fixtures.inputTiff); sharp(inputTiffBuffer) .resize(320, 240) @@ -26,7 +27,7 @@ describe('TIFF', function () { }); }); - it('Load multi-page TIFF from file', function (done) { + it('Load multi-page TIFF from file', function (_t, done) { sharp(fixtures.inputTiffMultipage) // defaults to page 0 .jpeg() .toBuffer(function (err, defaultData, defaultInfo) { @@ -49,7 +50,7 @@ describe('TIFF', function () { }); }); - it('Load multi-page TIFF from Buffer', function (done) { + it('Load multi-page TIFF from Buffer', function (_t, done) { const inputTiffBuffer = fs.readFileSync(fixtures.inputTiffMultipage); sharp(inputTiffBuffer) // defaults to page 0 .jpeg() @@ -73,7 +74,7 @@ describe('TIFF', function () { }); }); - it('Save TIFF to Buffer', function (done) { + it('Save TIFF to Buffer', function (_t, done) { sharp(fixtures.inputTiff) .resize(320, 240) .toBuffer(function (err, data, info) { @@ -114,7 +115,7 @@ describe('TIFF', function () { }); }); - it('Not squashing TIFF to a bit depth of 1 should not change the file size', function (done) { + it('Not squashing TIFF to a bit depth of 1 should not change the file size', function (_t, done) { const startSize = fs.statSync(fixtures.inputTiff8BitDepth).size; sharp(fixtures.inputTiff8BitDepth) .toColourspace('b-w') // can only squash 1 band uchar images @@ -131,7 +132,7 @@ describe('TIFF', function () { }); }); - it('Squashing TIFF to a bit depth of 1 should significantly reduce file size', function (done) { + it('Squashing TIFF to a bit depth of 1 should significantly reduce file size', function (_t, done) { const startSize = fs.statSync(fixtures.inputTiff8BitDepth).size; sharp(fixtures.inputTiff8BitDepth) .toColourspace('b-w') // can only squash 1 band uchar images @@ -219,7 +220,7 @@ describe('TIFF', function () { }); }); - it('TIFF lzw compression with horizontal predictor shrinks test file', function (done) { + it('TIFF lzw compression with horizontal predictor shrinks test file', function (_t, done) { const startSize = fs.statSync(fixtures.inputTiffUncompressed).size; sharp(fixtures.inputTiffUncompressed) .tiff({ @@ -271,7 +272,7 @@ describe('TIFF', function () { }) ); - it('TIFF ccittfax4 compression shrinks b-w test file', function (done) { + it('TIFF ccittfax4 compression shrinks b-w test file', function (_t, done) { const startSize = fs.statSync(fixtures.inputTiff).size; sharp(fixtures.inputTiff) .toColourspace('b-w') @@ -311,7 +312,7 @@ describe('TIFF', function () { assert.strictEqual(resolutionUnit, 'cm'); }); - it('TIFF deflate compression with horizontal predictor shrinks test file', function (done) { + it('TIFF deflate compression with horizontal predictor shrinks test file', function (_t, done) { const startSize = fs.statSync(fixtures.inputTiffUncompressed).size; sharp(fixtures.inputTiffUncompressed) .tiff({ @@ -326,7 +327,7 @@ describe('TIFF', function () { }); }); - it('TIFF deflate compression with float predictor shrinks test file', function (done) { + it('TIFF deflate compression with float predictor shrinks test file', function (_t, done) { const startSize = fs.statSync(fixtures.inputTiffUncompressed).size; sharp(fixtures.inputTiffUncompressed) .tiff({ @@ -341,7 +342,7 @@ describe('TIFF', function () { }); }); - it('TIFF deflate compression without predictor shrinks test file', function (done) { + it('TIFF deflate compression without predictor shrinks test file', function (_t, done) { const startSize = fs.statSync(fixtures.inputTiffUncompressed).size; sharp(fixtures.inputTiffUncompressed) .tiff({ @@ -356,7 +357,7 @@ describe('TIFF', function () { }); }); - it('TIFF jpeg compression shrinks test file', function (done) { + it('TIFF jpeg compression shrinks test file', function (_t, done) { const startSize = fs.statSync(fixtures.inputTiffUncompressed).size; sharp(fixtures.inputTiffUncompressed) .tiff({ @@ -430,7 +431,7 @@ describe('TIFF', function () { }); }); - it('TIFF tiled pyramid image without compression enlarges test file', function (done) { + it('TIFF tiled pyramid image without compression enlarges test file', function (_t, done) { const startSize = fs.statSync(fixtures.inputTiffUncompressed).size; sharp(fixtures.inputTiffUncompressed) .tiff({ @@ -520,7 +521,7 @@ describe('TIFF', function () { }); }); - it('TIFF file input with invalid page fails gracefully', function (done) { + it('TIFF file input with invalid page fails gracefully', function (_t, done) { sharp(fixtures.inputTiffMultipage, { page: 2 }) .toBuffer(function (err) { assert.strictEqual(true, !!err); @@ -528,7 +529,7 @@ describe('TIFF', function () { }); }); - it('TIFF buffer input with invalid page fails gracefully', function (done) { + it('TIFF buffer input with invalid page fails gracefully', function (_t, done) { sharp(fs.readFileSync(fixtures.inputTiffMultipage), { page: 2 }) .toBuffer(function (err) { assert.strictEqual(true, !!err); diff --git a/test/unit/tile.js b/test/unit/tile.js index 90381f667..e496dba7c 100644 --- a/test/unit/tile.js +++ b/test/unit/tile.js @@ -3,6 +3,7 @@ const fs = require('node:fs'); const path = require('node:path'); +const { describe, it } = require('node:test'); const assert = require('node:assert'); const extractZip = require('extract-zip'); @@ -329,7 +330,7 @@ describe('Tile', function () { }); if (sharp.format.dz.output.file) { - it('Deep Zoom layout', function (done) { + it('Deep Zoom layout', function (_t, done) { const directory = fixtures.path('output.dzi_files'); fs.rm(directory, { recursive: true }, function () { sharp(fixtures.inputJpg) @@ -345,7 +346,7 @@ describe('Tile', function () { }); }); - it('Deep Zoom layout with custom size+overlap', function (done) { + it('Deep Zoom layout with custom size+overlap', function (_t, done) { const directory = fixtures.path('output.512.dzi_files'); fs.rm(directory, { recursive: true }, function () { sharp(fixtures.inputJpg) @@ -367,7 +368,7 @@ describe('Tile', function () { }); }); - it('Deep Zoom layout with custom size+angle', function (done) { + it('Deep Zoom layout with custom size+angle', function (_t, done) { const directory = fixtures.path('output.512_90.dzi_files'); fs.rm(directory, { recursive: true }, function () { sharp(fixtures.inputJpg) @@ -401,7 +402,7 @@ describe('Tile', function () { }); }); - it('Deep Zoom layout with depth of one', function (done) { + it('Deep Zoom layout with depth of one', function (_t, done) { const directory = fixtures.path('output.512_depth_one.dzi_files'); fs.rm(directory, { recursive: true }, function () { sharp(fixtures.inputJpg) @@ -417,7 +418,7 @@ describe('Tile', function () { }); }); - it('Deep Zoom layout with depth of onepixel', function (done) { + it('Deep Zoom layout with depth of onepixel', function (_t, done) { const directory = fixtures.path('output.512_depth_onepixel.dzi_files'); fs.rm(directory, { recursive: true }, function () { sharp(fixtures.inputJpg) @@ -433,7 +434,7 @@ describe('Tile', function () { }); }); - it('Deep Zoom layout with depth of onetile', function (done) { + it('Deep Zoom layout with depth of onetile', function (_t, done) { const directory = fixtures.path('output.256_depth_onetile.dzi_files'); fs.rm(directory, { recursive: true }, function () { sharp(fixtures.inputJpg) @@ -449,7 +450,7 @@ describe('Tile', function () { }); }); - it('Deep Zoom layout with skipBlanks', function (done) { + it('Deep Zoom layout with skipBlanks', function (_t, done) { const directory = fixtures.path('output.256_skip_blanks.dzi_files'); fs.rm(directory, { recursive: true }, function () { sharp(fixtures.inputJpgOverlayLayer2) @@ -468,7 +469,7 @@ describe('Tile', function () { }); }); - it('Zoomify layout', function (done) { + it('Zoomify layout', function (_t, done) { const directory = fixtures.path('output.zoomify.dzi'); fs.rm(directory, { recursive: true }, function () { sharp(fixtures.inputJpg) @@ -492,7 +493,7 @@ describe('Tile', function () { }); }); - it('Zoomify layout with depth one', function (done) { + it('Zoomify layout with depth one', function (_t, done) { const directory = fixtures.path('output.zoomify.depth_one.dzi'); fs.rm(directory, { recursive: true }, function () { sharp(fixtures.inputJpg) @@ -513,7 +514,7 @@ describe('Tile', function () { }); }); - it('Zoomify layout with depth onetile', function (done) { + it('Zoomify layout with depth onetile', function (_t, done) { const directory = fixtures.path('output.zoomify.depth_onetile.dzi'); fs.rm(directory, { recursive: true }, function () { sharp(fixtures.inputJpg) @@ -534,7 +535,7 @@ describe('Tile', function () { }); }); - it('Zoomify layout with depth onepixel', function (done) { + it('Zoomify layout with depth onepixel', function (_t, done) { const directory = fixtures.path('output.zoomify.depth_onepixel.dzi'); fs.rm(directory, { recursive: true }, function () { sharp(fixtures.inputJpg) @@ -555,7 +556,7 @@ describe('Tile', function () { }); }); - it('Zoomify layout with skip blanks', function (done) { + it('Zoomify layout with skip blanks', function (_t, done) { const directory = fixtures.path('output.zoomify.skipBlanks.dzi'); fs.rm(directory, { recursive: true }, function () { sharp(fixtures.inputJpgOverlayLayer2) @@ -579,7 +580,7 @@ describe('Tile', function () { }); }); - it('Google layout', function (done) { + it('Google layout', function (_t, done) { const directory = fixtures.path('output.google.dzi'); fs.rm(directory, { recursive: true }, function () { sharp(fixtures.inputJpg) @@ -603,7 +604,7 @@ describe('Tile', function () { }); }); - it('Google layout with jpeg format', function (done) { + it('Google layout with jpeg format', function (_t, done) { const directory = fixtures.path('output.jpg.google.dzi'); fs.rm(directory, { recursive: true }, function () { sharp(fixtures.inputJpg) @@ -640,7 +641,7 @@ describe('Tile', function () { }); }); - it('Google layout with png format', function (done) { + it('Google layout with png format', function (_t, done) { const directory = fixtures.path('output.png.google.dzi'); fs.rm(directory, { recursive: true }, function () { sharp(fixtures.inputJpg) @@ -677,7 +678,7 @@ describe('Tile', function () { }); }); - it('Google layout with webp format', function (done) { + it('Google layout with webp format', function (_t, done) { const directory = fixtures.path('output.webp.google.dzi'); fs.rm(directory, { recursive: true }, function () { sharp(fixtures.inputJpg) @@ -715,7 +716,7 @@ describe('Tile', function () { }); }); - it('Google layout with depth one', function (done) { + it('Google layout with depth one', function (_t, done) { const directory = fixtures.path('output.google_depth_one.dzi'); fs.rm(directory, { recursive: true }, function () { sharp(fixtures.inputJpg) @@ -736,7 +737,7 @@ describe('Tile', function () { }); }); - it('Google layout with depth onetile', function (done) { + it('Google layout with depth onetile', function (_t, done) { const directory = fixtures.path('output.google_depth_onetile.dzi'); fs.rm(directory, { recursive: true }, function () { sharp(fixtures.inputJpg) @@ -757,7 +758,7 @@ describe('Tile', function () { }); }); - it('Google layout with default skip Blanks', function (done) { + it('Google layout with default skip Blanks', function (_t, done) { const directory = fixtures.path('output.google_depth_skipBlanks.dzi'); fs.rm(directory, { recursive: true }, function () { sharp(fixtures.inputPng) @@ -781,7 +782,7 @@ describe('Tile', function () { }); }); - it('Google layout with center image in tile', function (done) { + it('Google layout with center image in tile', function (_t, done) { const directory = fixtures.path('output.google_center.dzi'); fs.rm(directory, { recursive: true }, function () { sharp(fixtures.inputJpg) @@ -801,7 +802,7 @@ describe('Tile', function () { }); }); - it('Google layout with center image in tile centre', function (done) { + it('Google layout with center image in tile centre', function (_t, done) { const directory = fixtures.path('output.google_center.dzi'); fs.rm(directory, { recursive: true }, function () { sharp(fixtures.inputJpg) @@ -821,7 +822,7 @@ describe('Tile', function () { }); }); - it('IIIFv2 layout', function (done) { + it('IIIFv2 layout', function (_t, done) { const name = 'output.iiif.info'; const directory = fixtures.path(name); fs.rm(directory, { recursive: true }, function () { @@ -851,7 +852,7 @@ describe('Tile', function () { }); }); - it('IIIFv3 layout', function (done) { + it('IIIFv3 layout', function (_t, done) { const name = 'output.iiif3.info'; const directory = fixtures.path(name); fs.rm(directory, { recursive: true }, function () { @@ -882,7 +883,7 @@ describe('Tile', function () { }); }); - it('Write to ZIP container using file extension', function (done) { + it('Write to ZIP container using file extension', function (_t, done) { const container = fixtures.path('output.dz.container.zip'); const extractTo = fixtures.path('output.dz.container'); const directory = path.join(extractTo, 'output.dz.container_files'); @@ -903,13 +904,13 @@ describe('Tile', function () { .then(() => { assertDeepZoomTiles(directory, 256, 13, done); }) - .catch(done); + .catch(_t, done); }); }); }); }); - it('Write to ZIP container using container tile option', function (done) { + it('Write to ZIP container using container tile option', function (_t, done) { const container = fixtures.path('output.dz.containeropt.zip'); const extractTo = fixtures.path('output.dz.containeropt'); const directory = path.join(extractTo, 'output.dz.containeropt_files'); @@ -934,13 +935,13 @@ describe('Tile', function () { .then(() => { assertDeepZoomTiles(directory, 256, 13, done); }) - .catch(done); + .catch(_t, done); }); }); }); }); - it('Write ZIP container to Buffer', function (done) { + it('Write ZIP container to Buffer', function (_t, done) { const container = fixtures.path('output.dz.tiles.zip'); const extractTo = fixtures.path('output.dz.tiles'); const directory = path.join(extractTo, 'output.dz.tiles_files'); @@ -963,7 +964,7 @@ describe('Tile', function () { .then(() => { assertDeepZoomTiles(directory, 256, 13, done); }) - .catch(done); + .catch(_t, done); }); }); }); diff --git a/test/unit/timeout.js b/test/unit/timeout.js index 21782917b..ed2012acd 100644 --- a/test/unit/timeout.js +++ b/test/unit/timeout.js @@ -1,6 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); diff --git a/test/unit/tint.js b/test/unit/tint.js index 93cf17778..1e2ccf524 100644 --- a/test/unit/tint.js +++ b/test/unit/tint.js @@ -1,6 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); @@ -10,7 +11,7 @@ const fixtures = require('../fixtures'); const maxDistance = 6; describe('Tint', function () { - it('tints rgb image red', function (done) { + it('tints rgb image red', function (_t, done) { const output = fixtures.path('output.tint-red.jpg'); sharp(fixtures.inputJpg) .resize(320, 240) @@ -23,7 +24,7 @@ describe('Tint', function () { }); }); - it('tints rgb image green', function (done) { + it('tints rgb image green', function (_t, done) { const output = fixtures.path('output.tint-green.jpg'); sharp(fixtures.inputJpg) .resize(320, 240) @@ -36,7 +37,7 @@ describe('Tint', function () { }); }); - it('tints rgb image blue', function (done) { + it('tints rgb image blue', function (_t, done) { const output = fixtures.path('output.tint-blue.jpg'); sharp(fixtures.inputJpg) .resize(320, 240) @@ -49,7 +50,7 @@ describe('Tint', function () { }); }); - it('tints rgb image with sepia tone', function (done) { + it('tints rgb image with sepia tone', function (_t, done) { const output = fixtures.path('output.tint-sepia-hex.jpg'); sharp(fixtures.inputJpg) .resize(320, 240) @@ -63,7 +64,7 @@ describe('Tint', function () { }); }); - it('tints rgb image with sepia tone with rgb colour', function (done) { + it('tints rgb image with sepia tone with rgb colour', function (_t, done) { const output = fixtures.path('output.tint-sepia-rgb.jpg'); sharp(fixtures.inputJpg) .resize(320, 240) @@ -77,7 +78,7 @@ describe('Tint', function () { }); }); - it('tints rgb image with alpha channel', function (done) { + it('tints rgb image with alpha channel', function (_t, done) { const output = fixtures.path('output.tint-alpha.png'); sharp(fixtures.inputPngRGBWithAlpha) .resize(320, 240) @@ -91,7 +92,7 @@ describe('Tint', function () { }); }); - it('tints cmyk image red', function (done) { + it('tints cmyk image red', function (_t, done) { const output = fixtures.path('output.tint-cmyk.jpg'); sharp(fixtures.inputJpgWithCmykProfile) .resize(320, 240) diff --git a/test/unit/toBuffer.js b/test/unit/toBuffer.js index 163f284bc..40b2b0044 100644 --- a/test/unit/toBuffer.js +++ b/test/unit/toBuffer.js @@ -1,6 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); diff --git a/test/unit/toFormat.js b/test/unit/toFormat.js index 089a797e3..1d28efeaf 100644 --- a/test/unit/toFormat.js +++ b/test/unit/toFormat.js @@ -1,6 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/trim.js b/test/unit/trim.js index 6261a8667..b6b95e853 100644 --- a/test/unit/trim.js +++ b/test/unit/trim.js @@ -1,6 +1,7 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); @@ -8,7 +9,7 @@ const inRange = require('../../lib/is').inRange; const fixtures = require('../fixtures'); describe('Trim borders', function () { - it('Skip shrink-on-load', function (done) { + it('Skip shrink-on-load', function (_t, done) { const expected = fixtures.expected('alpha-layer-2-trim-resize.jpg'); sharp(fixtures.inputJpgOverlayLayer2) .trim() @@ -41,7 +42,7 @@ describe('Trim borders', function () { }) ); - it('16-bit PNG with alpha channel', function (done) { + it('16-bit PNG with alpha channel', function (_t, done) { sharp(fixtures.inputPngWithTransparency16bit) .resize(32, 32) .trim({ @@ -60,7 +61,7 @@ describe('Trim borders', function () { }); }); - it('Attempt to trim 2x2 pixel image fails', function (done) { + it('Attempt to trim 2x2 pixel image fails', function (_t, done) { sharp({ create: { width: 2, @@ -78,7 +79,7 @@ describe('Trim borders', function () { assert.strictEqual('Image to trim must be at least 3x3 pixels', err.message); done(); }) - .catch(done); + .catch(_t, done); }); it('Should rotate before trim', () => diff --git a/test/unit/unflatten.js b/test/unit/unflatten.js index b7941cf5b..1759353a9 100644 --- a/test/unit/unflatten.js +++ b/test/unit/unflatten.js @@ -1,25 +1,26 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const sharp = require('../../'); const fixtures = require('../fixtures'); describe('Unflatten', function () { - it('unflatten white background', function (done) { + it('unflatten white background', function (_t, done) { sharp(fixtures.inputPng).unflatten() .toBuffer(function (err, data) { if (err) throw err; fixtures.assertSimilar(fixtures.expected('unflatten-white-transparent.png'), data, { threshold: 0 }, done); }); }); - it('unflatten transparent image', function (done) { + it('unflatten transparent image', function (_t, done) { sharp(fixtures.inputPngTrimSpecificColourIncludeAlpha).unflatten() .toBuffer(function (err, data) { if (err) throw err; fixtures.assertSimilar(fixtures.expected('unflatten-flag-white-transparent.png'), data, { threshold: 0 }, done); }); }); - it('unflatten using threshold', function (done) { + it('unflatten using threshold', function (_t, done) { sharp(fixtures.inputPngPalette).unflatten().threshold(128, { grayscale: false }) .toBuffer(function (err, data) { if (err) throw err; diff --git a/test/unit/util.js b/test/unit/util.js index e29109cac..db74405c9 100644 --- a/test/unit/util.js +++ b/test/unit/util.js @@ -1,13 +1,14 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +const { describe, it } = require('node:test'); const assert = require('node:assert'); const semver = require('semver'); const sharp = require('../../'); describe('Utilities', function () { describe('Cache', function () { - it('Can be disabled', function (done) { + it('Can be disabled', function (_t, done) { const check = setInterval(() => { const cache = sharp.cache(false); const empty = @@ -75,7 +76,7 @@ describe('Utilities', function () { }); describe('Counters', function () { - it('Have zero value at rest', (done) => { + it('Have zero value at rest', (_t, done) => { queueMicrotask(() => { const counters = sharp.counters(); assert.strictEqual(0, counters.queue); diff --git a/test/unit/webp.js b/test/unit/webp.js index 32f45f4e1..e3d51cca0 100644 --- a/test/unit/webp.js +++ b/test/unit/webp.js @@ -2,13 +2,14 @@ // SPDX-License-Identifier: Apache-2.0 const fs = require('node:fs'); +const { describe, it } = require('node:test'); const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); describe('WebP', function () { - it('WebP output', function (done) { + it('WebP output', function (_t, done) { sharp(fixtures.inputJpg) .resize(320, 240) .toFormat(sharp.format.webp) @@ -34,7 +35,7 @@ describe('WebP', function () { }); }); - it('should work for webp alpha quality', function (done) { + it('should work for webp alpha quality', function (_t, done) { sharp(fixtures.inputPngAlphaPremultiplicationSmall) .webp({ alphaQuality: 80, effort: 0 }) .toBuffer(function (err, data, info) { @@ -45,7 +46,7 @@ describe('WebP', function () { }); }); - it('should work for webp lossless', function (done) { + it('should work for webp lossless', function (_t, done) { sharp(fixtures.inputPngAlphaPremultiplicationSmall) .webp({ lossless: true, effort: 0 }) .toBuffer(function (err, data, info) { @@ -56,7 +57,7 @@ describe('WebP', function () { }); }); - it('should work for webp near-lossless', function (done) { + it('should work for webp near-lossless', function (_t, done) { sharp(fixtures.inputPngAlphaPremultiplicationSmall) .webp({ nearLossless: true, quality: 50, effort: 0 }) .toBuffer(function (err50, data50, info50) { @@ -67,7 +68,7 @@ describe('WebP', function () { }); }); - it('should use near-lossless when both lossless and nearLossless are specified', function (done) { + it('should use near-lossless when both lossless and nearLossless are specified', function (_t, done) { sharp(fixtures.inputPngAlphaPremultiplicationSmall) .webp({ nearLossless: true, quality: 50, lossless: true, effort: 0 }) .toBuffer(function (err50, data50, info50) { @@ -269,7 +270,7 @@ describe('WebP', function () { assert.deepStrictEqual(updated.delay, [120, 120, 90, 120, 120, 90, 120, 90, 30]); }); - it('should work with streams when only animated is set', function (done) { + it('should work with streams when only animated is set', function (_t, done) { fs.createReadStream(fixtures.inputWebPAnimated) .pipe(sharp({ animated: true })) .webp({ lossless: true, effort: 0 }) @@ -281,7 +282,7 @@ describe('WebP', function () { }); }); - it('should work with streams when only pages is set', function (done) { + it('should work with streams when only pages is set', function (_t, done) { fs.createReadStream(fixtures.inputWebPAnimated) .pipe(sharp({ pages: -1 })) .webp({ lossless: true, effort: 0 }) From adb6275ae9a2d94a8b7a7e9c7921e83d9fd97ba1 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Sun, 21 Sep 2025 12:11:00 +0100 Subject: [PATCH 090/115] Remove licensing checker/linter This tool appears to no longer be maintained, but more importantly there are far fewer production dependencies now than when first introduced, and all are known/trusted. --- .github/workflows/ci.yml | 1 - package.json | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 25fb7c2d3..b6e49aa75 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,6 @@ jobs: - run: npm install --ignore-scripts - run: npm run lint-cpp - run: npm run lint-js - - run: npm run lint-licensing - run: npm run lint-types build-native: permissions: diff --git a/package.json b/package.json index 115e3c4f8..571744405 100644 --- a/package.json +++ b/package.json @@ -95,10 +95,9 @@ "install": "node install/check.js", "clean": "rm -rf src/build/ .nyc_output/ coverage/ test/fixtures/output.*", "test": "npm run lint && npm run test-unit", - "lint": "npm run lint-cpp && npm run lint-js && npm run lint-licensing && npm run lint-types", + "lint": "npm run lint-cpp && npm run lint-js && npm run lint-types", "lint-cpp": "cpplint", "lint-js": "biome lint", - "lint-licensing": "license-checker --production --summary --onlyAllow=\"Apache-2.0;BSD;ISC;LGPL-3.0-or-later;MIT\"", "lint-types": "tsd --files ./test/types/sharp.test-d.ts", "test-leak": "./test/leak/leak.sh", "test-unit": "node --experimental-test-coverage test/unit.mjs", @@ -182,7 +181,6 @@ "extract-zip": "^2.0.1", "icc": "^3.0.0", "jsdoc-to-markdown": "^9.1.2", - "license-checker": "^25.0.1", "node-addon-api": "^8.5.0", "node-gyp": "^11.4.2", "tar-fs": "^3.1.1", From 54722dd582f87223c23144d0542271499f987b5e Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Mon, 22 Sep 2025 14:59:52 +0100 Subject: [PATCH 091/115] Modernise C++ linter using new @cpplint/cli tooling --- package.json | 4 ++-- src/CPPLINT.cfg | 10 ++++++++++ src/common.cc | 12 +++++++----- src/common.h | 5 +++-- src/metadata.cc | 8 +++++--- src/metadata.h | 1 + src/operations.cc | 4 ++-- src/operations.h | 1 + src/pipeline.cc | 8 ++++---- src/pipeline.h | 2 +- src/sharp.cc | 12 ++++++------ src/stats.cc | 7 ++++--- src/stats.h | 3 ++- src/utilities.cc | 8 ++++---- 14 files changed, 52 insertions(+), 33 deletions(-) create mode 100644 src/CPPLINT.cfg diff --git a/package.json b/package.json index 571744405..af1378d2b 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "clean": "rm -rf src/build/ .nyc_output/ coverage/ test/fixtures/output.*", "test": "npm run lint && npm run test-unit", "lint": "npm run lint-cpp && npm run lint-js && npm run lint-types", - "lint-cpp": "cpplint", + "lint-cpp": "cpplint --quiet src/*.h src/*.cc", "lint-js": "biome lint", "lint-types": "tsd --files ./test/types/sharp.test-d.ts", "test-leak": "./test/leak/leak.sh", @@ -168,6 +168,7 @@ }, "devDependencies": { "@biomejs/biome": "^2.2.4", + "@cpplint/cli": "^0.1.0", "@emnapi/runtime": "^1.5.0", "@img/sharp-libvips-dev": "1.2.3", "@img/sharp-libvips-dev-wasm32": "1.2.3", @@ -175,7 +176,6 @@ "@img/sharp-libvips-win32-ia32": "1.2.3", "@img/sharp-libvips-win32-x64": "1.2.3", "@types/node": "*", - "cc": "^3.0.1", "emnapi": "^1.5.0", "exif-reader": "^2.0.2", "extract-zip": "^2.0.1", diff --git a/src/CPPLINT.cfg b/src/CPPLINT.cfg new file mode 100644 index 000000000..7a643b075 --- /dev/null +++ b/src/CPPLINT.cfg @@ -0,0 +1,10 @@ +set noparent + +linelength=120 + +filter=-build/include +filter=+build/include_alpha +filter=+build/include_subdir +filter=+build/include_what_you_use + +filter=-whitespace/indent_namespace diff --git a/src/common.cc b/src/common.cc index e4ce73209..5c517fc9e 100644 --- a/src/common.cc +++ b/src/common.cc @@ -1,18 +1,20 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +#include #include +#include +#include +#include #include -#include +#include +#include #include -#include -#include -#include // NOLINT(build/c++11) #include #include -#include "common.h" +#include "./common.h" using vips::VImage; diff --git a/src/common.h b/src/common.h index 2bba5e1c1..10b4e5490 100644 --- a/src/common.h +++ b/src/common.h @@ -4,10 +4,11 @@ #ifndef SRC_COMMON_H_ #define SRC_COMMON_H_ +#include #include #include +#include #include -#include #include #include @@ -30,7 +31,7 @@ using vips::VImage; namespace sharp { - struct InputDescriptor { // NOLINT(runtime/indentation_namespace) + struct InputDescriptor { std::string name; std::string file; bool autoOrient; diff --git a/src/metadata.cc b/src/metadata.cc index 788b71298..db582ca0d 100644 --- a/src/metadata.cc +++ b/src/metadata.cc @@ -1,15 +1,17 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +#include #include +#include +#include #include -#include #include #include -#include "common.h" -#include "metadata.h" +#include "./common.h" +#include "./metadata.h" static void* readPNGComment(VipsImage *image, const char *field, GValue *value, void *p); diff --git a/src/metadata.h b/src/metadata.h index f93dd516e..64b5b9053 100644 --- a/src/metadata.h +++ b/src/metadata.h @@ -5,6 +5,7 @@ #define SRC_METADATA_H_ #include +#include #include #include "./common.h" diff --git a/src/operations.cc b/src/operations.cc index ba3a05138..f60c99747 100644 --- a/src/operations.cc +++ b/src/operations.cc @@ -8,8 +8,8 @@ #include #include -#include "common.h" -#include "operations.h" +#include "./common.h" +#include "./operations.h" using vips::VImage; using vips::VError; diff --git a/src/operations.h b/src/operations.h index 22ff46fcf..6582459ce 100644 --- a/src/operations.h +++ b/src/operations.h @@ -8,6 +8,7 @@ #include #include #include +#include #include using vips::VImage; diff --git a/src/pipeline.cc b/src/pipeline.cc index e2dd1182a..4a470b5ad 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -3,7 +3,7 @@ #include #include -#include +#include // NOLINT(build/c++17) #include #include #include @@ -17,9 +17,9 @@ #include #include -#include "common.h" -#include "operations.h" -#include "pipeline.h" +#include "./common.h" +#include "./operations.h" +#include "./pipeline.h" class PipelineWorker : public Napi::AsyncWorker { public: diff --git a/src/pipeline.h b/src/pipeline.h index 8edfff58b..9fb89bdcd 100644 --- a/src/pipeline.h +++ b/src/pipeline.h @@ -6,8 +6,8 @@ #include #include -#include #include +#include #include #include diff --git a/src/sharp.cc b/src/sharp.cc index ed54c501a..ab873e807 100644 --- a/src/sharp.cc +++ b/src/sharp.cc @@ -1,16 +1,16 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 -#include // NOLINT(build/c++11) +#include #include #include -#include "common.h" -#include "metadata.h" -#include "pipeline.h" -#include "utilities.h" -#include "stats.h" +#include "./common.h" +#include "./metadata.h" +#include "./pipeline.h" +#include "./stats.h" +#include "./utilities.h" Napi::Object init(Napi::Env env, Napi::Object exports) { static std::once_flag sharp_vips_init_once; diff --git a/src/stats.cc b/src/stats.cc index bc9b243cc..cd5f4a385 100644 --- a/src/stats.cc +++ b/src/stats.cc @@ -1,15 +1,16 @@ // Copyright 2013 Lovell Fuller and others. // SPDX-License-Identifier: Apache-2.0 +#include #include +#include #include -#include #include #include -#include "common.h" -#include "stats.h" +#include "./common.h" +#include "./stats.h" class StatsWorker : public Napi::AsyncWorker { public: diff --git a/src/stats.h b/src/stats.h index c80e65fa8..9f99d8e9d 100644 --- a/src/stats.h +++ b/src/stats.h @@ -5,6 +5,7 @@ #define SRC_STATS_H_ #include +#include #include #include "./common.h" @@ -24,7 +25,7 @@ struct ChannelStats { ChannelStats(int minVal, int maxVal, double sumVal, double squaresSumVal, double meanVal, double stdevVal, int minXVal, int minYVal, int maxXVal, int maxYVal): - min(minVal), max(maxVal), sum(sumVal), squaresSum(squaresSumVal), + min(minVal), max(maxVal), sum(sumVal), squaresSum(squaresSumVal), // NOLINT(build/include_what_you_use) mean(meanVal), stdev(stdevVal), minX(minXVal), minY(minYVal), maxX(maxXVal), maxY(maxYVal) {} }; diff --git a/src/utilities.cc b/src/utilities.cc index 1f78cdd84..2922ed46e 100644 --- a/src/utilities.cc +++ b/src/utilities.cc @@ -2,16 +2,16 @@ // SPDX-License-Identifier: Apache-2.0 #include -#include #include +#include #include #include #include -#include "common.h" -#include "operations.h" -#include "utilities.h" +#include "./common.h" +#include "./operations.h" +#include "./utilities.h" /* Get and set cache limits From 6b922b30d59e85d0ac04c7b899a8129e3675dcf9 Mon Sep 17 00:00:00 2001 From: throwbi Date: Tue, 30 Sep 2025 10:41:02 +0200 Subject: [PATCH 092/115] Add support for BigTIFF output (#4459) --- docs/src/content/docs/api-output.md | 1 + lib/constructor.js | 1 + lib/index.d.ts | 2 ++ lib/output.js | 5 +++++ src/pipeline.cc | 3 +++ src/pipeline.h | 2 ++ test/unit/tiff.js | 12 ++++++++++++ 7 files changed, 26 insertions(+) diff --git a/docs/src/content/docs/api-output.md b/docs/src/content/docs/api-output.md index 7c966fd72..800732a2b 100644 --- a/docs/src/content/docs/api-output.md +++ b/docs/src/content/docs/api-output.md @@ -646,6 +646,7 @@ instead of providing `xres` and `yres` in pixels/mm. | [options.quality] | number | 80 | quality, integer 1-100 | | [options.force] | boolean | true | force TIFF output, otherwise attempt to use input format | | [options.compression] | string | "'jpeg'" | compression options: none, jpeg, deflate, packbits, ccittfax4, lzw, webp, zstd, jp2k | +| [options.bigtiff] | boolean | false | use BigTIFF variant (has no effect when compression is none) | | [options.predictor] | string | "'horizontal'" | compression predictor options: none, horizontal, float | | [options.pyramid] | boolean | false | write an image pyramid | | [options.tile] | boolean | false | write a tiled tiff | diff --git a/lib/constructor.js b/lib/constructor.js index 82acbd08e..488b9f03b 100644 --- a/lib/constructor.js +++ b/lib/constructor.js @@ -352,6 +352,7 @@ const Sharp = function (input, options) { gifProgressive: false, tiffQuality: 80, tiffCompression: 'jpeg', + tiffBigtiff: false, tiffPredictor: 'horizontal', tiffPyramid: false, tiffMiniswhite: false, diff --git a/lib/index.d.ts b/lib/index.d.ts index 83e010d80..ed99ecf8c 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1460,6 +1460,8 @@ declare namespace sharp { quality?: number | undefined; /** Compression options: none, jpeg, deflate, packbits, ccittfax4, lzw, webp, zstd, jp2k (optional, default 'jpeg') */ compression?: string | undefined; + /** Use BigTIFF variant (has no effect when compression is none) (optional, default false) */ + bigtiff?: boolean | undefined; /** Compression predictor options: none, horizontal, float (optional, default 'horizontal') */ predictor?: string | undefined; /** Write an image pyramid (optional, default false) */ diff --git a/lib/output.js b/lib/output.js index 1178d6259..8718c6983 100644 --- a/lib/output.js +++ b/lib/output.js @@ -974,6 +974,7 @@ function trySetAnimationOptions (source, target) { * @param {number} [options.quality=80] - quality, integer 1-100 * @param {boolean} [options.force=true] - force TIFF output, otherwise attempt to use input format * @param {string} [options.compression='jpeg'] - compression options: none, jpeg, deflate, packbits, ccittfax4, lzw, webp, zstd, jp2k + * @param {boolean} [options.bigtiff=false] - use BigTIFF variant (has no effect when compression is none) * @param {string} [options.predictor='horizontal'] - compression predictor options: none, horizontal, float * @param {boolean} [options.pyramid=false] - write an image pyramid * @param {boolean} [options.tile=false] - write a tiled tiff @@ -1052,6 +1053,10 @@ function tiff (options) { throw is.invalidParameterError('compression', 'one of: none, jpeg, deflate, packbits, ccittfax4, lzw, webp, zstd, jp2k', options.compression); } } + // bigtiff + if (is.defined(options.bigtiff)) { + this._setBooleanOption('tiffBigtiff', options.bigtiff); + } // predictor if (is.defined(options.predictor)) { if (is.string(options.predictor) && is.inArray(options.predictor, ['none', 'horizontal', 'float'])) { diff --git a/src/pipeline.cc b/src/pipeline.cc index 4a470b5ad..2b952fc91 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -1009,6 +1009,7 @@ class PipelineWorker : public Napi::AsyncWorker { ->set("Q", baton->tiffQuality) ->set("bitdepth", baton->tiffBitdepth) ->set("compression", baton->tiffCompression) + ->set("bigtiff", baton->tiffBigtiff) ->set("miniswhite", baton->tiffMiniswhite) ->set("predictor", baton->tiffPredictor) ->set("pyramid", baton->tiffPyramid) @@ -1211,6 +1212,7 @@ class PipelineWorker : public Napi::AsyncWorker { ->set("Q", baton->tiffQuality) ->set("bitdepth", baton->tiffBitdepth) ->set("compression", baton->tiffCompression) + ->set("bigtiff", baton->tiffBigtiff) ->set("miniswhite", baton->tiffMiniswhite) ->set("predictor", baton->tiffPredictor) ->set("pyramid", baton->tiffPyramid) @@ -1750,6 +1752,7 @@ Napi::Value pipeline(const Napi::CallbackInfo& info) { baton->gifReuse = sharp::AttrAsBool(options, "gifReuse"); baton->gifProgressive = sharp::AttrAsBool(options, "gifProgressive"); baton->tiffQuality = sharp::AttrAsUint32(options, "tiffQuality"); + baton->tiffBigtiff = sharp::AttrAsBool(options, "tiffBigtiff"); baton->tiffPyramid = sharp::AttrAsBool(options, "tiffPyramid"); baton->tiffMiniswhite = sharp::AttrAsBool(options, "tiffMiniswhite"); baton->tiffBitdepth = sharp::AttrAsUint32(options, "tiffBitdepth"); diff --git a/src/pipeline.h b/src/pipeline.h index 9fb89bdcd..eaec71fae 100644 --- a/src/pipeline.h +++ b/src/pipeline.h @@ -175,6 +175,7 @@ struct PipelineBaton { bool gifProgressive; int tiffQuality; VipsForeignTiffCompression tiffCompression; + bool tiffBigtiff; VipsForeignTiffPredictor tiffPredictor; bool tiffPyramid; int tiffBitdepth; @@ -350,6 +351,7 @@ struct PipelineBaton { gifProgressive(false), tiffQuality(80), tiffCompression(VIPS_FOREIGN_TIFF_COMPRESSION_JPEG), + tiffBigtiff(false), tiffPredictor(VIPS_FOREIGN_TIFF_PREDICTOR_HORIZONTAL), tiffPyramid(false), tiffBitdepth(8), diff --git a/test/unit/tiff.js b/test/unit/tiff.js index 8113d5a16..fb0b0e528 100644 --- a/test/unit/tiff.js +++ b/test/unit/tiff.js @@ -401,6 +401,18 @@ describe('TIFF', function () { }); }); + it('TIFF bigtiff true value does not throw error', function () { + assert.doesNotThrow(function () { + sharp().tiff({ bigtiff: true }); + }); + }); + + it('Invalid TIFF bigtiff value throws error', function () { + assert.throws(function () { + sharp().tiff({ bigtiff: 'true' }); + }); + }); + it('TIFF invalid predictor option throws', function () { assert.throws(function () { sharp().tiff({ predictor: 'a' }); From 5e72ad95fa85d26b236690715108ddf3c95a5d65 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Tue, 30 Sep 2025 10:54:00 +0100 Subject: [PATCH 093/115] Docs: changelog entry for #4459 --- docs/src/content/docs/changelog/v0.34.5.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 docs/src/content/docs/changelog/v0.34.5.md diff --git a/docs/src/content/docs/changelog/v0.34.5.md b/docs/src/content/docs/changelog/v0.34.5.md new file mode 100644 index 000000000..bf762f874 --- /dev/null +++ b/docs/src/content/docs/changelog/v0.34.5.md @@ -0,0 +1,8 @@ +--- +title: v0.34.5 - TBD +slug: changelog/v0.34.5 +--- + +* Add support for BigTIFF output. + [#4459](https://github.com/lovell/sharp/pull/4459) + [@throwbi](https://github.com/throwbi) From 2324d75f7fd8f1e222a529bd06e7a5c2c5bd7abe Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Sun, 5 Oct 2025 11:28:58 +0100 Subject: [PATCH 094/115] CI: Upgrade to macOS 15 (Sequoia) --- .github/workflows/ci.yml | 12 ++++++------ .github/workflows/npm.yml | 14 +++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b6e49aa75..3249f3845 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,34 +73,34 @@ jobs: nodejs_version: "^20.3.0" nodejs_version_major: 20 platform: linux-arm64 - - os: macos-13 + - os: macos-15-intel nodejs_arch: x64 nodejs_version: "^18.17.0" nodejs_version_major: 18 platform: darwin-x64 package: true - - os: macos-13 + - os: macos-15-intel nodejs_arch: x64 nodejs_version: "^20.3.0" nodejs_version_major: 20 platform: darwin-x64 - - os: macos-13 + - os: macos-15-intel nodejs_arch: x64 nodejs_version: "^22.9.0" nodejs_version_major: 22 platform: darwin-x64 - - os: macos-14 + - os: macos-15 nodejs_arch: arm64 nodejs_version: "^18.17.0" nodejs_version_major: 18 platform: darwin-arm64 package: true - - os: macos-14 + - os: macos-15 nodejs_arch: arm64 nodejs_version: "^20.3.0" nodejs_version_major: 20 platform: darwin-arm64 - - os: macos-14 + - os: macos-15 nodejs_arch: arm64 nodejs_version: "^22.9.0" nodejs_version_major: 22 diff --git a/.github/workflows/npm.yml b/.github/workflows/npm.yml index 7f0d04bb5..4db44a5b4 100644 --- a/.github/workflows/npm.yml +++ b/.github/workflows/npm.yml @@ -43,30 +43,30 @@ jobs: runtime: bun - name: darwin-x64-node-npm - runs-on: macos-13 + runs-on: macos-15-intel runtime: node package-manager: npm - name: darwin-x64-node-pnpm - runs-on: macos-13 + runs-on: macos-15-intel runtime: node package-manager: pnpm - name: darwin-x64-node-yarn - runs-on: macos-13 + runs-on: macos-15-intel runtime: node package-manager: yarn - name: darwin-x64-node-yarn-pnp - runs-on: macos-13 + runs-on: macos-15-intel runtime: node package-manager: yarn-pnp - name: darwin-x64-node-yarn-v1 - runs-on: macos-13 + runs-on: macos-15-intel runtime: node package-manager: yarn-v1 - name: darwin-x64-deno - runs-on: macos-13 + runs-on: macos-15-intel runtime: deno - name: darwin-x64-bun - runs-on: macos-13 + runs-on: macos-15-intel runtime: bun - name: win32-x64-node-npm From 1bbee519aa33205cee9da8f0ad26b26b08a5a520 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Tue, 7 Oct 2025 14:32:44 +0100 Subject: [PATCH 095/115] Separate build script from install script #4458 The --build-from-source flag is now deprecated and will soon be removed along with the need to define an install script. This will remove a whole category of package manager warnings about install scripts and "built" dependencies. Most people don't need to build sharp from source, but for those that do, a suitable method is now something like: $ npm install package-that-depends-on-sharp $ npm explore sharp -- npm run build --- .cirrus.yml | 7 +++-- .github/CONTRIBUTING.md | 2 +- .github/workflows/ci.yml | 12 +++++--- biome.json | 2 +- docs/src/content/docs/changelog/v0.34.5.md | 3 ++ docs/src/content/docs/install.md | 5 +-- install/build.js | 36 ++++++++++++++++++++++ install/check.js | 33 ++------------------ package.json | 9 +++--- test/bench/Dockerfile | 2 +- 10 files changed, 65 insertions(+), 46 deletions(-) create mode 100644 install/build.js diff --git a/.cirrus.yml b/.cirrus.yml index 0dbadc400..45f9c3df7 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,5 +1,5 @@ freebsd_instance: - image_family: freebsd-15-0-snap + image_family: freebsd-15-0 task: name: FreeBSD @@ -9,9 +9,10 @@ task: prerequisites_script: - pkg update -f - pkg upgrade -y - - pkg install -y devel/git devel/pkgconf graphics/vips www/node20 www/npm + - pkg install -y devel/git devel/pkgconf graphics/vips www/node22 www/npm - pkg-config --modversion vips-cpp install_script: - - npm install --build-from-source + - npm install + - npm run build test_script: - node --test test/unit/io.js diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index eeb6dd191..6239e09a4 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -25,7 +25,7 @@ Please select the `main` branch as the destination for your Pull Request so your Please squash your changes into a single commit using a command like `git rebase -i upstream/main`. -To test C++ changes, you can compile the module using `npm install --build-from-source` and then run the tests using `npm test`. +To test C++ changes, you can compile the module using `npm run build` and then run the tests using `npm test`. ## Submit a Pull Request with a new feature diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3249f3845..0211806d8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -169,7 +169,8 @@ jobs: node-version: ${{ matrix.nodejs_version }} architecture: ${{ matrix.nodejs_arch }} - uses: actions/checkout@v4 - - run: npm install --build-from-source + - run: npm install + - run: npm run build - run: npm run test-unit - if: matrix.package run: npm run package-from-local-build @@ -211,7 +212,8 @@ jobs: - name: Dependencies run: apk add build-base git python3 font-noto --update-cache - uses: actions/checkout@v4 - - run: npm install --build-from-source + - run: npm install + - run: npm run build - run: npm run test-unit - if: matrix.package run: npm run package-from-local-build @@ -265,7 +267,8 @@ jobs: mkdir /opt/nodejs curl --silent https://${{ matrix.nodejs_hostname }}/download/release/v${{ matrix.nodejs_version}}/node-v${{ matrix.nodejs_version}}-linux-${{ matrix.nodejs_arch }}.tar.xz | tar xJC /opt/nodejs --strip-components=1 export PATH=$PATH:/opt/nodejs/bin - npm install --build-from-source + npm install + npm run build node --test test/unit/io.js npm run package-from-local-build - uses: actions/upload-artifact@v4 @@ -289,7 +292,8 @@ jobs: uses: actions/setup-node@v5 with: node-version: "20" - - run: emmake npm install --build-from-source + - run: npm install + - run: emmake npm run build - name: Verify emscripten versions match run: | EMSCRIPTEN_VERSION_LIBVIPS=$(node -p "require('@img/sharp-libvips-dev-wasm32/versions').emscripten") diff --git a/biome.json b/biome.json index 2ed1c1042..12cd1a9b4 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.2.4/schema.json", + "$schema": "https://biomejs.dev/schemas/2.2.5/schema.json", "vcs": { "enabled": true, "clientKind": "git", diff --git a/docs/src/content/docs/changelog/v0.34.5.md b/docs/src/content/docs/changelog/v0.34.5.md index bf762f874..a754c33ad 100644 --- a/docs/src/content/docs/changelog/v0.34.5.md +++ b/docs/src/content/docs/changelog/v0.34.5.md @@ -3,6 +3,9 @@ title: v0.34.5 - TBD slug: changelog/v0.34.5 --- +* Support building from source with npm v12+, deprecate `--build-from-source` flag. + [#4458](https://github.com/lovell/sharp/issues/4458) + * Add support for BigTIFF output. [#4459](https://github.com/lovell/sharp/pull/4459) [@throwbi](https://github.com/throwbi) diff --git a/docs/src/content/docs/install.md b/docs/src/content/docs/install.md index 6e14ab1ca..d74d47a24 100644 --- a/docs/src/content/docs/install.md +++ b/docs/src/content/docs/install.md @@ -111,10 +111,11 @@ and on macOS when running Node.js under Rosetta. ## Building from source -This module will be compiled from source at `npm install` time when: +This module will be compiled from source when: * a globally-installed libvips is detected, or -* when the `npm install --build-from-source` flag is used. +* using `npm explore sharp -- npm run build`, or +* using the deprecated `npm run --build-from-source` at `npm install` time. The logic to detect a globally-installed libvips can be skipped by setting the `SHARP_IGNORE_GLOBAL_LIBVIPS` (never try to use it) or diff --git a/install/build.js b/install/build.js new file mode 100644 index 000000000..6af6541e1 --- /dev/null +++ b/install/build.js @@ -0,0 +1,36 @@ +// Copyright 2013 Lovell Fuller and others. +// SPDX-License-Identifier: Apache-2.0 + +const { + useGlobalLibvips, + globalLibvipsVersion, + log, + spawnRebuild, +} = require('../lib/libvips'); + +log('Attempting to build from source via node-gyp'); +log('See https://sharp.pixelplumbing.com/install#building-from-source'); + +try { + const addonApi = require('node-addon-api'); + log(`Found node-addon-api ${addonApi.version || ''}`); +} catch (_err) { + log('Please add node-addon-api to your dependencies'); + process.exit(1); +} +try { + const gyp = require('node-gyp'); + log(`Found node-gyp ${gyp().version}`); +} catch (_err) { + log('Please add node-gyp to your dependencies'); + process.exit(1); +} + +if (useGlobalLibvips(log)) { + log(`Detected globally-installed libvips v${globalLibvipsVersion()}`); +} + +const status = spawnRebuild(); +if (status !== 0) { + process.exit(status); +} diff --git a/install/check.js b/install/check.js index 8e96da86e..d526e0883 100644 --- a/install/check.js +++ b/install/check.js @@ -2,36 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 try { - const { useGlobalLibvips, globalLibvipsVersion, log, spawnRebuild } = require('../lib/libvips'); - - const buildFromSource = (msg) => { - log(msg); - log('Attempting to build from source via node-gyp'); - try { - const addonApi = require('node-addon-api'); - log(`Found node-addon-api ${addonApi.version || ''}`); - } catch (_err) { - log('Please add node-addon-api to your dependencies'); - return; - } - try { - const gyp = require('node-gyp'); - log(`Found node-gyp ${gyp().version}`); - } catch (_err) { - log('Please add node-gyp to your dependencies'); - return; - } - log('See https://sharp.pixelplumbing.com/install#building-from-source'); - const status = spawnRebuild(); - if (status !== 0) { - process.exit(status); - } - }; - - if (useGlobalLibvips(log)) { - buildFromSource(`Detected globally-installed libvips v${globalLibvipsVersion()}`); - } else if (process.env.npm_config_build_from_source) { - buildFromSource('Detected --build-from-source flag'); + const { useGlobalLibvips } = require('../lib/libvips'); + if (useGlobalLibvips() || process.env.npm_config_build_from_source) { + process.exit(1); } } catch (err) { const summary = err.message.split(/\n/).slice(0, 1); diff --git a/package.json b/package.json index af1378d2b..c15af175f 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,8 @@ "Don Denton " ], "scripts": { - "install": "node install/check.js", + "build": "node install/build.js", + "install": "node install/check.js || npm run build", "clean": "rm -rf src/build/ .nyc_output/ coverage/ test/fixtures/output.*", "test": "npm run lint && npm run test-unit", "lint": "npm run lint-cpp && npm run lint-js && npm run lint-types", @@ -139,7 +140,7 @@ ], "dependencies": { "@img/colour": "^1.0.0", - "detect-libc": "^2.1.0", + "detect-libc": "^2.1.1", "semver": "^7.7.2" }, "optionalDependencies": { @@ -167,7 +168,7 @@ "@img/sharp-win32-x64": "0.34.4" }, "devDependencies": { - "@biomejs/biome": "^2.2.4", + "@biomejs/biome": "^2.2.5", "@cpplint/cli": "^0.1.0", "@emnapi/runtime": "^1.5.0", "@img/sharp-libvips-dev": "1.2.3", @@ -180,7 +181,7 @@ "exif-reader": "^2.0.2", "extract-zip": "^2.0.1", "icc": "^3.0.0", - "jsdoc-to-markdown": "^9.1.2", + "jsdoc-to-markdown": "^9.1.3", "node-addon-api": "^8.5.0", "node-gyp": "^11.4.2", "tar-fs": "^3.1.1", diff --git a/test/bench/Dockerfile b/test/bench/Dockerfile index fc23deab0..290db857a 100644 --- a/test/bench/Dockerfile +++ b/test/bench/Dockerfile @@ -15,7 +15,7 @@ RUN apt-get install -y imagemagick libmagick++-dev graphicsmagick # Install sharp RUN mkdir /tmp/sharp RUN cd /tmp && git clone --single-branch --branch $BRANCH https://github.com/lovell/sharp.git -RUN cd /tmp/sharp && npm install --build-from-source +RUN cd /tmp/sharp && npm install && npm run build # Install benchmark test RUN cd /tmp/sharp/test/bench && npm install --omit optional From b7fda60a85bf2b36d0583fc54db485b9dfbe74eb Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Fri, 17 Oct 2025 14:56:17 +0100 Subject: [PATCH 096/115] Bump deps --- biome.json | 2 +- package.json | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/biome.json b/biome.json index 12cd1a9b4..2a79d5edf 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.2.5/schema.json", + "$schema": "https://biomejs.dev/schemas/2.2.6/schema.json", "vcs": { "enabled": true, "clientKind": "git", diff --git a/package.json b/package.json index c15af175f..0c3caf45a 100644 --- a/package.json +++ b/package.json @@ -140,8 +140,8 @@ ], "dependencies": { "@img/colour": "^1.0.0", - "detect-libc": "^2.1.1", - "semver": "^7.7.2" + "detect-libc": "^2.1.2", + "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.4", @@ -168,7 +168,7 @@ "@img/sharp-win32-x64": "0.34.4" }, "devDependencies": { - "@biomejs/biome": "^2.2.5", + "@biomejs/biome": "^2.2.6", "@cpplint/cli": "^0.1.0", "@emnapi/runtime": "^1.5.0", "@img/sharp-libvips-dev": "1.2.3", @@ -183,7 +183,7 @@ "icc": "^3.0.0", "jsdoc-to-markdown": "^9.1.3", "node-addon-api": "^8.5.0", - "node-gyp": "^11.4.2", + "node-gyp": "^11.5.0", "tar-fs": "^3.1.1", "tsd": "^0.33.0" }, From c1c16ed3e671817dc4780dba0dbdaa59f2fe592b Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Fri, 17 Oct 2025 14:57:38 +0100 Subject: [PATCH 097/115] Improve error messaging when only warnings issued #4465 --- docs/src/content/docs/changelog/v0.34.5.md | 3 +++ src/pipeline.cc | 13 +++++++++++-- src/pipeline.h | 2 ++ test/fixtures/bonne.geo.tif | Bin 0 -> 47034 bytes test/fixtures/index.js | 1 + test/unit/failOn.js | 7 +++++++ 6 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 test/fixtures/bonne.geo.tif diff --git a/docs/src/content/docs/changelog/v0.34.5.md b/docs/src/content/docs/changelog/v0.34.5.md index a754c33ad..886932b8f 100644 --- a/docs/src/content/docs/changelog/v0.34.5.md +++ b/docs/src/content/docs/changelog/v0.34.5.md @@ -9,3 +9,6 @@ slug: changelog/v0.34.5 * Add support for BigTIFF output. [#4459](https://github.com/lovell/sharp/pull/4459) [@throwbi](https://github.com/throwbi) + +* Improve error messaging when only warnings issued. + [#4465](https://github.com/lovell/sharp/issues/4465) diff --git a/src/pipeline.cc b/src/pipeline.cc index 2b952fc91..4a848293d 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -1278,7 +1278,12 @@ class PipelineWorker : public Napi::AsyncWorker { if (what && what[0]) { (baton->err).append(what); } else { - (baton->err).append("Unknown error"); + if (baton->input->failOn == VIPS_FAIL_ON_WARNING) { + (baton->err).append("Warning treated as error due to failOn setting"); + baton->errUseWarning = true; + } else { + (baton->err).append("Unknown error"); + } } } // Clean up libvips' per-request data and threads @@ -1293,7 +1298,11 @@ class PipelineWorker : public Napi::AsyncWorker { // Handle warnings std::string warning = sharp::VipsWarningPop(); while (!warning.empty()) { - debuglog.Call(Receiver().Value(), { Napi::String::New(env, warning) }); + if (baton->errUseWarning) { + (baton->err).append("\n").append(warning); + } else { + debuglog.Call(Receiver().Value(), { Napi::String::New(env, warning) }); + } warning = sharp::VipsWarningPop(); } diff --git a/src/pipeline.h b/src/pipeline.h index eaec71fae..14ee5456e 100644 --- a/src/pipeline.h +++ b/src/pipeline.h @@ -198,6 +198,7 @@ struct PipelineBaton { bool jxlLossless; VipsBandFormat rawDepth; std::string err; + bool errUseWarning; int keepMetadata; int withMetadataOrientation; double withMetadataDensity; @@ -373,6 +374,7 @@ struct PipelineBaton { jxlEffort(7), jxlLossless(false), rawDepth(VIPS_FORMAT_UCHAR), + errUseWarning(false), keepMetadata(0), withMetadataOrientation(-1), withMetadataDensity(0.0), diff --git a/test/fixtures/bonne.geo.tif b/test/fixtures/bonne.geo.tif new file mode 100644 index 0000000000000000000000000000000000000000..1592bf86ce775707683897f6f5176bc35c32ac5b GIT binary patch literal 47034 zcmeIbS*)#Tdf&CHs%`9c$KZ6GVGnDb=Xsv@Je)d1)v38_=uw?^560bT+fC?npr!VO zFF;}tV&)XkJsPc+uLUT@y8wq zr^ey$=l4Fox8?UAeCx$ueedu7p-+GG_|ls^WWmb&wc3m^Uu8y=llfkzi|6pDt`P!&wqyVe~kA$=gx=T zzk7R~D(~OBJ?Dt$2haUjT(isb!`tUmo>xEg*>8XMg}qbW+w$@ty-*hI`u|p_u2QaSC7ZtO10YJviVf1Q0Lrwy%CREwNfq=3gv3G zTCbEVfb@*OPWRcXXIer;3$)_VBP!EL7T!MygIcxMZ&ZelKl}dW$@SwI18p^mnbc7h_BESzsA#sERc>A@ zF`#OtT7xg8LN=4l7xI~0vCXUTOQ9F)mow0A2mz0Zmadmx4!X(w_bYk)hF$0rCG}zr7}p{ zyVcQvR;3`H0XDsp~79u@R<=FW%8+fA$^oeWeeFt zYt$d15JlOa%N24(#9J<8)9v$hFn z@yj%*K&O#NC10pEJHsg?^m_evv(;*$uFXa@pH63s2(6UQ6q?OiA$4$+&KHZ-_OL(U zX32?PhfSo8(y2p~t56@bOL>UTqff}NRApq< zdO2O_PBz<4snn=9n&n)jR$xrc$>+cG^Iv>=^46EG(c{w5VXlC@RJ5QEB&RH)v*y z7)rCjqp z)Oy{~#aF)dbDw_n;LV5a%H33@)|zZO4a~OPggJ#$t&SW3q)t<2t2o6x!pBT9IrI=p zYaNJdcSi$^4F=RR`x#C_r%?J*z18W@cn0QHi^Xz2S1PwUXkrzh5cj;K!UkW20%(W* z>BIedckktUljECR7rW5h%P_Z5sTLcf>sQZ5ox!ltKs`pCdN!LcH+zGAt^3};_|4Cq z_a>dA`{{Be+q`@_z%-gjqmVC410*1s9LNdQ!{~H2lp)PMG2})cOYaWGv+=Ok>2%ty z0wxBp!R7*x(E<)IuQL3^7#KKark#NpT(N{DwlP1fDwEIgsZ16$NgwRryLVU{FU}rb z%$fyo7iFy0TMZ1iar)$B(C)9+{a&|RpA4JzW+&t_Zr^<63pa!G{lg;mQ0PB;?W`#% zaM_Yp+T>Y|dqRYwP+t&6+9Q+A6`O~S5vWgVpX9LJY zOY>L-bn)kKL_iTj1)RiXOaVWVJwj=#lkMrlr;m=?3KO~E^cvM_qdS@QI=%67J{mMK z#qp@w?si*EoI;^ASdWTWS!pz>l_&4MvujjwqUvo0KdIX*1l|A}s#B;G&H;$TFdH50 zW;z}W2Ji1L!=m9M}ekk^+z#ErdG48+PzDEdv0QIFo_oB7-9SXrXW$OaRQs z6B|)9>os%>uFIS;e$oDQNsCvson9QivBW~f;gB}xo}Figrtws*;1>6 zFYW>YZGJ-uW5f(_TR4ddBQ6zNgVA(@T5Hb+I{cjoL1FL@I#77R4df@`AiO|Q$P$nZ zx93+^%O-@PQk}s780q!<{Z^yf%4gtkzTD}S3!M={@p|O|P+T7>Se;y-b!**zr&c89 z7z}%L>=DDxX%!(40=O*nU?I?+$u~M(JRy?qN{e(j&?Jmf9WP zY2y?KGr?;8aGhYTQX5PD8P4Q4e=mEl1P|kc3{rLzFNm(aH-=&=_cIgHrr& z^WXRq=ZQ1Rb$6$mVXZlu%ub1l>Wof07*!#iw@z-(E>HXI>12GIM?0__Y{OB3 zqeTOE3?ZLW-D)-Bf!1)??V<||sst$Ka;18w=f~=Tez}JN5qxNY)pDWAO*{R*!9~9f z;{a;Heb@z*U`x7X0KGpR_i%z-4#P+Y$znw+lwo3MnRFD}$^$BF(doU()F6TKHFOK~Zh=3b}^yzGU zFhuS_2dZAcnT$unNx#$Yl8O-Q9~cuOTiHqg4bN(gZm%uhDm4Ov2z1aS{RZHuc?A3# z|Dd5AB9Vq%t~NS-OtI~4Nmpv4?bYK~9$j8so^KW_himV7HC%Ila*+R3V9+XFOuS`7|lZAxb5-)*uCFZh$5A zcDG$oM4fi1l>$MP#1uUU2#K9b9&m*N!cGx<83#o&(&G}`x0tUEP9DDU+RHDUo}QiV zb_E?o1l|Xkac-mIC)-{P;Kdz@eNe)Hl@%z!=(s_>+mp%VO0(NX54v^2 zt3khiFy$hl0CcK->XG0$PCJTAB({Z&aJRn-j9cVjfXoyrC8h z0m(u~wbN_i2kY%#J0XLZ8-djdi#L-lvm!K6gNS@I4db11u;aOn3 zuKSPCVTi>$g?cN{+PEGY1m{LQ3=GMZ3+3_V6hT{pHCvdC8OMg(c3e1^{Qvr+4hutJm%e~w@24v7uPchJ>Jt$1|r-u**D83Gz2 zQ<(}M;go{(^SC2&He5C%))dgGaD#>qc+L!QNtWa~K8SS?JvF+dhCTEZ*5N*9$Lr;G zwcd6HyR!!ffP*lEWYA0-Lb!J7=;$bwM}MJ#8UkQYEQ9w0vH+mNaWnz`TBX$`*3lIX z)vPYL12{k)gN+^CzrTNEFl-nLHQEO%3s*_Sv5hM6CpSV6W;q5^Il>oVSMvmeAuhZb z5Y)g6so7mZtgd{;Ayli=)p)j;uV>}KZo7m3*cKN+x1a_pNMDa&5+OGVL)whRS11KE zd*cDt96HXg7BEM!!!4TQ`Ixx6!RuO`Gl&@~rPR^EzB;8>i#Rq?KFO%z$vH~ZNZF+kqDIQ>&P&c@NA>yU^3gCjLBv;+YknK3ZO`nBvD2% zX(H+k)5d2LPM}OfBpM!>^p(p3p%@3kA!yu9i7$$!CeamIR!rwhS?oJSV6DY+abixg z0S*Qrl2|=LmkUUN!DIq;8DKPcE9_nTZTCGy<*E+jwn0Q*QK!BOH?HYaIzAIsA9KM}FOG&rWv3c9mj5 zy;~#kE^)ck!66k5v;zP|CWKOTP~D&z9Yw_;FrT$-q&g)Q4Ke6|TE<~q9ds11L?d-W z5lR#UijX9(LRGmnpP#?_=w`HNgoRBMK+VB``tBkEpI>!oDQ~I=~4Ig@Q05*e06F7HfD>2W^n9 zZjl6PDH;uIRZ7sI>%?V0%Xx#kba4)&a=uD%JL2IB4WEM+XE{c|0z*hX(18NS$#n z%9wP(utLqsl7TT?FdjmnfD9#mN(k?%R}}atlz@`J3U1TTM>6n<=t+CASsq`$w3%L9 zU7jHf>EK9bxsfo>nWh^mfcmu9>^3u!Bdi40^tz#{B*rBpCK%K#XG?8j@JYMT>$S_) zx`>O2azm$pP*ko8$Rtq@WMJx6L5Zz#0}`V1=3xAi0M1Afbdh8L)`>ungDwaCf{v*E z5Ycx@qHiuX+vUllL@%*+0GnH(GpH~iN%(_R)_VPBW3btcaT3baQcY*z-^6$VdFW_V zx{qHT_s7dlly;>ehfjhEbqeM|v1E`HLQsQJk0}q?nl%|R1qs0#qyv)3HM5k;qilu)to@flpZ4RAn7!htwaP+sbq;u1oPK44AM!R(p(npL4Qg*8*+b8(2`^5tuG~n z+}#1|wV(rH#C)FmkN1fwgjh(?_h7HkA>sk0n18J?*s;M1SGA_CK~S#jk87Fsn8$)Kpn zNO0;}CxW<5(-Kh?iCnd4?OFk#VQ}`A4xUDwtm_XYu>=W6c#c(?P|r^;uUGYAZ+@zY zi`J#EUGD)EL{6w>?kGo+L{)}#5n_OfQtRx|y5Fjd&)jH_AlK4UUP>n5#Dhsj>l?nW3EYcBXLOzJYgm|Ss;&NHh$$OHHkzeEWA%hWTeExo z@N9;q5Q`Ao_6Msst||uLSS-$ugcD&Piy)(vrz8kq>5_oMye!*u$Y-7cYc7o&M z4_qkdKt9-5(SQaG=T_KBq-#iogc;gei<`??uW>L>i+Vl3e~|BR!3-rC(xC#H zf$8=~Q8QdJ+Dr%0W}_9^CdyUi9glF}5@|?;AuuqUF2r$q{ z7qnA`0@cU_EREP3{=gj=2+<~0@IOf4H}!M^PUwI&1dG6;bTB;BLf;;-Y_&1yHF~2# zk(_NmRRGnrXMUDzgLb(^ZJT-3FiouAKvljm3DGC;Y_-R;=E2=`b9b>|ic-_S9Po7! zx;sdU9twkq01b4c|gkL_D zZeHQzm`E6m2j#>2`x&zWB~eBF%cWkgR-^hMT|m2~R_2rqXxhUOB^Qdut#;|&-Ar?N zGG-1_SkiTA!V#qlH3T3P3Xc6A#TCYieUvD9SsD*72neelSgg`e9+JwX82zo|FbRps zov=5X=#{J{z{V9s91BQrQ1I?|`>k^3XdmUlc%W3~RPq(9C~B}+3p6uRo#RQq(xn{R z?{<3KYWCpX{rqsdXu?^|7GfATMgc`RCU#TQMw}mDA}XrN%s*LNpjg_}wjo}qL0bt}4FT2|E6>fyNa0Wuid{82LeMM* zhzP`fZiBTUya-{DdMJRbMGw#jr|3lAL+D^in9Nu@hA zFtdulp1~@ElFxyr!Ogs` zE$EdQKJF7)J5Yi@R82Ar7)Fy}M~k33YhK3NOwQ)<5eh`V8iX(?Y{LwR2cUw-E*I<% zfe@Tf6tgfm(2jC2u86TC6yq|~46%DDFc`Ecq&DVk zI^)vh>cROKEO5*beZxU$U<3#U@u5@P0tF@{9uMfdqJ#<&P(kO3A49(QK`cc=LZw2h zxS2T%Y(X2SDQe${0*Y{qw+MmP}54JfLkh} z6qFDrpk6Q*Y4B$h9hYa}At*^4JfR}#v(RRQZ`Q?aoSUI=NnRjg$7s;u@E3~8z*tRe zQaHqAMOg`lit=C`PLNj1NiipEE72@nf?P(<20dm>G5hriiOl zEotEh%`+w-@Gx|UnwF+P{lq{~d(xPYM9?eFhrRO}1~F326`b!-$05RC7|4Qy_5tA1 z@*Emz_mdA$k~`F)H`!w>hu^$o1{gHV}ubMgz}*~hF228 z!+=`EfdtLNOoOS4B-HZmpq4ljAD1EUOf|t4=l| z13;Iv%%m-=d4S-YOeYP87S2=1P)%_RT+2x}axEsnXko*o?MI4Vf0^zX=3`BWELI|ZmH@Zyyma#B-Yc$ZIX-!*66fWk1$zHWZgj7i7xd$bT z@C0x|8;rm|>|SV;3$Eju7v>XzyU3!npd(oQX#G# z1v4bUWziNbjByd594QR}%Q|rAxE~`lkPOSQR7**Ic&SH$6p9JaQx_R{HNSsIDUt>( zbPTdYUxPrXL71?XyU81cp)?9bXDsZWLfh#)g1ZC|&S5cGOLrG#0rZM&Q^-`Pd?X=6 z*CyIBY8e9&@(WT_{ir+O5d|zV6WYGSc!&t^7KE6m+l*vj69es1m7`_~7B(B@^nR+0 z2c`=rqDSeZU;!n79L8x3piTilv3=MuCbe2{C{$-7pg12_Z0Tg^{#d)qH(Ch7Jg{faiySqC_Wk zAvzLdF8@8C!hQhwCG_}?b8eC4W~^IBaZZKyJUty9sCexlf~*FH^EOSo1jU57v?kyp_ODkoHLZsawUhw8*r0(B|y&WN129W!Q% zyiqcq;}*d)X9^3A@zg(JX+-9bpaTK0u#YraMcjl!$Bdap31j|Zp=aNLVka`e`WUO1 zv;qr*4W88goFn!i;5Nuou<(mFAcQKGh8}d#)gTo}BN;muj)M(hM|?{_2hMOevO$YN z3Z;hoCd4L+FrYQwD0R1+;h<{+BaxuerEG@JC>BEE^!edEoSh*+q#i`CLZdMp0=vu> zM6WT;IofwX6{SM+B*-|lFZh-YbJys*EnFmHA0ku z$swbw*0={zs9hCrt5*_5bP^arYr33{JD?}hKr@t;bqur6oPEk^CTguJ0vEt@i_Ebz z=nvW*k|_PExgHkI@Pr5EK&9j8@F=V0I_kv!-~v1a3{)-84nmAh(lp&F4{ROHaUwuE zP!V%V1OOe}N5|9IzVylood}?PG~UA|!ANh1MOWIB*+2wwz6V>w)QR@U+*4Fi8BsdC zGZ&)rJ6UW_wiB~|CcCZMqr4#tRZEY|Y6aL#g~~{Q@ydOEU>X`3V^cJ~i(x7etBT|f zP|JbLgjNX&UX3wO)sElz%)5_gPWBO9a{(?LpX0XNtyrHfhgHeI_wkZRRWJ*_ zqPDDHI7)*>_3o%UTC6tP?Pj}~xX1w$RE3#UBu>$@Yo-mPMToAPc^A2i#s2q{he7WB2wwu*zJf6+x+s$l3quXtkM5JZ_ zWCjvh1=@s?s~mboM#7NguP#*O3YQS31R+YS!kk9Xp+;&ob|wY)@dEr=;HA!k`zK92Tggs4yiOP;tDI`@H1Ia(Vag7t2@oX>il!DzHt z(gI5llbY-J$nW4acJAol3NH!jV~$S_GkSQ6mLy(Afdr?8CtW_h^@5v8x>|+sxRimK zn8r)4MO-CZ=SHu*e>FON>#d7E0&=ziI;?u5S;m9LW`*Wv)`AnaI>mG>Y_jTFrph>9 zE|;4%l~k%*^wN_AL^V_uwk9Lv@gK51LRm;>)}fBtz$MHO%5ZE1unbRuFo?h=bc-{} z_78{WR2~Wv^$W8?C|sCus>_XS1sPtv`NpfCdVSX+r6u)NpR7WmUQmMOh!oAuwg+1w z%Lzb8%^jw#JnC@zG@Y*IbU(rt3U~yEE&y_VhXxMrECt+MNWoF5)wNc)ZXHHVVNh1> z_$%C%(}+?CQ}`y(G3#gq06?mp$)6zK8l#rdqMekmGL`O(uRrzPE6eV9)&W}$Gmt2y zX73@xjHPO`lW{#JDDjTGE~e<^LHUVl%pRFY6v`u9pd3#FA)qeQ6V+)7P^eC0)@TRU zqvx@RgXIO3Xg_Kj(g-aRc~oha1sH@G0iat37Elp{z*^`)?huVEP5m?Jes^;H+Eu^1 znm0v9{TxDP+EWlGSD?yJC=5?#wM^PU$QEXI4c3V-120e@Y!%cdOlRti!Y-kfe*+TX zuU?Ss9IkM6IE@HeJr^o)FI^zPEyxq)5XKn@z)iTbOAd00U#F~y7KjQ&Uf8ZsWzZ|= z!XR;T)@m*uzr5)V`&Hu(=|CVvh(MJ&xae2tZx?k#LhT3gtc_ur*qN&gNHHvd(7fnD zqi~nl6V*)$pKzS#f+@Vj;-H14U-Vs@geVVel!jmxpE1j}NVjmpkylf2iuwqNBrb&{r#DYen+Y8Xo_8^5qX80Q2A(Psy+S!O zaa)99(YqZ8n}lpui(FZS3egcnu}3e*t59eNp#Y<*nPZWAQ$we@zn%;fS;oXachiP4 zDH?4Q6?8Bq}MFUWR*>&vwEL^x!Y zMD6ET(@6b}(h*jRfQ&FPGbd*RC%b+?4q=B}T^9@bAQAo}5)`Wm9e_)84q=ntaojIQ z5mGdbtR$ipx{~b}VhD`H!x7Ll2O*9|OhZ|aj22?LB(9L7BwkO5hM7wTzPkE_7% z(*t8?JLd!^EQz39x(fA_I0ZVOh%RkbWHHqq(hyw5S1NaW8ha;HS33MBOvGVW(n)ZO zu0}fZDa@hL4eSeJXpM(;Mu4_pgYwGQ3#_!V;3_{Y1P3Bht!G6t#b~T!in@AO?bzN2 z)~33AlS{BR%@EP1i4X?Ylmbjj|INwhFmVaFUX8RTNytcH1uGXC(1#q>(xLXoflGAB ztWl^409dJp^e)nljTDI@xMsOO?Sok;JC?*i$zuqDxMQR_+#07Gx&bJQ^gx;!kw^;4 zF&xJhR5+DaZxDc!tzgn9kw7f}qtc>F#n@Fg3{$oPN`#B9{pi`R!hq>e7k|6s5eaQ) zv8Ew8Ch3WNAkk1!pN{a$bnp*Z`)8{Ydd@t0iRtYY-U^W?9ca>l1_1uDFWP1B128d- z%TjCN1w+TrN1cM`$){8uX@hTAC_=LwzXT%%l2)5lxFiIKTcjG4AQ(uOw3j7GwE3Z7 z(f3D`1Ddje7q}Unoz7Uf0#;QT&Yhd2qVb^s)xm5yaOp-YcVyr&rav7rAE}$=fm%R^ z>Wq4GV_Y520(S`IqAuqm7i%pMIZ}jh>J6iU@6Kx4i>-zsF;N&zTe z-WW`ltA4!*0oZCO$I4GcVN|QzW+uH<>g$uHHN;TOHIP(dw zLK%RS=@O()$pAZWRPx@Gb&Y5UlZTyVk&3yBg{4?CZZ=dt7OB-J^$t$1AKaX>9EVRa zD+@N3*%V;9p0c8iE`Hsnjs*um12b&opAvB9OS{d1p>WcQ46ktISSa>@3L%Q9wg3b) zURzAT02s3KGo`8;Mg&MLL^@(6ExbUy5=HUQUP|sKNz(TE-KFXg#O8*J=*7msgh;D~60bh~m3O{1o%XgFds-O3=1ERE~D_ zp#sq_0yEr?@Xo-N0kOm_iPqtzGg4R#bG?vD-3tQgo)L>UGjxm#lvF%HSze%1Mk`u7 zX8?*?v&DF)z*x2H^4n^i1&{a|W`$5o`{;~c@^#(20;;#yth_o~A`aB5$>Qf`fsBrI zPHp=FNd1UfxTK!5KA7}Kmr&`j3VW|mGE@Pu5sR=BRov*L5Xo(k5Jf`*7{qInUaeb2 z)SWx~m&nCnlD~(x8qJVltEMbdV-E@@MzD)6T}?Q3{z{#OiJu%GKuOgIFzK6>}1^^53O^hIDXoOCe1QusNDc&;?M##f%3$aRsf(GPaIn=1<*755Hk$j2iI2IR` z=u4gq+J;O~>ZVTxFVA{adXfzg5lXYaxxPF*nP5GHzGhbf6u}nuUf1`$#0JcD|{_&%$v-1VZNl_x}GG-xB%MR5u zp$6M<^kiXGmL(zz<0yhT4bfR9LIJ}we2rceA<=UU4cZ1?#F---^={+f1P~B}#-Vld zAZ{V#ib@p|uQ? zb&Cqb^xbeQ#DT&|I!>4=X0%Dqj-do3AkPx|K}uU0Ku4!sYz-&V#cIBo_faWU={toY zreYDJ&E;Z_vw_Oy7Di&St!9Bo!Dq-wY#a!KMNkmxM2G<7YA4}jbexBLywK`WR4A0Ygsn6qFSncJ zd_HC01eQv|c~-|r1t!v@dH(9bL)J`TGRVT25vb5=E!7+CDN8UeW`!)(Sv(-r zrZ}h~?T4}c8B1clBn}(Rg7Zi!?4Qed024&YrhisalD|YA1Ibu~Dy2M(V?;LQ0a)Bv zXft6(2MkTV+vRdGVX3nrI+~-6E0Jb%cDh~fruu#O&taSeR3^c+frOX>qv#fbns`5u zN`g#?^-O^{j45=`vQUBiP8EvL;=QHDKr#-z0JLxe&{%Qk_Z6K~=wdK)@@4yJ)7cu) zF5Mc<@sMSz&GGX5m{o|2S(ok$noL10q=8pw&WnkhCRot5{sRq|FUTYd85EWfJhR9_ zRtRi6Ag2u^R8EtvK@Xumt6f=mrSGN3zD58ZbVMcr!X~^3CnHy^8gOMLN}$Z-9e5yA z#{vE1Hv}|lX1T*s+G4Jb17TTOZ+daUE*0z5dbL{8idJIx4V;Hl=Djg)g+R(8SNnq1RAymo~ldM0%i2_9r%&o#gbfIXlJMJzwYYqq*2&H-leIw3} z^qeU=%vO~b#xXxQB|%n?*w|ob`}yO~J?&yD;H-kuPcffTVfEL92<`mzcz3*<4s;b1 zz*r&2em>BFY7l%710xamVf-P3q(v)47_4j}b`fk7X;`oiTq8E4UeW5n-F%tNY3To} zlWp{88|FP$tHq4PV6_Humkyno678WLGYy)pwu^?-SXHR^CIhT?x;eePzP!A8{Qk>b z28lNTF^L5YfrwHo<-zIo^~J^c<>i)zB@_neV+Iw7+QV2GAyZ-Da}wXJEC}^r8K!Tj zf>zNwmXIMe$S@5P!bEa)D)eko!KPUQTw-Ur9gNqTHLx|C45?N37bD{OGCsx&;^gQi z5g-9jb9De-g&W;)FG^$D3iDS*UWk$<7&lEI|WupQOh8gf)Q|R~M(d zi8jx2R}d(17dmxj)WbQ56^L4WMAVpISca4^dPI;=A|2L~j@a}HjjPi7K=qEjcJR@p zrA%jP9^_Xpy=7q`*Yp8n=a>LGBXOb zgXMC)oKzu#cs!k^^KP-(ob9&fm)GYr^8$N!Xg0OBg=PS!NDap*5vUtvVCc?6;_?|W zY6S&4e-Ga9J*08K0RWV3RW219!`ZAG#m;tjv6#>L^!5;sJ8MI9ssRW*9I%PJJ6CRx z7b80T2IJGmuf6m3OGCMuD#^*o-73x1@fPbiy|}*Ev{4vh zA5y}stNH{_+@8)F6E`jvf^9(~CU%j6I~?ieIruGZ@mhsE+}{s*FimcoZD)15W{w|U z$hH^*N+(z~n5**w{Ed(WbxU8a6{rm7+mn-7hvZ|he(=gW@4mcb8wA<}`t01otS-}a zEaTX$*hr-1=d@uq%$jdj;FY>{JisO3qHH*gg}am&IEjufM198u83V+4J1rA{Ty?V8o}REmmu*Al z*H1q6>9U^guPXid;^b_1a(Q`vJXG_64)S)ZTuHp= zM2pHg+d4XM3vp zY<&#!o?ToVk4PU?QRzTI=w#*>7X}%Tzri{<7i|f2_lL_y5{WKJ6+Q&#@r;s?C38?l z=A9rzSug`;af47-rHa-Xu8Bi#_lIqEH_TEA>(5pvr`vI-Gw2OZ9=-X_o0mbO+L(GLjE9yggsl!HJ$%J!mZRG_Gqu4u0ZAD+JgXxgQ0hp32 zcIWGp^OG^_O@@Q@#m$qK&st>3(UyreR6A9~+?lQxOX%RE*cGT(Ypl21tgl0zql<~wPxos+ne)bY0Sd`KCnBD)~9;HK0tn#-8fYgw=r~&psfxB2yYmN+c6Fyb4Awa+ z)Gp9YfOokVz#+GZLQ7Eic5|^iIXOMsE~ganL0(!7Ew-uf6xzzvKCn_E@W{jgYz-N8 zk_0t@@%vL}!-%vYvQGRsu@b2@0bmO>f&%Iu(Bj@&xCYcpe`-1aPhE6KjmWIdY z51!oY*rTr9nD5SR9-X(@%|p=T!6d7b3hn8Pb?v0V1OvtwW-N_TZ@D?UAR)6R;r&Ua zFhMnhf;2lNk`ja7F-E+7>>Y}mbL`jwXDJIciAq;;KT{Lw;6uc(%rH|Mq(JK0HBxh0 z7$|6&@F@YDGW#7+-@vw%X?}2V{rI()PpOK|=-@cMd~n8oWl0WgB+O=gBpD529xL(a z8&M5skit_-`8hnt<~vm$hXwHmEk z**X(ktC}~3E`<-{Sr`aWUI35T3GCo%Y8WCiH^Z)n^zJbyzz&nt8tBpFPgH8~V&&H4 z(Sz-{flXRZ1uAMQ<`FL0Je5{=F4CM5coEp4g3r_!Rdtdi1a9abx3*|d>#%*;sDV|Y zaM8mQ4n`kk_C;}zG7(cbw{&RJK@2<$c^FR^xM(915@l(b0wFZH&|^HEjpp;kVlf@f z)~k6ZF-@3LtaKJHzkW7pVk_`XgQ@h#Sh&r1W)iG?rHIGfU|wjj+^5oQOpEA~RvnzA zlgZ8H>G{RU8u`Ux*O$9L$^`a*B|}73Sgxu=hdLs_;b|CQ3tpEkY^6g&kiG=CfLu$) zL|CITow6ztS|)>LotR?TBUn_i+)1}NIDhSIfPt7x5LzQ54FT9=>mTDi@>|G*r&bAK z2#C^)8;C0mBQybn-7K!Jug*4If^#M4NsBU7Jy&)AW8g;3g5RP;vW95No6;KG+S1-*Q$ip;;O9o8nx;Z7L z2$BRP{Jv%)5F&Akd8D(VXhbZ~kt_9&uWxS7w|z=J5QlC!w?R9r7ser@$ed4>1DkEC z;s(h9-{Xm$eT2_O4%~;|*5KV`&E@`rMFdwqFvx*5~bYT=E#8=-EB=19^( z3#%32h|_Ijq>h7htd$YFDGroX#S*tTAWLn;S)!2)pN~5+0srhalnOI;$nY&5zz#M8t(|Ju!qJ=I( zAfeOQCN^c?pQA*F(iS5_qk;(DRAnu{2piN_Ddc(6e_UV-h^nIwT~EHo-1AvEX*q#BFM>#K|7nNg{_ zWsqRo1AI29hO40?fD5HJ?yp@4+aVR$g9fAMsx~AAn;4BdYH?rd{|rXz3EP#27toT? z$y|z$p?*BK7-fl#KXHYG4t{2H)giSWei!k5wNkY=S#5VLo@RuUWF(d>D$2reW_Wgm zK$cB8fnB(%G!vi@A3i}Sr@Q2dLL$q{gAZoUkv4f|~FFvUm1=?Ge z4Xl!2C)=astx<|{E~2xpDd=+r|FgZonC)y?^wlH_s+ZgAlhe~<*0Sr4qp1R~K_>)J zEW&KFui(was*BUc^572q1bPuXoQ6>ZH0U`gsr{{v$^YSg5_G}PF(DYq)ucmXVNQs3 z)kk^89VemcN+L?iY7a3_1T_$;pMg`jX*Ts_BjKP!GE}bea7J0X+!zu((FMIEq}|y* z?-Dis48x2zIFn|i+VcGR=KOe6q>(V3jp42{^*CneFpwi9Vqy;3LK^a&&+=hM0R@qbvp(ILRh}#o;61C3XN*q0_LQ*JM)M2W>C7Mjg}$ zNk{|-Bi6>y5CzLi2kDG98 z$>0<%M!GUYOL#;NMR$3;p@~CJVo*%9qEaQ4z{2`?F`k_eH!a3J8vQ!m^@((JKnb*y zXofGNfYI0TmmFcPA%d&9}cC0B2r=gphTEX zIM}~`SfFf34hWQ>Pyx`28K;$T84JlSIS3apPFY`EoSn`aS=Z?>x28PM6X}LEC^=&5 zE@p&gOq4TS(w*<1W7o^k*%NeND2|YuRI2OK%d68Zi94478)K`$ChPjpKzhyOJ6v)C z)XE6?xI^YWk9fknumHGYXAt&kVP7VVE7XwuMPH5ti0u@n)pQo%u=jDZH|usbr)TF^ zm)lP6h){+_QZB4y6t@=#DPUgY`&2BNO!aoB$0zI6c9?f3O#qZDGDoF=QP$b^^z3BW zXO~I91&_riLCK<#i)u_Gh6|| zOgB^Y_(V4CbL~G}3p5{&=96~+&)6LRn@74Bbv0ER{J46!VitIB`F!v{#C7g8|Q}$z(4xB7(5L2Zi z%#p5UzI=rZnJEi%VYGti9+y&Oq9$TRH*MDZF zc{Lzul$%~X;UR&uAC(jW8#*5P>kT%)sG5?{L{9+Mr&7X}jjqJ+ueT>`EC#v?Iw%%{ zkNFsiJj?<>$9<23BXmb`DtZnE3;-c3g`rHaa7uZYG%DL1@SQID2O8EBd0;I}Z?I&Z zukAn{gAqM%Q!sVASr1~qvOlJqj5a{2!1hAifI{S51~x8s?<|jZ8hZ5SkOWn_>r+f@ zGoAFf5pzC%mkHBcggFHFDFkrOnG7~5_SeAy;@~%Qm<#$Jmy8smDhCDDyUcRAH#;h$ z$phB-*YxKI7-rgiVDws}JFMMfW{nAr0nhm=p3Uy~cv5Bqr2b^YHr>4j(ok>FFGfS$ zfn;ExAv>7XnKKo?S`WY{jF!QU7F!GL%h>>rB&9ela52lBI>r6F44+Z%@83gVe98{k z*4YWs4k#!}lLmpPEHEZdHFjeqDj)+kNvD3`gbHx2m($vbbn3K+SyJrN588pA(R#aC zZB~`~(Y>+LyJf%}cV@4A3t*j@Ed`q~4Z+NovL*Ory4;+c9n+a9 zIO-#Ev0rxqw^~WDSF{4~KZht3MEK%<&;$XN>ZIV=A)+HNH|_4z=woCTb1GC;fpCD3 zppgx5_!mSu)ROPsyQ>lSojqBGu0lx&jAx%;p3tLt@7`U`;rp0E z5YGsRSwW}HrGqX-x?lM2qfwvTq60UeBQlPNT=_m24i|r*L*4ddO58DHRm%|b`C?G(QtccrhJX%V%mRWSZQK%HMub3$O&$c$-k2L&yCilOc35#o!vV!y3fa90OChK8NuO^40aPa)_TjEtaSbl9ixN)G_=3@5 z>J_p1DtwnUFLWT2Vw~D?a2aZpicm^#QwnoP?JFk%H%>y)0*vq7 zN3W2Bb{@wwkw6C;Vew$J+OdQdOJ+3-0fO;9jwGTWf_%ziY;`}S6-a}h4*gODBCd9S z&Q9s<4i;Lg+B!dB=75^r<|Jk;xR#)TPIbHXz_4m2&{g|TCg@l=?L&40OgnbDe^*Mm zW};!7BV0M#FB!Lx8-(Buu_qU#GOkTQ`q=uP}_`BjA?@5DX(e{?6hJE{kM|H9as4%gGQDPCc>);TYdQd_Y3N-Y$A;k%+-! zx(pTP9SQ?@Di2-<9g@N+{(5%!jegD`5JHMmx<9yOJE1$QDjW3rHkFGQu-n8GJ^~k64~B%;LM?kYPCs=q3YI znbbve$9{K0s}w~=2ul7OLk|c*LcBl~A&<#W{-FWLLGwmyy|JMq-2;|zTFlLkClmGr zhYk!R2E8>e7BoQMAS&%@!zAy%nT)L?`X%DN@451dmr@LNN| ztl@L0HhGfO7(nVU&vyMNQiwn);3n~s3?Di;or7$Wiyr~fL{;7*z??8&Js<;T#%B5G z>7y;40iRAQK_C_&%)Lp4P9U)-7K!njI?$m56cIYSrJ0YF zeXNojR=dOH>tFxU+q(&qXhe>}7g~iCz{KIn+4;$KvsujN#7QLa;y_Y`LjN7L6kruj zia0+3b$lx(;Vrc{#tmU57y|}IPjdcZ2}1Rg`h zh?v(LUJ?z$RUw%|=noYP+Cm|NEe|3#=E^a__4@*rAJfXojf4`CW*AobCX5efI?)*TzDr|j%8pukH3jG-Db zg7|fs{1$FB7>&oeHAfZ)3<#TG??iYGUXZmSX##!=Y23mx6;v?W&X@BsxyI@PO0s+d z=e>K7;TVaUaCJyPmwgzE*9iGBnZx_26fy2S)C%KJrKm{4HhgUM@V?<8HOa&}D6j=7 zylhS;{oZg!b13D#pd;Lf8zmcoxIsq9L0pmx9FV|Zbrn&N6}Mo#>PqiXvDc<;fLUZp zwib6YxqhD+yrfiH%)x$?i-;saSWFv2uou1~#cxcsc?m^JEZm4aVie{5j4=w5m;oP!CHOt#4c?VkaV5n; ze#GE8h#`0gt5`;qnKD8gbi@D?3}T4;2Phh{Ny`LVG4c^C-nkJPKBO9&mZ&SLIDDGrNOp@dhQ0nB3T;&$?oGPTodF#*7KQyFtT zd~bUH&fP;&BW7Hkp~-`|_ZTVE^EE*lu){pLt7Z%b;3e~L*#4)cqqQcX%IPrwL{85FoGiA-~Z)Ln-1E=tv8}jvZCgMhM^| z&SC~7QC?kM_+2dc?DrVBI zTJamjqw=HYM6a+5*II!mi8-hS>OQs-1B%h}ESbrL5StvZ8YH6t{BL5I481<3=Pd}r zSeTEBx)}G#u$r~Ww&q~}!2uh~5e;Olh2SExn5|zo1s(UD3ojQ_*g0q<4DlnCKMJ-V z9Au06TRQIG&Y?z8;NK~mu!t395_U}t)c86{gpzJShxP#l{6i{Ug(wuI3E`+>XbG~G#lQsRU<(Qu zBP558p<>IUxrxl?|dnaMT0L{ydpQ#Ldy=Tc7*47b2msQr)7MNmRpnEeLL7|E8M0W7rTcYg z@H?`3SALWBtD%H?Qqx_syTH*eV4n%*YrZ9_I* zA9dJ3(}0!mmYVVrM$87-ghe!6TNl0~Zz2D^~+BIb_uFcl`J z`R@@*LoSN#Y4ki2raK-qMaZN%BA_e&1f4-CbD*)kDguksGH$s|FS)CE^K2QgIz8R2 z79-PMOTpyvO{QsylH}>3Wf0pZ{mlg^m=H|qRhTc&ABIhrYCynn7s=ec^U1q< z5$p&<4?2)ZBm+41Fq9xn)K#a*0i56APSK7g1QWGr7aW{`*$UFqAqVUucTx?R)W)0T zXiih8IXo?ad^aVV<oIwCG|e&O86S%a%?e!g&X#p(?TGLq=YQ&LaFg7mRY-K6q`YM z(9#<(wkJ22+u3r(KX!27Yo-Q#vEyjGUD2CcBj1Lj`_4u&)97tcX9`}B;Xzgp8Idh1 z1Y=&on(;%IxXW8wipXXbO!xqf1|R(q24g8x$!f1mTVdmd%PiCnyKv~CaoUIWP5so; z5FunpfrcX1a6h=ZymV#F@nSX`QULArM&spTNdbHF;NgSKyh%NZ17*^Zgh;}B;xF(< z;GroA0A|1pT7-uEhj?>cyTZ}bd1?s-7>MiWZyBn(5?y3yH8Id_nUqKlI-<7f%sRlV zBB^fLhR<;K*8Sb(#+n!31kh^r7MD+6dGh$B2dC#J=Y!t3$=6Zw)!6IZ#>Ggh2Ul}e zSNO%(49f4F=Kj**R(L8GvL$ph&;*buYlki?| zWh^IvCnak=u{Y8(&>TiDDS8gd=9Foh1p{?Eulb4)zLb5qxOx4}*Is-2+A9y|=Zl_m zI_>^+eR_VjTg*m-DU*lnv~j=}CScVT8tKV~0}VE4fs2|6UF(cc^HzV5iG#JEVm1=U z`yq*dXHkVml!2P&em4(~?{PqnfJF>oDcoOE$AZ_0VGpy7p53@0S5;WjIP(SGi zvw#kkl!S2bC>0TP#8OF?MGwc5#j8K}jbHf2H@^PWFMaikub%)`)8Tmg_>Ctgb2=P5 z(GWvIi24$)lT$$l0%q+G3WSmr3?zO?GDPb}Fg7nC9jcWg z;jfSasr;SFM+jWK4LTBmRO!9onVMGa@dbH6(ZCa<`ryzxAoBV3ZXvl5k6FXOP%03YthnL54_(4h)A4nmi}* zAV`4)XUHKjmw^X6Mu%t5s6 zFJtRJU_IzCR;A!pr`GP>$)oU%7(oKLQX}-&OF4 z1uD!vZ>dlk0*H>pCj##WhK^p@$Ye3M*i;%!bWWjS+-@yi|NQ4a`~LgyJYhziNzeKE z^yGN8n6qmnL4G7VemfD0Vu(t-z)FPM6~Tst2m6jZp&-#LP5$7JNK#9e5LnD_M;~w8 zipEhN81Wj-hCmdBreVMa8433hgxS-y+oU;*&l`MUfD39+;duhJ%mx2~;NaHc(U2dakqAkckUhB{K70&>ydv^|^ z&c^8VeTiq+?A1f8#PRY9i?i^S0Eu)s&u*nPsR~803Dvf*3k$J2;xa&9li9jnaOQ!T zs9UqEw?F;fyYIa5=yWw>69@7X4n$76Z<32~AoVOuU0KdTmmZ~R$l%*n2_Xb3M{bhw z%+PrUYaoiDRuX0b8Y45K7A2!0W6AuF-$WiL4FbWLC(;lA2}WIotAPN&dT?4YwGszF z&l2&tEgVB2b;^bZ5Fs6>Pv3gu)i++dne&Z{5!RRtf*6U4rqTrAM~&V2$_4}XT&Lti zFoYqJ7-G~)gWvvu2BRv5c<06a)PcCGXYr2^D;=s$@I8==7sP=$IcgT>Xb2K<;9Q99 zGyDvE(Ll)GombONSdOfoF^WQGie(UWFyB7q-{$4FUw`H4)0bu}aWFvOLPuCCtcbRH zw%JP^me`<%&*nu_%R4$`jUHub11~dM73ht3g8`2#*3HUdi#x+Z;pG+ ze9I0Q!oMR78}m-UiZ2tzliH9*>!&4h!%&hw4n(4MAs7FlOZ$g+4c3`6)VpKg{3C_r zd1CgMK4ZR*XwWewLOq1}Ene#neYnv%wT`4-iRxk3(!uCyW@5LApeUEFjv)f%wQT@f zpPpXrrZhRQZ6eAk2dq>n5#%8y8CP;pAGW95N(G{jHIPj}OIe4}hjxib1QbW)kGw@{Klw_++S_>28dk$;0SaLpM?-zG=b( zk4}48RIuF^1nxtJX#j-C7!v_h(}^w$d^{nYcIPAJcP(fDm?VK=%rgES`8UB`I+wOM zO%Ovxo*9BeEhY~22t!vaw{#dX9vl)P6jEgF+?CQ3gD?ezFvS?UM)kl$HP^Q*vP%hTRqwA5}>X?n@gh+UW@CfDf)ce#MlXxDx2=$XJNMNA2NIaqjPxV>{ z9-#>Fl)1lzXs$5Gkjj;R?k!Yj6C+fDA+kV{<{!wQ$(BHc#fB_hjV)SOY)>~0i;VdI z(%_(yYDad!lR{NfpobqesxiRtN?d_Dy=`crxieMnARzP!T>+OvWng&X>hB^G zy&;4^2X2Yj&2$n@ali8Eri%!$32ctxX- zyN`xFIBE`t=h$Gl*llITB@tS@jF0S-r)ZlI1pe3ac{fkNA*@P$vH#i;WX&a5Pe* zEl5Y;tz=n?)D?!KO+@6|k^voPpPx(Yh4~VOpV+mw8)ZdQMmn$y*e=&CPl^tPA-Gxd zXPd5=XjWySiHg2?$7#4rw;qF0M5?jR864+B2ruIdZHh=*w2~E$=h<)R@L-?@kqjH= z$9tB~d{@Qde6nsn=Xa{`(IWGq(qX(37SD4{SoP92h!(BFf^*8_wj{^85!;+$t{isG z)ttk*a#u<^kq~$CM+hZ`2~Mg$P%>gLz@#4$q;*xKs-CK^bZ3{)sjGq(;P? z$b)fv8gKIs5>jcT01t{LWr^KH6NVUMAe@9gq``km0=KEOePoOeXXI=)A)i`>H3+o< zx*}@$5NC^UANLOp98gj$!W~A%Bfy8cvkcJ@Ix5EGAtj1i`*&;i@QG{%l1i~oh^Q}N zx*XM162cLJj3O5o2?-SrNS!0#wT$K;xn$@RCt>>LsSz46N*tU)0rZ>uhB4?iBbK~x z`93|KdlRhL`3u&VWMUu@iCh6dp^j#bi7rWs(js!= z9Do+mu?8gI<`_^Dc#2q{gH{5rK}MP=mSS+6-jXMd*xnP0bM#ZW*MVO~#oJXvNqGzb z;*cLhS(vRczaUEz{ISb$R}K)Pcy=HXvyy;KJ5VGjvSNYH{NeyED1tyLvje_dm_BkF zDOtk~4SH4Y9qv^#51n`N0ILI0d8zbcP@V|WRYSjPpM%jJJ_Y(2vCU12%)vfCGlTG|d@I;ikz2gaR5S0DSQT zet33dehx4Rdt`tM%K#|fFX-ee6c!L@~h)j45J~%Gl2M>Z`Y<+*9EKQFce?Ya}Jb=PK_L;zjKh+ml zjzWZsrX-6aQH4T{{Hb&BKm&DY;lS2qGMP>fL z>X;I7l!;iv))9@mr4QiFTueNUxdjEXe=kmQ=M;BUahb>wGrKfzP$P}H8<$jxq$Dv2 z`qct80HJ&>ulf*Z)uQt#c1Go@kPuTfD{@TYL4qe2X36nUP~jwn{=pI3|8oIpAL3y zB>^O%4%1Ni!wAAiBn8<)h6~31S_0LWixkp~5@(g9qD)v)5QF0kN#wG72bqxjB?7sn zLjwt#pakusM?k32a1}CQrV}v`k9AWlBPCRVZ_LD*gV42t%{bK&F}pA)UM6&)P8HUk zkQwn>T{CDT$VHpHf&AbI|ETB~BO_3?nTk#5pyH&*qT(zxISZz=Sj;43QCOfD1KjA; z`4B$=1%Has_vqOOGH&TW;?%h;U)|Z;`{r|dd%uz0+xv%`y}j{!y#Dsy-Zt}(KlV5{ zH4cA2zxVOIEx-TZTQC0Vdw=&2efp!vm)^YjJG*CZ{u9pom3;bdeDL>Y=Ow>?z-azy zjvs8EVqY4XO8{QSwEImkB#%hQ)$efJAr`-SiP^1u3T{YU@lum7#z z{O$k#_x|2L_}~B0|G$op_4i@N-ri5|{n6gXKH$*abIJ4H;xEsA==t-{y%6X81n<9a z`&_R6_=leV4CntC@BJ75?%v*=550f)_BvJmcJKC_-{zcy=YA}%`TIOSynX(MJg=!H@VK==N|t$k82)t9v{1X{7>Bfzv1zp@%VRm{Chn9 z8jtVZ{{9#E{Vg7!`QAMqFY@># zkDuo87j9oO{JnpU$4~L_{eSlMx$i>~NWQnH#Y0-0<9m>{2U+o+@B7-r_aG~N``q_^ zc#iKsJJ0972b<#XTv!y3XV3kE=lOVcc+N-1pI;9A+54%-|G}T^r#{Cy&-~Oc^8A^f z`VP;3)KC3BD*DU3pBx|gsgL~BGhO)8{{F~MC4TE8KlP{8ppQQH|27AnCyM$mH+>er zd^m>L+k11HjAwBB`~Bqici!Iq^^c#I{__8MeEa_K_MQLv+yCwKSBl%z@_+mXZ+-Ty z+w+dM|J%Rz&sVem`Ch#KFYA-tUK~Hz{I7Q}x5dN9AG}W9CvN>;{*BIm^6UTMc1wWy z;j#P{C-``FWFP+Vzdw8b|H*GM=D+%9@3;Stzy2rt?N9v2KlIyKoSKezXf{_6A3eiKkXxA(>SKM}vbcK8#Y`2P2l z%TLDd=k`7xzn|axsrdcE-iz^@to##y^Lqyl@%B0&i{G_EGV0r(-+68O$6kN%;s=}K zuYL8apU=MXwZHt0FJ^aN`TWoSrO$r)tJ&UcH2y0eoRmEIum0e-f9*3@+r8hp{rw|< z{=a+qNB`X~{{6rGxAMEr?-hUiZ~x{`-Rj{-^`QT+RE?h1gFec;_x3)@yMJiqALZRY z*e47)jv6&`AyDwR)_dqo { fs.createReadStream(fixtures.inputJpgTruncated).pipe(writable); return writable.toBuffer(); }); + + it('converts warnings to error for GeoTIFF', async () => { + await assert.rejects( + sharp(fixtures.inputTiffGeo).toBuffer(), + /Unknown field with tag 33550/ + ); + }); }); From 206eb4a89a5ab7e87a82f8e073b2956221a6dcb8 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Sat, 18 Oct 2025 14:52:17 +0100 Subject: [PATCH 098/115] Limit colour strings to 200 chars, helps reduce effect of potential ReDoS --- lib/colour.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/colour.js b/lib/colour.js index 8de8d3326..b8b19b56b 100644 --- a/lib/colour.js +++ b/lib/colour.js @@ -139,7 +139,10 @@ function toColorspace (colorspace) { * @throws {Error} Invalid value */ function _getBackgroundColourOption (value) { - if (is.object(value) || is.string(value)) { + if ( + is.object(value) || + (is.string(value) && value.length >= 3 && value.length <= 200) + ) { const colour = color(value); return [ colour.red(), From 9e4e184132cf040b31c917568c9337e70b36cda6 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Sun, 19 Oct 2025 10:25:50 +0100 Subject: [PATCH 099/115] Add experimental support for prebuilt linux-riscv64 binaries --- .github/workflows/ci.yml | 24 +++++++---- docs/src/content/docs/changelog/v0.34.5.md | 2 + docs/src/content/docs/install.md | 1 + lib/libvips.js | 2 +- npm/linux-riscv64/package.json | 46 ++++++++++++++++++++++ package.json | 2 + 6 files changed, 68 insertions(+), 9 deletions(-) create mode 100644 npm/linux-riscv64/package.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0211806d8..b337e0bde 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -235,32 +235,40 @@ jobs: matrix: include: - platform: linux-arm - distro: bullseye - run_on_arch: armv6 + base_image: "balenalib/rpi-raspbian:bullseye" nodejs_arch: armv6l nodejs_hostname: unofficial-builds.nodejs.org nodejs_version: "18.17.0" nodejs_version_major: 18 - platform: linux-s390x - distro: bookworm - run_on_arch: s390x + base_image: "--platform=linux/s390x s390x/debian:bookworm" nodejs_arch: s390x nodejs_hostname: nodejs.org nodejs_version: "18.17.0" nodejs_version_major: 18 - platform: linux-ppc64 - distro: bookworm - run_on_arch: ppc64le + base_image: "--platform=linux/ppc64le ppc64le/debian:bookworm" nodejs_arch: ppc64le nodejs_hostname: nodejs.org nodejs_version: "18.17.0" nodejs_version_major: 18 + - platform: linux-riscv64 + base_image: "--platform=linux/riscv64 riscv64/debian:trixie" + compiler_flags: "-march=rv64gc" + nodejs_arch: riscv64 + nodejs_hostname: unofficial-builds.nodejs.org + nodejs_version: "20.19.5" + nodejs_version_major: 20 steps: - uses: actions/checkout@v4 - uses: uraimo/run-on-arch-action@v3 with: - arch: ${{ matrix.run_on_arch }} - distro: ${{ matrix.distro }} + arch: none + distro: none + base_image: ${{ matrix.base_image }} + env: | + CFLAGS: "${{ matrix.compiler_flags }}" + CXXFLAGS: "${{ matrix.compiler_flags }}" run: | apt-get update apt-get install -y curl g++ git libatomic1 make python3 xz-utils diff --git a/docs/src/content/docs/changelog/v0.34.5.md b/docs/src/content/docs/changelog/v0.34.5.md index 886932b8f..0c4a936a3 100644 --- a/docs/src/content/docs/changelog/v0.34.5.md +++ b/docs/src/content/docs/changelog/v0.34.5.md @@ -3,6 +3,8 @@ title: v0.34.5 - TBD slug: changelog/v0.34.5 --- +* Add experimental support for prebuilt Linux RISC-V 64-bit binaries. + * Support building from source with npm v12+, deprecate `--build-from-source` flag. [#4458](https://github.com/lovell/sharp/issues/4458) diff --git a/docs/src/content/docs/install.md b/docs/src/content/docs/install.md index d74d47a24..083db5ccd 100644 --- a/docs/src/content/docs/install.md +++ b/docs/src/content/docs/install.md @@ -49,6 +49,7 @@ Ready-compiled sharp and libvips binaries are provided for use on the most commo * macOS ARM64 * Linux ARM (glibc >= 2.31) * Linux ARM64 (glibc >= 2.26, musl >= 1.2.2) +* Linux RISC-V 64-bit (glibc >= 2.41) * Linux ppc64 (glibc >= 2.36) * Linux s390x (glibc >= 2.36) * Linux x64 (glibc >= 2.26, musl >= 1.2.2, CPU with SSE4.2) diff --git a/lib/libvips.js b/lib/libvips.js index 9c2917fcf..dba1ab458 100644 --- a/lib/libvips.js +++ b/lib/libvips.js @@ -16,7 +16,7 @@ const minimumLibvipsVersion = semverCoerce(minimumLibvipsVersionLabelled).versio const prebuiltPlatforms = [ 'darwin-arm64', 'darwin-x64', - 'linux-arm', 'linux-arm64', 'linux-ppc64', 'linux-s390x', 'linux-x64', + 'linux-arm', 'linux-arm64', 'linux-ppc64', 'linux-riscv64', 'linux-s390x', 'linux-x64', 'linuxmusl-arm64', 'linuxmusl-x64', 'win32-arm64', 'win32-ia32', 'win32-x64' ]; diff --git a/npm/linux-riscv64/package.json b/npm/linux-riscv64/package.json new file mode 100644 index 000000000..dc3677353 --- /dev/null +++ b/npm/linux-riscv64/package.json @@ -0,0 +1,46 @@ +{ + "name": "@img/sharp-linux-riscv64", + "version": "0.34.4", + "description": "Prebuilt sharp for use with Linux (glibc) RISC-V 64-bit", + "author": "Lovell Fuller ", + "homepage": "https://sharp.pixelplumbing.com", + "repository": { + "type": "git", + "url": "git+https://github.com/lovell/sharp.git", + "directory": "npm/linux-riscv64" + }, + "license": "Apache-2.0", + "funding": { + "url": "https://opencollective.com/libvips" + }, + "preferUnplugged": true, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.3" + }, + "files": [ + "lib" + ], + "publishConfig": { + "access": "public" + }, + "type": "commonjs", + "exports": { + "./sharp.node": "./lib/sharp-linux-riscv64.node", + "./package": "./package.json" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "config": { + "glibc": ">=2.41" + }, + "os": [ + "linux" + ], + "libc": [ + "glibc" + ], + "cpu": [ + "riscv64" + ] +} diff --git a/package.json b/package.json index 0c3caf45a..3f00bc09c 100644 --- a/package.json +++ b/package.json @@ -151,6 +151,7 @@ "@img/sharp-libvips-linux-arm": "1.2.3", "@img/sharp-libvips-linux-arm64": "1.2.3", "@img/sharp-libvips-linux-ppc64": "1.2.3", + "@img/sharp-libvips-linux-riscv64": "1.2.3", "@img/sharp-libvips-linux-s390x": "1.2.3", "@img/sharp-libvips-linux-x64": "1.2.3", "@img/sharp-libvips-linuxmusl-arm64": "1.2.3", @@ -158,6 +159,7 @@ "@img/sharp-linux-arm": "0.34.4", "@img/sharp-linux-arm64": "0.34.4", "@img/sharp-linux-ppc64": "0.34.4", + "@img/sharp-linux-riscv64": "0.34.4", "@img/sharp-linux-s390x": "0.34.4", "@img/sharp-linux-x64": "0.34.4", "@img/sharp-linuxmusl-arm64": "0.34.4", From 69b2c45615364316e4e6e6ef30145bc3a4cf2f38 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Mon, 27 Oct 2025 17:21:37 +0100 Subject: [PATCH 100/115] Tests: migrate text suite to async (#4466) --- test/unit/text.js | 93 ++++++++++++++++++----------------------------- 1 file changed, 36 insertions(+), 57 deletions(-) diff --git a/test/unit/text.js b/test/unit/text.js index 3e5c0a92a..d55031a0a 100644 --- a/test/unit/text.js +++ b/test/unit/text.js @@ -39,7 +39,7 @@ describe('Text to image', function () { assert.ok(info.textAutofitDpi > 0); }); - it('text with width and height', function (t, done) { + it('text with width and height', async function (t) { const output = fixtures.path('output.text-width-height.png'); const text = sharp({ text: { @@ -51,18 +51,15 @@ describe('Text to image', function () { if (!sharp.versions.pango) { return t.skip(); } - text.toFile(output, function (err, info) { - if (err) throw err; - assert.strictEqual('png', info.format); - assert.strictEqual(3, info.channels); - assert.ok(inRange(info.width, 400, 600), `Actual width ${info.width}`); - assert.ok(inRange(info.height, 290, 500), `Actual height ${info.height}`); - assert.ok(inRange(info.textAutofitDpi, 900, 1300), `Actual textAutofitDpi ${info.textAutofitDpi}`); - done(); - }); + const info = await text.toFile(output); + assert.strictEqual('png', info.format); + assert.strictEqual(3, info.channels); + assert.ok(inRange(info.width, 400, 600), `Actual width ${info.width}`); + assert.ok(inRange(info.height, 290, 500), `Actual height ${info.height}`); + assert.ok(inRange(info.textAutofitDpi, 900, 1300), `Actual textAutofitDpi ${info.textAutofitDpi}`); }); - it('text with dpi', function (t, done) { + it('text with dpi', async function (t) { const output = fixtures.path('output.text-dpi.png'); const dpi = 300; const text = sharp({ @@ -74,18 +71,13 @@ describe('Text to image', function () { if (!sharp.versions.pango) { return t.skip(); } - text.toFile(output, function (err, info) { - if (err) throw err; - assert.strictEqual('png', info.format); - sharp(output).metadata(function (err, metadata) { - if (err) throw err; - assert.strictEqual(dpi, metadata.density); - done(); - }); - }); + const info = await text.toFile(output); + assert.strictEqual('png', info.format); + const metadata = await sharp(output).metadata(); + assert.strictEqual(dpi, metadata.density); }); - it('text with color and pango markup', function (t, done) { + it('text with color and pango markup', async function (t) { const output = fixtures.path('output.text-color-pango.png'); const dpi = 300; const text = sharp({ @@ -98,21 +90,16 @@ describe('Text to image', function () { if (!sharp.versions.pango) { return t.skip(); } - text.toFile(output, function (err, info) { - if (err) throw err; - assert.strictEqual('png', info.format); - assert.strictEqual(4, info.channels); - sharp(output).metadata(function (err, metadata) { - if (err) throw err; - assert.strictEqual(dpi, metadata.density); - assert.strictEqual('uchar', metadata.depth); - assert.strictEqual(true, metadata.hasAlpha); - done(); - }); - }); + const info = await text.toFile(output); + assert.strictEqual('png', info.format); + assert.strictEqual(4, info.channels); + const metadata = await sharp(output).metadata(); + assert.strictEqual(dpi, metadata.density); + assert.strictEqual('uchar', metadata.depth); + assert.strictEqual(true, metadata.hasAlpha); }); - it('text with font', function (t, done) { + it('text with font', async function (t) { const output = fixtures.path('output.text-with-font.png'); const text = sharp({ text: { @@ -123,17 +110,14 @@ describe('Text to image', function () { if (!sharp.versions.pango) { return t.skip(); } - text.toFile(output, function (err, info) { - if (err) throw err; - assert.strictEqual('png', info.format); - assert.strictEqual(3, info.channels); - assert.ok(info.width > 30); - assert.ok(info.height > 10); - done(); - }); + const info = await text.toFile(output); + assert.strictEqual('png', info.format); + assert.strictEqual(3, info.channels); + assert.ok(info.width > 30); + assert.ok(info.height > 10); }); - it('text with justify and composite', function (t, done) { + it('text with justify and composite', async function (t) { const output = fixtures.path('output.text-composite.png'); const width = 500; const dpi = 300; @@ -167,20 +151,15 @@ describe('Text to image', function () { if (!sharp.versions.pango) { return t.skip(); } - text.toFile(output, function (err, info) { - if (err) throw err; - assert.strictEqual('png', info.format); - assert.strictEqual(4, info.channels); - assert.strictEqual(width, info.width); - assert.strictEqual(true, info.premultiplied); - sharp(output).metadata(function (err, metadata) { - if (err) throw err; - assert.strictEqual('srgb', metadata.space); - assert.strictEqual('uchar', metadata.depth); - assert.strictEqual(true, metadata.hasAlpha); - done(); - }); - }); + const info = await text.toFile(output); + assert.strictEqual('png', info.format); + assert.strictEqual(4, info.channels); + assert.strictEqual(width, info.width); + assert.strictEqual(true, info.premultiplied); + const metadata = await sharp(output).metadata(); + assert.strictEqual('srgb', metadata.space); + assert.strictEqual('uchar', metadata.depth); + assert.strictEqual(true, metadata.hasAlpha); }); it('bad text input', function () { From 1f2f33d9a7eb8ffba91b8576e49a39df5fdebb76 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Thu, 30 Oct 2025 22:15:41 +0000 Subject: [PATCH 101/115] Ensure licensing headers are retained by code bundlers --- docs/build.mjs | 6 ++++-- install/build.js | 6 ++++-- install/check.js | 6 ++++-- lib/channel.js | 6 ++++-- lib/colour.js | 6 ++++-- lib/composite.js | 6 ++++-- lib/constructor.js | 6 ++++-- lib/index.js | 6 ++++-- lib/input.js | 6 ++++-- lib/is.js | 6 ++++-- lib/libvips.js | 6 ++++-- lib/operation.js | 6 ++++-- lib/output.js | 6 ++++-- lib/resize.js | 6 ++++-- lib/sharp.js | 6 ++++-- lib/utility.js | 6 ++++-- npm/from-local-build.js | 6 ++++-- src/common.cc | 6 ++++-- src/common.h | 6 ++++-- src/emscripten/pre.js | 6 ++++-- src/metadata.cc | 6 ++++-- src/metadata.h | 6 ++++-- src/operations.cc | 6 ++++-- src/pipeline.cc | 6 ++++-- src/pipeline.h | 6 ++++-- src/sharp.cc | 6 ++++-- src/stats.cc | 6 ++++-- src/stats.h | 6 ++++-- src/utilities.cc | 6 ++++-- src/utilities.h | 6 ++++-- test/bench/parallel.js | 6 ++++-- test/bench/perf.js | 6 ++++-- test/bench/random.js | 6 ++++-- test/fixtures/index.js | 6 ++++-- test/unit/affine.js | 6 ++++-- test/unit/alpha.js | 6 ++++-- test/unit/avif.js | 6 ++++-- test/unit/bandbool.js | 6 ++++-- test/unit/blur.js | 6 ++++-- test/unit/boolean.js | 6 ++++-- test/unit/clahe.js | 6 ++++-- test/unit/clone.js | 6 ++++-- test/unit/colourspace.js | 6 ++++-- test/unit/composite.js | 6 ++++-- test/unit/convolve.js | 6 ++++-- test/unit/extend.js | 6 ++++-- test/unit/extract.js | 6 ++++-- test/unit/extractChannel.js | 6 ++++-- test/unit/failOn.js | 6 ++++-- test/unit/fixtures.js | 6 ++++-- test/unit/gamma.js | 6 ++++-- test/unit/gif.js | 6 ++++-- test/unit/heif.js | 6 ++++-- test/unit/io.js | 6 ++++-- test/unit/join.js | 6 ++++-- test/unit/joinChannel.js | 6 ++++-- test/unit/jp2.js | 6 ++++-- test/unit/jpeg.js | 6 ++++-- test/unit/jxl.js | 6 ++++-- test/unit/libvips.js | 6 ++++-- test/unit/linear.js | 6 ++++-- test/unit/median.js | 6 ++++-- test/unit/metadata.js | 6 ++++-- test/unit/modulate.js | 6 ++++-- test/unit/negate.js | 6 ++++-- test/unit/noise.js | 6 ++++-- test/unit/normalize.js | 6 ++++-- test/unit/png.js | 6 ++++-- test/unit/raw.js | 6 ++++-- test/unit/recomb.js | 6 ++++-- test/unit/resize-contain.js | 6 ++++-- test/unit/resize-cover.js | 6 ++++-- test/unit/resize.js | 6 ++++-- test/unit/rotate.js | 6 ++++-- test/unit/sharpen.js | 6 ++++-- test/unit/stats.js | 6 ++++-- test/unit/svg.js | 6 ++++-- test/unit/text.js | 6 ++++-- test/unit/threshold.js | 6 ++++-- test/unit/tiff.js | 6 ++++-- test/unit/tile.js | 6 ++++-- test/unit/timeout.js | 6 ++++-- test/unit/tint.js | 6 ++++-- test/unit/toBuffer.js | 6 ++++-- test/unit/toFormat.js | 6 ++++-- test/unit/trim.js | 6 ++++-- test/unit/unflatten.js | 6 ++++-- test/unit/util.js | 6 ++++-- test/unit/webp.js | 6 ++++-- 89 files changed, 356 insertions(+), 178 deletions(-) diff --git a/docs/build.mjs b/docs/build.mjs index 522e6cd96..da43a5bf5 100644 --- a/docs/build.mjs +++ b/docs/build.mjs @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ import fs from 'node:fs/promises'; import path from 'node:path'; diff --git a/install/build.js b/install/build.js index 6af6541e1..2ca224586 100644 --- a/install/build.js +++ b/install/build.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { useGlobalLibvips, diff --git a/install/check.js b/install/check.js index d526e0883..1cfb7d32e 100644 --- a/install/check.js +++ b/install/check.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ try { const { useGlobalLibvips } = require('../lib/libvips'); diff --git a/lib/channel.js b/lib/channel.js index bb1368cb1..6af20db6b 100644 --- a/lib/channel.js +++ b/lib/channel.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const is = require('./is'); diff --git a/lib/colour.js b/lib/colour.js index b8b19b56b..f4c2a2b77 100644 --- a/lib/colour.js +++ b/lib/colour.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const color = require('@img/colour'); const is = require('./is'); diff --git a/lib/composite.js b/lib/composite.js index 1d41ba9d0..aab058965 100644 --- a/lib/composite.js +++ b/lib/composite.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const is = require('./is'); diff --git a/lib/constructor.js b/lib/constructor.js index 488b9f03b..f5aeeeb53 100644 --- a/lib/constructor.js +++ b/lib/constructor.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const util = require('node:util'); const stream = require('node:stream'); diff --git a/lib/index.js b/lib/index.js index cb632edfe..b80191d71 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const Sharp = require('./constructor'); require('./input')(Sharp); diff --git a/lib/input.js b/lib/input.js index 403ee31e3..27d24883a 100644 --- a/lib/input.js +++ b/lib/input.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const is = require('./is'); const sharp = require('./sharp'); diff --git a/lib/is.js b/lib/is.js index c61b6bbd9..58e29ee68 100644 --- a/lib/is.js +++ b/lib/is.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ /** * Is this value defined and not null? diff --git a/lib/libvips.js b/lib/libvips.js index dba1ab458..881dc5c13 100644 --- a/lib/libvips.js +++ b/lib/libvips.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { spawnSync } = require('node:child_process'); const { createHash } = require('node:crypto'); diff --git a/lib/operation.js b/lib/operation.js index 824da9110..183353fcc 100644 --- a/lib/operation.js +++ b/lib/operation.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const is = require('./is'); diff --git a/lib/output.js b/lib/output.js index 8718c6983..e10dc05b0 100644 --- a/lib/output.js +++ b/lib/output.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const path = require('node:path'); const is = require('./is'); diff --git a/lib/resize.js b/lib/resize.js index 287d0ae3f..7a643bb8e 100644 --- a/lib/resize.js +++ b/lib/resize.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const is = require('./is'); diff --git a/lib/sharp.js b/lib/sharp.js index 5cd4a40fb..1081c9314 100644 --- a/lib/sharp.js +++ b/lib/sharp.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ // Inspects the runtime environment and exports the relevant sharp.node binary diff --git a/lib/utility.js b/lib/utility.js index 6dd9b19f5..3ef27a6a1 100644 --- a/lib/utility.js +++ b/lib/utility.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const events = require('node:events'); const detectLibc = require('detect-libc'); diff --git a/npm/from-local-build.js b/npm/from-local-build.js index 76719cb3c..fc35bd2ed 100644 --- a/npm/from-local-build.js +++ b/npm/from-local-build.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ // Populate the npm package for the current platform with the local build diff --git a/src/common.cc b/src/common.cc index 5c517fc9e..a27c90c7c 100644 --- a/src/common.cc +++ b/src/common.cc @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ #include #include diff --git a/src/common.h b/src/common.h index 10b4e5490..16c07fc7c 100644 --- a/src/common.h +++ b/src/common.h @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ #ifndef SRC_COMMON_H_ #define SRC_COMMON_H_ diff --git a/src/emscripten/pre.js b/src/emscripten/pre.js index d37a487de..1163b9e77 100644 --- a/src/emscripten/pre.js +++ b/src/emscripten/pre.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ /* global Module, ENV, _vips_shutdown, _uv_library_shutdown */ diff --git a/src/metadata.cc b/src/metadata.cc index db582ca0d..73e3f930b 100644 --- a/src/metadata.cc +++ b/src/metadata.cc @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ #include #include diff --git a/src/metadata.h b/src/metadata.h index 64b5b9053..6f02d452c 100644 --- a/src/metadata.h +++ b/src/metadata.h @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ #ifndef SRC_METADATA_H_ #define SRC_METADATA_H_ diff --git a/src/operations.cc b/src/operations.cc index f60c99747..daeba5ab4 100644 --- a/src/operations.cc +++ b/src/operations.cc @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ #include #include diff --git a/src/pipeline.cc b/src/pipeline.cc index 4a848293d..5da169a15 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ #include #include diff --git a/src/pipeline.h b/src/pipeline.h index 14ee5456e..ff9465987 100644 --- a/src/pipeline.h +++ b/src/pipeline.h @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ #ifndef SRC_PIPELINE_H_ #define SRC_PIPELINE_H_ diff --git a/src/sharp.cc b/src/sharp.cc index ab873e807..7678975c9 100644 --- a/src/sharp.cc +++ b/src/sharp.cc @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ #include diff --git a/src/stats.cc b/src/stats.cc index cd5f4a385..b1fd27a7c 100644 --- a/src/stats.cc +++ b/src/stats.cc @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ #include #include diff --git a/src/stats.h b/src/stats.h index 9f99d8e9d..88e13c60c 100644 --- a/src/stats.h +++ b/src/stats.h @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ #ifndef SRC_STATS_H_ #define SRC_STATS_H_ diff --git a/src/utilities.cc b/src/utilities.cc index 2922ed46e..4154c08ac 100644 --- a/src/utilities.cc +++ b/src/utilities.cc @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ #include #include diff --git a/src/utilities.h b/src/utilities.h index 9272f9558..a1719fa23 100644 --- a/src/utilities.h +++ b/src/utilities.h @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ #ifndef SRC_UTILITIES_H_ #define SRC_UTILITIES_H_ diff --git a/test/bench/parallel.js b/test/bench/parallel.js index 7f2c4aaa9..ac8105c55 100644 --- a/test/bench/parallel.js +++ b/test/bench/parallel.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ process.env.UV_THREADPOOL_SIZE = 64; diff --git a/test/bench/perf.js b/test/bench/perf.js index c10802c7b..5ca09018e 100644 --- a/test/bench/perf.js +++ b/test/bench/perf.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const fs = require('node:fs'); const { execSync } = require('node:child_process'); diff --git a/test/bench/random.js b/test/bench/random.js index fa575d355..bc2f27dc8 100644 --- a/test/bench/random.js +++ b/test/bench/random.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const imagemagick = require('imagemagick'); const gm = require('gm'); diff --git a/test/fixtures/index.js b/test/fixtures/index.js index b57148755..f86041da6 100644 --- a/test/fixtures/index.js +++ b/test/fixtures/index.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const path = require('node:path'); const sharp = require('../../'); diff --git a/test/unit/affine.js b/test/unit/affine.js index 7c76776c1..43ff8ed92 100644 --- a/test/unit/affine.js +++ b/test/unit/affine.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/alpha.js b/test/unit/alpha.js index 3cb61aaa9..59e05f103 100644 --- a/test/unit/alpha.js +++ b/test/unit/alpha.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/avif.js b/test/unit/avif.js index 1c28a975a..6fb08c6fb 100644 --- a/test/unit/avif.js +++ b/test/unit/avif.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/bandbool.js b/test/unit/bandbool.js index 67574522e..a8678e767 100644 --- a/test/unit/bandbool.js +++ b/test/unit/bandbool.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/blur.js b/test/unit/blur.js index 41414bf2e..050168879 100644 --- a/test/unit/blur.js +++ b/test/unit/blur.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/boolean.js b/test/unit/boolean.js index c7fcdb4df..1e23068d7 100644 --- a/test/unit/boolean.js +++ b/test/unit/boolean.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const fs = require('node:fs'); const { describe, it } = require('node:test'); diff --git a/test/unit/clahe.js b/test/unit/clahe.js index a72770252..e3f7cf528 100644 --- a/test/unit/clahe.js +++ b/test/unit/clahe.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/clone.js b/test/unit/clone.js index 2075c5602..0b5b26e3b 100644 --- a/test/unit/clone.js +++ b/test/unit/clone.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const fs = require('node:fs'); const { afterEach, beforeEach, describe, it } = require('node:test'); diff --git a/test/unit/colourspace.js b/test/unit/colourspace.js index f373db341..cbcbfc783 100644 --- a/test/unit/colourspace.js +++ b/test/unit/colourspace.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/composite.js b/test/unit/composite.js index c442c8298..0df0007aa 100644 --- a/test/unit/composite.js +++ b/test/unit/composite.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/convolve.js b/test/unit/convolve.js index 29c7a8f63..6317e77be 100644 --- a/test/unit/convolve.js +++ b/test/unit/convolve.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/extend.js b/test/unit/extend.js index c36424d25..eba41440e 100644 --- a/test/unit/extend.js +++ b/test/unit/extend.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/extract.js b/test/unit/extract.js index d1e14ecb3..0901fcbe0 100644 --- a/test/unit/extract.js +++ b/test/unit/extract.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/extractChannel.js b/test/unit/extractChannel.js index 4f05c1ac8..d1bd1e1ce 100644 --- a/test/unit/extractChannel.js +++ b/test/unit/extractChannel.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/failOn.js b/test/unit/failOn.js index 9add6778e..460b53a1c 100644 --- a/test/unit/failOn.js +++ b/test/unit/failOn.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/fixtures.js b/test/unit/fixtures.js index ca975627a..b97edec39 100644 --- a/test/unit/fixtures.js +++ b/test/unit/fixtures.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/gamma.js b/test/unit/gamma.js index b58567c7a..4af5e0777 100644 --- a/test/unit/gamma.js +++ b/test/unit/gamma.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/gif.js b/test/unit/gif.js index 4921be725..976ad96b0 100644 --- a/test/unit/gif.js +++ b/test/unit/gif.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const fs = require('node:fs'); const { describe, it } = require('node:test'); diff --git a/test/unit/heif.js b/test/unit/heif.js index 9cb5355b1..adb7b2969 100644 --- a/test/unit/heif.js +++ b/test/unit/heif.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/io.js b/test/unit/io.js index 75a7959f5..4388507e7 100644 --- a/test/unit/io.js +++ b/test/unit/io.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const fs = require('node:fs'); const path = require('node:path'); diff --git a/test/unit/join.js b/test/unit/join.js index 6538346ff..3aea9ce36 100644 --- a/test/unit/join.js +++ b/test/unit/join.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/joinChannel.js b/test/unit/joinChannel.js index 814565ebf..e1b743151 100644 --- a/test/unit/joinChannel.js +++ b/test/unit/joinChannel.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/jp2.js b/test/unit/jp2.js index 3445c90f7..de70ab6f2 100644 --- a/test/unit/jp2.js +++ b/test/unit/jp2.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const fs = require('node:fs'); const { describe, it } = require('node:test'); diff --git a/test/unit/jpeg.js b/test/unit/jpeg.js index 0954439e8..a089e0a75 100644 --- a/test/unit/jpeg.js +++ b/test/unit/jpeg.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/jxl.js b/test/unit/jxl.js index 20af7de0c..f70de1cbb 100644 --- a/test/unit/jxl.js +++ b/test/unit/jxl.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/libvips.js b/test/unit/libvips.js index 79f70dc46..ee0c4f1d7 100644 --- a/test/unit/libvips.js +++ b/test/unit/libvips.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { after, before, describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/linear.js b/test/unit/linear.js index dba44a2e3..500d63326 100644 --- a/test/unit/linear.js +++ b/test/unit/linear.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const sharp = require('../../'); const fixtures = require('../fixtures'); diff --git a/test/unit/median.js b/test/unit/median.js index 5a2f6b3d3..97b706512 100644 --- a/test/unit/median.js +++ b/test/unit/median.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/metadata.js b/test/unit/metadata.js index 73875a54c..5ad41e20c 100644 --- a/test/unit/metadata.js +++ b/test/unit/metadata.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const fs = require('node:fs'); const { describe, it } = require('node:test'); diff --git a/test/unit/modulate.js b/test/unit/modulate.js index 502677629..fcf0935b2 100644 --- a/test/unit/modulate.js +++ b/test/unit/modulate.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const sharp = require('../../'); const { describe, it } = require('node:test'); diff --git a/test/unit/negate.js b/test/unit/negate.js index bd0c0a941..825f26700 100644 --- a/test/unit/negate.js +++ b/test/unit/negate.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/noise.js b/test/unit/noise.js index 3578fbec7..8a606a710 100644 --- a/test/unit/noise.js +++ b/test/unit/noise.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/normalize.js b/test/unit/normalize.js index 0c9a9b280..748b68343 100644 --- a/test/unit/normalize.js +++ b/test/unit/normalize.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/png.js b/test/unit/png.js index d5f487ae6..d7eb31218 100644 --- a/test/unit/png.js +++ b/test/unit/png.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const fs = require('node:fs'); const { describe, it } = require('node:test'); diff --git a/test/unit/raw.js b/test/unit/raw.js index 3d9c1b77b..7afca4284 100644 --- a/test/unit/raw.js +++ b/test/unit/raw.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/recomb.js b/test/unit/recomb.js index 78d1bf429..d16019f31 100644 --- a/test/unit/recomb.js +++ b/test/unit/recomb.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/resize-contain.js b/test/unit/resize-contain.js index ec5424c8d..dc5bdb410 100644 --- a/test/unit/resize-contain.js +++ b/test/unit/resize-contain.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/resize-cover.js b/test/unit/resize-cover.js index f5bdd5150..09ae42d62 100644 --- a/test/unit/resize-cover.js +++ b/test/unit/resize-cover.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/resize.js b/test/unit/resize.js index ce59d4d5e..ff6420104 100644 --- a/test/unit/resize.js +++ b/test/unit/resize.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/rotate.js b/test/unit/rotate.js index 6d8422c4f..ce8fe92f3 100644 --- a/test/unit/rotate.js +++ b/test/unit/rotate.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/sharpen.js b/test/unit/sharpen.js index 28b3db547..66eae7049 100644 --- a/test/unit/sharpen.js +++ b/test/unit/sharpen.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/stats.js b/test/unit/stats.js index 89102cd65..be42793d4 100644 --- a/test/unit/stats.js +++ b/test/unit/stats.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const fs = require('node:fs'); const { describe, it } = require('node:test'); diff --git a/test/unit/svg.js b/test/unit/svg.js index a12932ac5..a772bb378 100644 --- a/test/unit/svg.js +++ b/test/unit/svg.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const fs = require('node:fs'); const { describe, it } = require('node:test'); diff --git a/test/unit/text.js b/test/unit/text.js index d55031a0a..77a8177fd 100644 --- a/test/unit/text.js +++ b/test/unit/text.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/threshold.js b/test/unit/threshold.js index 350bf0b46..1b0956f5b 100644 --- a/test/unit/threshold.js +++ b/test/unit/threshold.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/tiff.js b/test/unit/tiff.js index fb0b0e528..6fc87b040 100644 --- a/test/unit/tiff.js +++ b/test/unit/tiff.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const fs = require('node:fs'); const { describe, it } = require('node:test'); diff --git a/test/unit/tile.js b/test/unit/tile.js index e496dba7c..77521bce3 100644 --- a/test/unit/tile.js +++ b/test/unit/tile.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const fs = require('node:fs'); const path = require('node:path'); diff --git a/test/unit/timeout.js b/test/unit/timeout.js index ed2012acd..d44179aa2 100644 --- a/test/unit/timeout.js +++ b/test/unit/timeout.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/tint.js b/test/unit/tint.js index 1e2ccf524..f7a168a78 100644 --- a/test/unit/tint.js +++ b/test/unit/tint.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/toBuffer.js b/test/unit/toBuffer.js index 40b2b0044..7e4b1d452 100644 --- a/test/unit/toBuffer.js +++ b/test/unit/toBuffer.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/toFormat.js b/test/unit/toFormat.js index 1d28efeaf..0974e4604 100644 --- a/test/unit/toFormat.js +++ b/test/unit/toFormat.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/trim.js b/test/unit/trim.js index b6b95e853..5df2aabcb 100644 --- a/test/unit/trim.js +++ b/test/unit/trim.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/unflatten.js b/test/unit/unflatten.js index 1759353a9..7a4423517 100644 --- a/test/unit/unflatten.js +++ b/test/unit/unflatten.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const sharp = require('../../'); diff --git a/test/unit/util.js b/test/unit/util.js index db74405c9..16c04a63c 100644 --- a/test/unit/util.js +++ b/test/unit/util.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const { describe, it } = require('node:test'); const assert = require('node:assert'); diff --git a/test/unit/webp.js b/test/unit/webp.js index e3d51cca0..b36c9a503 100644 --- a/test/unit/webp.js +++ b/test/unit/webp.js @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ const fs = require('node:fs'); const { describe, it } = require('node:test'); From 040b73ca746f4b8e71950708de4a464c7ba6a188 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Sat, 1 Nov 2025 10:12:13 +0000 Subject: [PATCH 102/115] Upgrade to libvips v8.17.3 --- .github/workflows/ci.yml | 2 +- biome.json | 2 +- docs/src/content/docs/changelog/v0.34.5.md | 2 ++ npm/darwin-arm64/package.json | 2 +- npm/darwin-x64/package.json | 2 +- npm/linux-arm/package.json | 2 +- npm/linux-arm64/package.json | 2 +- npm/linux-ppc64/package.json | 2 +- npm/linux-riscv64/package.json | 2 +- npm/linux-s390x/package.json | 2 +- npm/linux-x64/package.json | 2 +- npm/linuxmusl-arm64/package.json | 2 +- npm/linuxmusl-x64/package.json | 2 +- npm/wasm32/package.json | 2 +- package.json | 38 +++++++++++----------- src/common.h | 4 +-- src/operations.h | 6 ++-- test/unit/failOn.js | 2 +- test/unit/libvips.js | 2 +- test/unit/metadata.js | 24 ++++++++++---- 20 files changed, 59 insertions(+), 45 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b337e0bde..cd6838590 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -291,7 +291,7 @@ jobs: needs: lint name: "build-wasm32 [package]" runs-on: ubuntu-24.04 - container: "emscripten/emsdk:4.0.14" + container: "emscripten/emsdk:4.0.18" steps: - uses: actions/checkout@v4 - name: Dependencies diff --git a/biome.json b/biome.json index 2a79d5edf..a7d41490b 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.2.6/schema.json", + "$schema": "https://biomejs.dev/schemas/2.3.2/schema.json", "vcs": { "enabled": true, "clientKind": "git", diff --git a/docs/src/content/docs/changelog/v0.34.5.md b/docs/src/content/docs/changelog/v0.34.5.md index 0c4a936a3..8cfca9c9b 100644 --- a/docs/src/content/docs/changelog/v0.34.5.md +++ b/docs/src/content/docs/changelog/v0.34.5.md @@ -3,6 +3,8 @@ title: v0.34.5 - TBD slug: changelog/v0.34.5 --- +* Upgrade to libvips v8.17.3 for upstream bug fixes. + * Add experimental support for prebuilt Linux RISC-V 64-bit binaries. * Support building from source with npm v12+, deprecate `--build-from-source` flag. diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index da5ee34b3..f056b3bdd 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.3" + "@img/sharp-libvips-darwin-arm64": "1.2.4" }, "files": [ "lib" diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index 835d80a00..cdf02fe06 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.3" + "@img/sharp-libvips-darwin-x64": "1.2.4" }, "files": [ "lib" diff --git a/npm/linux-arm/package.json b/npm/linux-arm/package.json index 4872f3576..d32dc06bd 100644 --- a/npm/linux-arm/package.json +++ b/npm/linux-arm/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.3" + "@img/sharp-libvips-linux-arm": "1.2.4" }, "files": [ "lib" diff --git a/npm/linux-arm64/package.json b/npm/linux-arm64/package.json index 320764149..bd2c4587e 100644 --- a/npm/linux-arm64/package.json +++ b/npm/linux-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.3" + "@img/sharp-libvips-linux-arm64": "1.2.4" }, "files": [ "lib" diff --git a/npm/linux-ppc64/package.json b/npm/linux-ppc64/package.json index 7db2e1e70..8a2e183c2 100644 --- a/npm/linux-ppc64/package.json +++ b/npm/linux-ppc64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.2.3" + "@img/sharp-libvips-linux-ppc64": "1.2.4" }, "files": [ "lib" diff --git a/npm/linux-riscv64/package.json b/npm/linux-riscv64/package.json index dc3677353..076d2cdf5 100644 --- a/npm/linux-riscv64/package.json +++ b/npm/linux-riscv64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-riscv64": "1.2.3" + "@img/sharp-libvips-linux-riscv64": "1.2.4" }, "files": [ "lib" diff --git a/npm/linux-s390x/package.json b/npm/linux-s390x/package.json index ff0f657d1..6ba8a4555 100644 --- a/npm/linux-s390x/package.json +++ b/npm/linux-s390x/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.2.3" + "@img/sharp-libvips-linux-s390x": "1.2.4" }, "files": [ "lib" diff --git a/npm/linux-x64/package.json b/npm/linux-x64/package.json index 20996aaba..e613ddfad 100644 --- a/npm/linux-x64/package.json +++ b/npm/linux-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.3" + "@img/sharp-libvips-linux-x64": "1.2.4" }, "files": [ "lib" diff --git a/npm/linuxmusl-arm64/package.json b/npm/linuxmusl-arm64/package.json index da27e8ad6..3ab8537e3 100644 --- a/npm/linuxmusl-arm64/package.json +++ b/npm/linuxmusl-arm64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.3" + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" }, "files": [ "lib" diff --git a/npm/linuxmusl-x64/package.json b/npm/linuxmusl-x64/package.json index 3d2180614..83f7027d1 100644 --- a/npm/linuxmusl-x64/package.json +++ b/npm/linuxmusl-x64/package.json @@ -15,7 +15,7 @@ }, "preferUnplugged": true, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.3" + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" }, "files": [ "lib" diff --git a/npm/wasm32/package.json b/npm/wasm32/package.json index f6a40247b..f4fc25fd4 100644 --- a/npm/wasm32/package.json +++ b/npm/wasm32/package.json @@ -31,7 +31,7 @@ "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "dependencies": { - "@emnapi/runtime": "^1.5.0" + "@emnapi/runtime": "^1.6.0" }, "cpu": [ "wasm32" diff --git a/package.json b/package.json index 3f00bc09c..da083a492 100644 --- a/package.json +++ b/package.json @@ -146,16 +146,16 @@ "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.4", "@img/sharp-darwin-x64": "0.34.4", - "@img/sharp-libvips-darwin-arm64": "1.2.3", - "@img/sharp-libvips-darwin-x64": "1.2.3", - "@img/sharp-libvips-linux-arm": "1.2.3", - "@img/sharp-libvips-linux-arm64": "1.2.3", - "@img/sharp-libvips-linux-ppc64": "1.2.3", - "@img/sharp-libvips-linux-riscv64": "1.2.3", - "@img/sharp-libvips-linux-s390x": "1.2.3", - "@img/sharp-libvips-linux-x64": "1.2.3", - "@img/sharp-libvips-linuxmusl-arm64": "1.2.3", - "@img/sharp-libvips-linuxmusl-x64": "1.2.3", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.4", "@img/sharp-linux-arm64": "0.34.4", "@img/sharp-linux-ppc64": "0.34.4", @@ -170,16 +170,16 @@ "@img/sharp-win32-x64": "0.34.4" }, "devDependencies": { - "@biomejs/biome": "^2.2.6", + "@biomejs/biome": "^2.3.2", "@cpplint/cli": "^0.1.0", - "@emnapi/runtime": "^1.5.0", - "@img/sharp-libvips-dev": "1.2.3", - "@img/sharp-libvips-dev-wasm32": "1.2.3", - "@img/sharp-libvips-win32-arm64": "1.2.3", - "@img/sharp-libvips-win32-ia32": "1.2.3", - "@img/sharp-libvips-win32-x64": "1.2.3", + "@emnapi/runtime": "^1.6.0", + "@img/sharp-libvips-dev": "1.2.4", + "@img/sharp-libvips-dev-wasm32": "1.2.4", + "@img/sharp-libvips-win32-arm64": "1.2.4", + "@img/sharp-libvips-win32-ia32": "1.2.4", + "@img/sharp-libvips-win32-x64": "1.2.4", "@types/node": "*", - "emnapi": "^1.5.0", + "emnapi": "^1.6.0", "exif-reader": "^2.0.2", "extract-zip": "^2.0.1", "icc": "^3.0.0", @@ -194,7 +194,7 @@ "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "config": { - "libvips": ">=8.17.2" + "libvips": ">=8.17.3" }, "funding": { "url": "https://opencollective.com/libvips" diff --git a/src/common.h b/src/common.h index 16c07fc7c..c15755bb0 100644 --- a/src/common.h +++ b/src/common.h @@ -19,8 +19,8 @@ #if (VIPS_MAJOR_VERSION < 8) || \ (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION < 17) || \ - (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 17 && VIPS_MICRO_VERSION < 2) -#error "libvips version 8.17.2+ is required - please see https://sharp.pixelplumbing.com/install" + (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION == 17 && VIPS_MICRO_VERSION < 3) +#error "libvips version 8.17.3+ is required - please see https://sharp.pixelplumbing.com/install" #endif #if defined(__has_include) diff --git a/src/operations.h b/src/operations.h index 6582459ce..c281c02cd 100644 --- a/src/operations.h +++ b/src/operations.h @@ -1,5 +1,7 @@ -// Copyright 2013 Lovell Fuller and others. -// SPDX-License-Identifier: Apache-2.0 +/*! + Copyright 2013 Lovell Fuller and others. + SPDX-License-Identifier: Apache-2.0 +*/ #ifndef SRC_OPERATIONS_H_ #define SRC_OPERATIONS_H_ diff --git a/test/unit/failOn.js b/test/unit/failOn.js index 460b53a1c..f55791480 100644 --- a/test/unit/failOn.js +++ b/test/unit/failOn.js @@ -109,7 +109,7 @@ describe('failOn', () => { it('converts warnings to error for GeoTIFF', async () => { await assert.rejects( sharp(fixtures.inputTiffGeo).toBuffer(), - /Unknown field with tag 33550/ + /Tag 34737/ ); }); }); diff --git a/test/unit/libvips.js b/test/unit/libvips.js index ee0c4f1d7..6cab3cce1 100644 --- a/test/unit/libvips.js +++ b/test/unit/libvips.js @@ -180,7 +180,7 @@ describe('libvips binaries', function () { process.env.npm_config_arch = 's390x'; process.env.npm_config_libc = ''; const locatorHash = libvips.yarnLocator(); - assert.strictEqual(locatorHash, '7c141893d6'); + assert.strictEqual(locatorHash, '4ab19140fd'); delete process.env.npm_config_platform; delete process.env.npm_config_arch; delete process.env.npm_config_libc; diff --git a/test/unit/metadata.js b/test/unit/metadata.js index 5ad41e20c..75a6919c7 100644 --- a/test/unit/metadata.js +++ b/test/unit/metadata.js @@ -1013,13 +1013,23 @@ describe('Image metadata', function () { }); }); - it('Unsupported lossless JPEG passes underlying error message', function (_t, done) { - sharp(fixtures.inputJpgLossless) - .metadata(function (err) { - assert.strictEqual(true, !!err); - assert.strictEqual(true, /Input file has corrupt header: VipsJpeg: Unsupported JPEG process: SOF type 0xc3/.test(err.message)); - done(); - }); + it('Lossless JPEG', async () => { + const metadata = await sharp(fixtures.inputJpgLossless).metadata(); + assert.deepStrictEqual(metadata, { + format: 'jpeg', + width: 227, + height: 149, + space: 'srgb', + channels: 3, + depth: 'uchar', + density: 72, + chromaSubsampling: '4:4:4', + isProgressive: false, + isPalette: false, + hasProfile: false, + hasAlpha: false, + autoOrient: { width: 227, height: 149 } + }); }); it('keepExif maintains all EXIF metadata', async () => { From 09d5aa8cfa09522ddc67342295cb75ab1d044b09 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Sun, 2 Nov 2025 14:38:22 +0000 Subject: [PATCH 103/115] Docs: update internal and libvips doc links --- .github/CONTRIBUTING.md | 2 +- docs/package.json | 6 +++--- docs/src/content/docs/api-channel.md | 2 +- docs/src/content/docs/api-colour.md | 4 ++-- docs/src/content/docs/api-composite.md | 6 +++--- docs/src/content/docs/api-input.md | 6 +++--- docs/src/content/docs/api-operation.md | 2 +- docs/src/content/docs/api-output.md | 8 ++++---- docs/src/content/docs/api-utility.md | 2 +- lib/channel.js | 2 +- lib/colour.js | 6 +++--- lib/composite.js | 6 +++--- lib/input.js | 6 +++--- lib/operation.js | 6 +++--- lib/output.js | 16 ++++++++-------- lib/utility.js | 2 +- 16 files changed, 41 insertions(+), 41 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 6239e09a4..b65d48b98 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -14,7 +14,7 @@ If a [similar request](https://github.com/lovell/sharp/labels/enhancement) exist it's probably fastest to add a comment to it about your requirement. Implementation is usually straightforward if libvips -[already supports](https://www.libvips.org/API/current/func-list.html) +[already supports](https://www.libvips.org/API/current/function-list.html) the feature you need. ## Submit a Pull Request to fix a bug diff --git a/docs/package.json b/docs/package.json index 89bd0f291..7eaa41943 100644 --- a/docs/package.json +++ b/docs/package.json @@ -11,8 +11,8 @@ "astro": "astro" }, "dependencies": { - "@astrojs/starlight": "^0.35.2", - "astro": "^5.13.5", - "starlight-auto-sidebar": "^0.1.2" + "@astrojs/starlight": "^0.36.2", + "astro": "^5.15.3", + "starlight-auto-sidebar": "^0.1.3" } } diff --git a/docs/src/content/docs/api-channel.md b/docs/src/content/docs/api-channel.md index fb8ed3339..214e8611d 100644 --- a/docs/src/content/docs/api-channel.md +++ b/docs/src/content/docs/api-channel.md @@ -8,7 +8,7 @@ title: Channel manipulation Remove alpha channels, if any. This is a no-op if the image does not have an alpha channel. -See also [flatten](/api-operation#flatten). +See also [flatten](/api-operation/#flatten). **Example** diff --git a/docs/src/content/docs/api-colour.md b/docs/src/content/docs/api-colour.md index b1085ed2b..6fb81debd 100644 --- a/docs/src/content/docs/api-colour.md +++ b/docs/src/content/docs/api-colour.md @@ -80,7 +80,7 @@ as defined by [toColourspace](#tocolourspace). | Param | Type | Description | | --- | --- | --- | -| [colourspace] | string | pipeline colourspace e.g. `rgb16`, `scrgb`, `lab`, `grey16` [...](https://github.com/libvips/libvips/blob/41cff4e9d0838498487a00623462204eb10ee5b8/libvips/iofuncs/enumtypes.c#L774) | +| [colourspace] | string | pipeline colourspace e.g. `rgb16`, `scrgb`, `lab`, `grey16` [...](https://www.libvips.org/API/current/enum.Interpretation.html) | **Example** ```js @@ -123,7 +123,7 @@ By default output image will be web-friendly sRGB, with additional channels inte | Param | Type | Description | | --- | --- | --- | -| [colourspace] | string | output colourspace e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://github.com/libvips/libvips/blob/3c0bfdf74ce1dc37a6429bed47fa76f16e2cd70a/libvips/iofuncs/enumtypes.c#L777-L794) | +| [colourspace] | string | output colourspace e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://www.libvips.org/API/current/enum.Interpretation.html) | **Example** ```js diff --git a/docs/src/content/docs/api-composite.md b/docs/src/content/docs/api-composite.md index ea185ba0c..d4f9b8550 100644 --- a/docs/src/content/docs/api-composite.md +++ b/docs/src/content/docs/api-composite.md @@ -21,7 +21,7 @@ The `blend` option can be one of `clear`, `source`, `over`, `in`, `out`, `atop`, `hard-light`, `soft-light`, `difference`, `exclusion`. More information about blend modes can be found at -https://www.libvips.org/API/current/libvips-conversion.html#VipsBlendMode +https://www.libvips.org/API/current/enum.BlendMode.html and https://www.cairographics.org/operators/ @@ -64,8 +64,8 @@ and https://www.cairographics.org/operators/ | [images[].raw.height] | Number | | | | [images[].raw.channels] | Number | | | | [images[].animated] | boolean | false | Set to `true` to read all frames/pages of an animated image. | -| [images[].failOn] | string | "'warning'" | @see [constructor parameters](/api-constructor#parameters) | -| [images[].limitInputPixels] | number \| boolean | 268402689 | @see [constructor parameters](/api-constructor#parameters) | +| [images[].failOn] | string | "'warning'" | @see [constructor parameters](/api-constructor/) | +| [images[].limitInputPixels] | number \| boolean | 268402689 | @see [constructor parameters](/api-constructor/) | **Example** ```js diff --git a/docs/src/content/docs/api-input.md b/docs/src/content/docs/api-input.md index e460723ce..a5a9e3739 100644 --- a/docs/src/content/docs/api-input.md +++ b/docs/src/content/docs/api-input.md @@ -13,7 +13,7 @@ It does not take into consideration any operations to be applied to the output i such as resize or rotate. Dimensions in the response will respect the `page` and `pages` properties of the -[constructor parameters](/api-constructor#parameters). +[constructor parameters](/api-constructor/). A `Promise` is returned when `callback` is not provided. @@ -21,9 +21,9 @@ A `Promise` is returned when `callback` is not provided. - `size`: Total size of image in bytes, for Stream and Buffer input only - `width`: Number of pixels wide (EXIF orientation is not taken into consideration, see example below) - `height`: Number of pixels high (EXIF orientation is not taken into consideration, see example below) -- `space`: Name of colour space interpretation e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://www.libvips.org/API/current/VipsImage.html#VipsInterpretation) +- `space`: Name of colour space interpretation e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://www.libvips.org/API/current/enum.Interpretation.html) - `channels`: Number of bands e.g. `3` for sRGB, `4` for CMYK -- `depth`: Name of pixel depth format e.g. `uchar`, `char`, `ushort`, `float` [...](https://www.libvips.org/API/current/VipsImage.html#VipsBandFormat) +- `depth`: Name of pixel depth format e.g. `uchar`, `char`, `ushort`, `float` [...](https://www.libvips.org/API/current/enum.BandFormat.html) - `density`: Number of pixels per inch (DPI), if present - `chromaSubsampling`: String containing JPEG chroma subsampling, `4:2:0` or `4:4:4` for RGB, `4:2:0:4` or `4:4:4:4` for CMYK - `isProgressive`: Boolean indicating whether the image is interlaced using a progressive scan diff --git a/docs/src/content/docs/api-operation.md b/docs/src/content/docs/api-operation.md index dea7c79e3..abcb41fc1 100644 --- a/docs/src/content/docs/api-operation.md +++ b/docs/src/content/docs/api-operation.md @@ -179,7 +179,7 @@ When used without parameters, performs a fast, mild sharpen of the output image. When a `sigma` is provided, performs a slower, more accurate sharpen of the L channel in the LAB colour space. Fine-grained control over the level of sharpening in "flat" (m1) and "jagged" (m2) areas is available. -See [libvips sharpen](https://www.libvips.org/API/current/libvips-convolution.html#vips-sharpen) operation. +See [libvips sharpen](https://www.libvips.org/API/current/method.Image.sharpen.html) operation. **Throws**: diff --git a/docs/src/content/docs/api-output.md b/docs/src/content/docs/api-output.md index 800732a2b..8368e54dd 100644 --- a/docs/src/content/docs/api-output.md +++ b/docs/src/content/docs/api-output.md @@ -201,7 +201,7 @@ const dataWithMergedExif = await sharp(inputWithExif) Keep ICC profile from the input image in the output image. -Where necessary, will attempt to convert the output colour space to match the profile. +For non-RGB output use [toColourspace](/api-colour/#tocolourspace). **Since**: 0.33.0 @@ -430,7 +430,7 @@ Indexed PNG input at 1, 2 or 4 bits per pixel is converted to 8 bits per pixel. Set `palette` to `true` for slower, indexed PNG output. For 16 bits per pixel output, convert to `rgb16` via -[toColourspace](/api-colour#tocolourspace). +[toColourspace](/api-colour/#tocolourspace). **Throws**: @@ -589,7 +589,7 @@ Use these JP2 options for output image. Requires libvips compiled with support for OpenJPEG. The prebuilt binaries do not include this - see -[installing a custom libvips](https://sharp.pixelplumbing.com/install#custom-libvips). +[installing a custom libvips](/install#custom-libvips). **Throws**: @@ -754,7 +754,7 @@ This feature is experimental, please do not use in production systems. Requires libvips compiled with support for libjxl. The prebuilt binaries do not include this - see -[installing a custom libvips](https://sharp.pixelplumbing.com/install#custom-libvips). +[installing a custom libvips](/install/#custom-libvips). **Throws**: diff --git a/docs/src/content/docs/api-utility.md b/docs/src/content/docs/api-utility.md index b2ac16861..73190fd01 100644 --- a/docs/src/content/docs/api-utility.md +++ b/docs/src/content/docs/api-utility.md @@ -114,7 +114,7 @@ e.g. libaom manages its own 4 threads when encoding AVIF images, and these are independent of the value set here. :::note -Further [control over performance](/performance) is available. +Further [control over performance](/performance/) is available. ::: diff --git a/lib/channel.js b/lib/channel.js index 6af20db6b..9576ff834 100644 --- a/lib/channel.js +++ b/lib/channel.js @@ -18,7 +18,7 @@ const bool = { /** * Remove alpha channels, if any. This is a no-op if the image does not have an alpha channel. * - * See also {@link /api-operation#flatten|flatten}. + * See also {@link /api-operation/#flatten flatten}. * * @example * sharp('rgba.png') diff --git a/lib/colour.js b/lib/colour.js index f4c2a2b77..a606738cd 100644 --- a/lib/colour.js +++ b/lib/colour.js @@ -69,7 +69,7 @@ function grayscale (grayscale) { * * The input image will be converted to the provided colourspace at the start of the pipeline. * All operations will use this colourspace before converting to the output colourspace, - * as defined by {@link #tocolourspace|toColourspace}. + * as defined by {@link #tocolourspace toColourspace}. * * @since 0.29.0 * @@ -80,7 +80,7 @@ function grayscale (grayscale) { * .toColourspace('srgb') * .toFile('16bpc-pipeline-to-8bpc-output.png') * - * @param {string} [colourspace] - pipeline colourspace e.g. `rgb16`, `scrgb`, `lab`, `grey16` [...](https://github.com/libvips/libvips/blob/41cff4e9d0838498487a00623462204eb10ee5b8/libvips/iofuncs/enumtypes.c#L774) + * @param {string} [colourspace] - pipeline colourspace e.g. `rgb16`, `scrgb`, `lab`, `grey16` [...](https://www.libvips.org/API/current/enum.Interpretation.html) * @returns {Sharp} * @throws {Error} Invalid parameters */ @@ -112,7 +112,7 @@ function pipelineColorspace (colorspace) { * .toColourspace('rgb16') * .toFile('16-bpp.png') * - * @param {string} [colourspace] - output colourspace e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://github.com/libvips/libvips/blob/3c0bfdf74ce1dc37a6429bed47fa76f16e2cd70a/libvips/iofuncs/enumtypes.c#L777-L794) + * @param {string} [colourspace] - output colourspace e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://www.libvips.org/API/current/enum.Interpretation.html) * @returns {Sharp} * @throws {Error} Invalid parameters */ diff --git a/lib/composite.js b/lib/composite.js index aab058965..cd8037631 100644 --- a/lib/composite.js +++ b/lib/composite.js @@ -56,7 +56,7 @@ const blend = { * `hard-light`, `soft-light`, `difference`, `exclusion`. * * More information about blend modes can be found at - * https://www.libvips.org/API/current/libvips-conversion.html#VipsBlendMode + * https://www.libvips.org/API/current/enum.BlendMode.html * and https://www.cairographics.org/operators/ * * @since 0.22.0 @@ -123,8 +123,8 @@ const blend = { * @param {Number} [images[].raw.height] * @param {Number} [images[].raw.channels] * @param {boolean} [images[].animated=false] - Set to `true` to read all frames/pages of an animated image. - * @param {string} [images[].failOn='warning'] - @see {@link /api-constructor#parameters|constructor parameters} - * @param {number|boolean} [images[].limitInputPixels=268402689] - @see {@link /api-constructor#parameters|constructor parameters} + * @param {string} [images[].failOn='warning'] - @see {@link /api-constructor/ constructor parameters} + * @param {number|boolean} [images[].limitInputPixels=268402689] - @see {@link /api-constructor/ constructor parameters} * @returns {Sharp} * @throws {Error} Invalid parameters */ diff --git a/lib/input.js b/lib/input.js index 27d24883a..a3c13fff1 100644 --- a/lib/input.js +++ b/lib/input.js @@ -570,7 +570,7 @@ function _isStreamInput () { * such as resize or rotate. * * Dimensions in the response will respect the `page` and `pages` properties of the - * {@link /api-constructor#parameters|constructor parameters}. + * {@link /api-constructor/ constructor parameters}. * * A `Promise` is returned when `callback` is not provided. * @@ -578,9 +578,9 @@ function _isStreamInput () { * - `size`: Total size of image in bytes, for Stream and Buffer input only * - `width`: Number of pixels wide (EXIF orientation is not taken into consideration, see example below) * - `height`: Number of pixels high (EXIF orientation is not taken into consideration, see example below) - * - `space`: Name of colour space interpretation e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://www.libvips.org/API/current/VipsImage.html#VipsInterpretation) + * - `space`: Name of colour space interpretation e.g. `srgb`, `rgb`, `cmyk`, `lab`, `b-w` [...](https://www.libvips.org/API/current/enum.Interpretation.html) * - `channels`: Number of bands e.g. `3` for sRGB, `4` for CMYK - * - `depth`: Name of pixel depth format e.g. `uchar`, `char`, `ushort`, `float` [...](https://www.libvips.org/API/current/VipsImage.html#VipsBandFormat) + * - `depth`: Name of pixel depth format e.g. `uchar`, `char`, `ushort`, `float` [...](https://www.libvips.org/API/current/enum.BandFormat.html) * - `density`: Number of pixels per inch (DPI), if present * - `chromaSubsampling`: String containing JPEG chroma subsampling, `4:2:0` or `4:4:4` for RGB, `4:2:0:4` or `4:4:4:4` for CMYK * - `isProgressive`: Boolean indicating whether the image is interlaced using a progressive scan diff --git a/lib/operation.js b/lib/operation.js index 183353fcc..9b30efbe4 100644 --- a/lib/operation.js +++ b/lib/operation.js @@ -239,7 +239,7 @@ function affine (matrix, options) { * When a `sigma` is provided, performs a slower, more accurate sharpen of the L channel in the LAB colour space. * Fine-grained control over the level of sharpening in "flat" (m1) and "jagged" (m2) areas is available. * - * See {@link https://www.libvips.org/API/current/libvips-convolution.html#vips-sharpen|libvips sharpen} operation. + * See {@link https://www.libvips.org/API/current/method.Image.sharpen.html libvips sharpen} operation. * * @example * const data = await sharp(input).sharpen().toBuffer(); @@ -485,7 +485,7 @@ function erode (width) { /** * Merge alpha transparency channel, if any, with a background, then remove the alpha channel. * - * See also {@link /api-channel#removealpha|removeAlpha}. + * See also {@link /api-channel#removealpha removeAlpha}. * * @example * await sharp(rgbaInput) @@ -660,7 +660,7 @@ function normalize (options) { /** * Perform contrast limiting adaptive histogram equalization - * {@link https://en.wikipedia.org/wiki/Adaptive_histogram_equalization#Contrast_Limited_AHE|CLAHE}. + * {@link https://en.wikipedia.org/wiki/Adaptive_histogram_equalization#Contrast_Limited_AHE CLAHE}. * * This will, in general, enhance the clarity of the image by bringing out darker details. * diff --git a/lib/output.js b/lib/output.js index e10dc05b0..7ba8707c0 100644 --- a/lib/output.js +++ b/lib/output.js @@ -43,7 +43,7 @@ const bitdepthFromColourCount = (colours) => 1 << 31 - Math.clz32(Math.ceil(Math * Note that raw pixel data is only supported for buffer output. * * By default all metadata will be removed, which includes EXIF-based orientation. - * See {@link #withmetadata|withMetadata} for control over this. + * See {@link #withmetadata withMetadata} for control over this. * * The caller is responsible for ensuring directory structures and permissions exist. * @@ -97,12 +97,12 @@ function toFile (fileOut, callback) { * Write output to a Buffer. * JPEG, PNG, WebP, AVIF, TIFF, GIF and raw pixel data output are supported. * - * Use {@link #toformat|toFormat} or one of the format-specific functions such as {@link jpeg}, {@link png} etc. to set the output format. + * Use {@link #toformat toFormat} or one of the format-specific functions such as {@link #jpeg jpeg}, {@link #png png} etc. to set the output format. * * If no explicit format is set, the output format will match the input image, except SVG input which becomes PNG output. * * By default all metadata will be removed, which includes EXIF-based orientation. - * See {@link #withmetadata|withMetadata} for control over this. + * See {@link #withmetadata withMetadata} for control over this. * * `callback`, if present, gets three arguments `(err, data, info)` where: * - `err` is an error, if any. @@ -256,7 +256,7 @@ function withExifMerge (exif) { /** * Keep ICC profile from the input image in the output image. * - * Where necessary, will attempt to convert the output colour space to match the profile. + * For non-RGB output use {@link /api-colour/#tocolourspace toColourspace}. * * @since 0.33.0 * @@ -565,7 +565,7 @@ function jpeg (options) { * Set `palette` to `true` for slower, indexed PNG output. * * For 16 bits per pixel output, convert to `rgb16` via - * {@link /api-colour#tocolourspace|toColourspace}. + * {@link /api-colour/#tocolourspace toColourspace}. * * @example * // Convert any input to full colour PNG output @@ -850,7 +850,7 @@ function gif (options) { * * Requires libvips compiled with support for OpenJPEG. * The prebuilt binaries do not include this - see - * {@link https://sharp.pixelplumbing.com/install#custom-libvips installing a custom libvips}. + * {@link /install#custom-libvips installing a custom libvips}. * * @example * // Convert any input to lossless JP2 output @@ -959,7 +959,7 @@ function trySetAnimationOptions (source, target) { /** * Use these TIFF options for output image. * - * The `density` can be set in pixels/inch via {@link #withmetadata|withMetadata} + * The `density` can be set in pixels/inch via {@link #withmetadata withMetadata} * instead of providing `xres` and `yres` in pixels/mm. * * @example @@ -1194,7 +1194,7 @@ function heif (options) { * * Requires libvips compiled with support for libjxl. * The prebuilt binaries do not include this - see - * {@link https://sharp.pixelplumbing.com/install#custom-libvips installing a custom libvips}. + * {@link /install/#custom-libvips installing a custom libvips}. * * @since 0.31.3 * diff --git a/lib/utility.js b/lib/utility.js index 3ef27a6a1..6b445d7c6 100644 --- a/lib/utility.js +++ b/lib/utility.js @@ -136,7 +136,7 @@ cache(true); * and these are independent of the value set here. * * :::note - * Further {@link /performance|control over performance} is available. + * Further {@link /performance/ control over performance} is available. * ::: * * @example From 4f9f8179a6350448a32851e5daf5508d61c727ba Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Mon, 3 Nov 2025 21:14:45 +0000 Subject: [PATCH 104/115] Linter: apply all recommended biome settings Enforces previously-skipped useArrowFunction check --- biome.json | 7 +- lib/channel.js | 2 +- lib/colour.js | 2 +- lib/composite.js | 2 +- lib/constructor.js | 8 +- lib/input.js | 2 +- lib/is.js | 56 ++---- lib/operation.js | 6 +- lib/output.js | 2 +- lib/resize.js | 2 +- lib/utility.js | 2 +- package.json | 2 +- test/bench/parallel.js | 16 +- test/bench/perf.js | 256 +++++++++++++-------------- test/bench/random.js | 18 +- test/fixtures/index.js | 14 +- test/unit/alpha.js | 58 +++---- test/unit/bandbool.js | 20 +-- test/unit/blur.js | 46 ++--- test/unit/boolean.js | 30 ++-- test/unit/clahe.js | 68 ++++---- test/unit/clone.js | 20 +-- test/unit/colourspace.js | 38 ++-- test/unit/convolve.js | 28 +-- test/unit/dilate.js | 14 +- test/unit/erode.js | 14 +- test/unit/extend.js | 40 ++--- test/unit/extract.js | 114 ++++++------ test/unit/extractChannel.js | 34 ++-- test/unit/failOn.js | 20 +-- test/unit/fixtures.js | 16 +- test/unit/gamma.js | 30 ++-- test/unit/gif.js | 8 +- test/unit/io.js | 324 +++++++++++++++++----------------- test/unit/join.js | 2 +- test/unit/joinChannel.js | 46 ++--- test/unit/jp2.js | 12 +- test/unit/jpeg.js | 78 ++++----- test/unit/libvips.js | 48 +++--- test/unit/linear.js | 36 ++-- test/unit/median.js | 2 +- test/unit/metadata.js | 194 ++++++++++----------- test/unit/modulate.js | 10 +- test/unit/negate.js | 62 +++---- test/unit/noise.js | 56 +++--- test/unit/normalize.js | 56 +++--- test/unit/png.js | 72 ++++---- test/unit/raw.js | 76 ++++---- test/unit/recomb.js | 40 ++--- test/unit/resize-contain.js | 190 ++++++++++---------- test/unit/resize-cover.js | 80 ++++----- test/unit/resize.js | 252 +++++++++++++-------------- test/unit/rotate.js | 168 +++++++++--------- test/unit/sharpen.js | 40 ++--- test/unit/stats.js | 86 +++++---- test/unit/svg.js | 46 ++--- test/unit/text.js | 46 ++--- test/unit/threshold.js | 54 +++--- test/unit/tiff.js | 164 +++++++++--------- test/unit/tile.js | 336 ++++++++++++++++++------------------ test/unit/timeout.js | 2 +- test/unit/tint.js | 30 ++-- test/unit/trim.js | 22 +-- test/unit/unflatten.js | 14 +- test/unit/util.js | 56 +++--- test/unit/webp.js | 38 ++-- 66 files changed, 1823 insertions(+), 1910 deletions(-) diff --git a/biome.json b/biome.json index a7d41490b..a89282fbb 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.3.2/schema.json", + "$schema": "https://biomejs.dev/schemas/2.3.3/schema.json", "vcs": { "enabled": true, "clientKind": "git", @@ -11,10 +11,7 @@ "linter": { "enabled": true, "rules": { - "recommended": true, - "complexity": { - "useArrowFunction": "off" - } + "recommended": true } }, "formatter": { diff --git a/lib/channel.js b/lib/channel.js index 9576ff834..3c6c0b439 100644 --- a/lib/channel.js +++ b/lib/channel.js @@ -163,7 +163,7 @@ function bandbool (boolOp) { * @module Sharp * @private */ -module.exports = function (Sharp) { +module.exports = (Sharp) => { Object.assign(Sharp.prototype, { // Public instance functions removeAlpha, diff --git a/lib/colour.js b/lib/colour.js index a606738cd..e61c248a8 100644 --- a/lib/colour.js +++ b/lib/colour.js @@ -175,7 +175,7 @@ function _setBackgroundColourOption (key, value) { * @module Sharp * @private */ -module.exports = function (Sharp) { +module.exports = (Sharp) => { Object.assign(Sharp.prototype, { // Public tint, diff --git a/lib/composite.js b/lib/composite.js index cd8037631..1c3e5e629 100644 --- a/lib/composite.js +++ b/lib/composite.js @@ -206,7 +206,7 @@ function composite (images) { * @module Sharp * @private */ -module.exports = function (Sharp) { +module.exports = (Sharp) => { Sharp.prototype.composite = composite; Sharp.blend = blend; }; diff --git a/lib/constructor.js b/lib/constructor.js index f5aeeeb53..9aac8105c 100644 --- a/lib/constructor.js +++ b/lib/constructor.js @@ -12,6 +12,10 @@ require('./sharp'); // Use NODE_DEBUG=sharp to enable libvips warnings const debuglog = util.debuglog('sharp'); +const queueListener = (queueLength) => { + Sharp.queue.emit('change', queueLength); +}; + /** * Constructor factory to create an instance of `sharp`, to which further methods are chained. * @@ -398,9 +402,7 @@ const Sharp = function (input, options) { debuglog(warning); }, // Function to notify of queue length changes - queueListener: function (queueLength) { - Sharp.queue.emit('change', queueLength); - } + queueListener }; this.options.input = this._createInputDescriptor(input, options, { allowStream: true }); return this; diff --git a/lib/input.js b/lib/input.js index a3c13fff1..728b7188e 100644 --- a/lib/input.js +++ b/lib/input.js @@ -792,7 +792,7 @@ function stats (callback) { * @module Sharp * @private */ -module.exports = function (Sharp) { +module.exports = (Sharp) => { Object.assign(Sharp.prototype, { // Private _inputOptionsFromObject, diff --git a/lib/is.js b/lib/is.js index 58e29ee68..3ac9a1a35 100644 --- a/lib/is.js +++ b/lib/is.js @@ -7,55 +7,43 @@ * Is this value defined and not null? * @private */ -const defined = function (val) { - return typeof val !== 'undefined' && val !== null; -}; +const defined = (val) => typeof val !== 'undefined' && val !== null; /** * Is this value an object? * @private */ -const object = function (val) { - return typeof val === 'object'; -}; +const object = (val) => typeof val === 'object'; /** * Is this value a plain object? * @private */ -const plainObject = function (val) { - return Object.prototype.toString.call(val) === '[object Object]'; -}; +const plainObject = (val) => Object.prototype.toString.call(val) === '[object Object]'; /** * Is this value a function? * @private */ -const fn = function (val) { - return typeof val === 'function'; -}; +const fn = (val) => typeof val === 'function'; /** * Is this value a boolean? * @private */ -const bool = function (val) { - return typeof val === 'boolean'; -}; +const bool = (val) => typeof val === 'boolean'; /** * Is this value a Buffer object? * @private */ -const buffer = function (val) { - return val instanceof Buffer; -}; +const buffer = (val) => val instanceof Buffer; /** * Is this value a typed array object?. E.g. Uint8Array or Uint8ClampedArray? * @private */ -const typedArray = function (val) { +const typedArray = (val) => { if (defined(val)) { switch (val.constructor) { case Uint8Array: @@ -78,49 +66,37 @@ const typedArray = function (val) { * Is this value an ArrayBuffer object? * @private */ -const arrayBuffer = function (val) { - return val instanceof ArrayBuffer; -}; +const arrayBuffer = (val) => val instanceof ArrayBuffer; /** * Is this value a non-empty string? * @private */ -const string = function (val) { - return typeof val === 'string' && val.length > 0; -}; +const string = (val) => typeof val === 'string' && val.length > 0; /** * Is this value a real number? * @private */ -const number = function (val) { - return typeof val === 'number' && !Number.isNaN(val); -}; +const number = (val) => typeof val === 'number' && !Number.isNaN(val); /** * Is this value an integer? * @private */ -const integer = function (val) { - return Number.isInteger(val); -}; +const integer = (val) => Number.isInteger(val); /** * Is this value within an inclusive given range? * @private */ -const inRange = function (val, min, max) { - return val >= min && val <= max; -}; +const inRange = (val, min, max) => val >= min && val <= max; /** * Is this value within the elements of an array? * @private */ -const inArray = function (val, list) { - return list.includes(val); -}; +const inArray = (val, list) => list.includes(val); /** * Create an Error with a message relating to an invalid parameter. @@ -131,11 +107,9 @@ const inArray = function (val, list) { * @returns {Error} Containing the formatted message. * @private */ -const invalidParameterError = function (name, expected, actual) { - return new Error( +const invalidParameterError = (name, expected, actual) => new Error( `Expected ${expected} for ${name} but received ${actual} of type ${typeof actual}` ); -}; /** * Ensures an Error from C++ contains a JS stack. @@ -145,7 +119,7 @@ const invalidParameterError = function (name, expected, actual) { * @returns {Error} Error with message and stack. * @private */ -const nativeError = function (native, context) { +const nativeError = (native, context) => { context.message = native.message; return context; }; diff --git a/lib/operation.js b/lib/operation.js index 9b30efbe4..ebbf54e9c 100644 --- a/lib/operation.js +++ b/lib/operation.js @@ -742,9 +742,7 @@ function convolve (kernel) { } // Default scale is sum of kernel values if (!is.integer(kernel.scale)) { - kernel.scale = kernel.kernel.reduce(function (a, b) { - return a + b; - }, 0); + kernel.scale = kernel.kernel.reduce((a, b) => a + b, 0); } // Clip scale to a minimum value of 1 if (kernel.scale < 1) { @@ -989,7 +987,7 @@ function modulate (options) { * @module Sharp * @private */ -module.exports = function (Sharp) { +module.exports = (Sharp) => { Object.assign(Sharp.prototype, { autoOrient, rotate, diff --git a/lib/output.js b/lib/output.js index 7ba8707c0..dac7774ca 100644 --- a/lib/output.js +++ b/lib/output.js @@ -1623,7 +1623,7 @@ function _pipeline (callback, stack) { * @module Sharp * @private */ -module.exports = function (Sharp) { +module.exports = (Sharp) => { Object.assign(Sharp.prototype, { // Public toFile, diff --git a/lib/resize.js b/lib/resize.js index 7a643bb8e..544fbba3a 100644 --- a/lib/resize.js +++ b/lib/resize.js @@ -579,7 +579,7 @@ function trim (options) { * @module Sharp * @private */ -module.exports = function (Sharp) { +module.exports = (Sharp) => { Object.assign(Sharp.prototype, { resize, extend, diff --git a/lib/utility.js b/lib/utility.js index 6b445d7c6..c0ad39f86 100644 --- a/lib/utility.js +++ b/lib/utility.js @@ -277,7 +277,7 @@ function unblock (options) { * @module Sharp * @private */ -module.exports = function (Sharp) { +module.exports = (Sharp) => { Sharp.cache = cache; Sharp.concurrency = concurrency; Sharp.counters = counters; diff --git a/package.json b/package.json index da083a492..f992e7100 100644 --- a/package.json +++ b/package.json @@ -170,7 +170,7 @@ "@img/sharp-win32-x64": "0.34.4" }, "devDependencies": { - "@biomejs/biome": "^2.3.2", + "@biomejs/biome": "^2.3.3", "@cpplint/cli": "^0.1.0", "@emnapi/runtime": "^1.6.0", "@img/sharp-libvips-dev": "1.2.4", diff --git a/test/bench/parallel.js b/test/bench/parallel.js index ac8105c55..88d7d4bac 100644 --- a/test/bench/parallel.js +++ b/test/bench/parallel.js @@ -16,31 +16,29 @@ const height = 480; sharp.concurrency(1); -const timer = setInterval(function () { +const timer = setInterval(() => { console.dir(sharp.counters()); }, 100); -async.mapSeries([1, 1, 2, 4, 8, 16, 32, 64], function (parallelism, next) { +async.mapSeries([1, 1, 2, 4, 8, 16, 32, 64], (parallelism, next) => { const start = Date.now(); async.times(parallelism, - function (_id, callback) { - sharp(fixtures.inputJpg).resize(width, height).toBuffer(function (err, buffer) { + (_id, callback) => { + sharp(fixtures.inputJpg).resize(width, height).toBuffer((err, buffer) => { buffer = null; callback(err, Date.now() - start); }); }, - function (err, ids) { + (err, ids) => { assert(!err); assert(ids.length === parallelism); ids.sort(); - const mean = ids.reduce(function (a, b) { - return a + b; - }) / ids.length; + const mean = ids.reduce((a, b) => a + b) / ids.length; console.log(`${parallelism} parallel calls: fastest=${ids[0]}ms slowest=${ids[ids.length - 1]}ms mean=${mean}ms`); next(); } ); -}, function () { +}, () => { clearInterval(timer); console.dir(sharp.counters()); }); diff --git a/test/bench/perf.js b/test/bench/perf.js index 5ca09018e..375006ef0 100644 --- a/test/bench/perf.js +++ b/test/bench/perf.js @@ -45,13 +45,13 @@ console.log(`Detected ${physicalCores} physical cores`); sharp.concurrency(physicalCores); async.series({ - jpeg: function (callback) { + jpeg: (callback) => { const inputJpgBuffer = fs.readFileSync(fixtures.inputJpg); const jpegSuite = new Benchmark.Suite('jpeg'); // jimp jpegSuite.add('jimp-buffer-buffer', { defer: true, - fn: async function (deferred) { + fn: async (deferred) => { const image = await Jimp.read(inputJpgBuffer); await image .resize({ w: width, h: height, mode: Jimp.RESIZE_BICUBIC }) @@ -60,7 +60,7 @@ async.series({ } }).add('jimp-file-file', { defer: true, - fn: async function (deferred) { + fn: async (deferred) => { const image = await Jimp.read(fixtures.inputJpg); await image .resize({ w: width, h: height, mode: Jimp.RESIZE_BICUBIC }) @@ -71,14 +71,14 @@ async.series({ // mapnik mapnik && jpegSuite.add('mapnik-file-file', { defer: true, - fn: function (deferred) { - mapnik.Image.open(fixtures.inputJpg, function (err, img) { + fn: (deferred) => { + mapnik.Image.open(fixtures.inputJpg, (err, img) => { if (err) throw err; img .resize(width, height, { scaling_method: mapnik.imageScaling.lanczos }) - .save(outputJpg, 'jpeg:quality=80', function (err) { + .save(outputJpg, 'jpeg:quality=80', (err) => { if (err) throw err; deferred.resolve(); }); @@ -86,14 +86,14 @@ async.series({ } }).add('mapnik-buffer-buffer', { defer: true, - fn: function (deferred) { - mapnik.Image.fromBytes(inputJpgBuffer, { max_size: 3000 }, function (err, img) { + fn: (deferred) => { + mapnik.Image.fromBytes(inputJpgBuffer, { max_size: 3000 }, (err, img) => { if (err) throw err; img .resize(width, height, { scaling_method: mapnik.imageScaling.lanczos }) - .encode('jpeg:quality=80', function (err) { + .encode('jpeg:quality=80', (err) => { if (err) throw err; deferred.resolve(); }); @@ -103,7 +103,7 @@ async.series({ // imagemagick jpegSuite.add('imagemagick-file-file', { defer: true, - fn: function (deferred) { + fn: (deferred) => { imagemagick.resize({ srcPath: fixtures.inputJpg, dstPath: outputJpg, @@ -112,7 +112,7 @@ async.series({ height, format: 'jpg', filter: 'Lanczos' - }, function (err) { + }, (err) => { if (err) { throw err; } else { @@ -124,12 +124,12 @@ async.series({ // gm jpegSuite.add('gm-buffer-file', { defer: true, - fn: function (deferred) { + fn: (deferred) => { gm(inputJpgBuffer) .filter('Lanczos') .resize(width, height) .quality(80) - .write(outputJpg, function (err) { + .write(outputJpg, (err) => { if (err) { throw err; } else { @@ -139,12 +139,12 @@ async.series({ } }).add('gm-buffer-buffer', { defer: true, - fn: function (deferred) { + fn: (deferred) => { gm(inputJpgBuffer) .filter('Lanczos') .resize(width, height) .quality(80) - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -154,12 +154,12 @@ async.series({ } }).add('gm-file-file', { defer: true, - fn: function (deferred) { + fn: (deferred) => { gm(fixtures.inputJpg) .filter('Lanczos') .resize(width, height) .quality(80) - .write(outputJpg, function (err) { + .write(outputJpg, (err) => { if (err) { throw err; } else { @@ -169,12 +169,12 @@ async.series({ } }).add('gm-file-buffer', { defer: true, - fn: function (deferred) { + fn: (deferred) => { gm(fixtures.inputJpg) .filter('Lanczos') .resize(width, height) .quality(80) - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -186,17 +186,17 @@ async.series({ // tfjs tfjs && jpegSuite.add('tfjs-node-buffer-buffer', { defer: true, - fn: function (deferred) { + fn: (deferred) => { const decoded = tfjs.node.decodeJpeg(inputJpgBuffer); const resized = tfjs.image.resizeBilinear(decoded, [height, width]); tfjs .node .encodeJpeg(resized, 'rgb', 80) - .then(function () { + .then(() => { deferred.resolve(); tfjs.disposeVariables(); }) - .catch(function (err) { + .catch((err) => { throw err; }); } @@ -204,10 +204,10 @@ async.series({ // sharp jpegSuite.add('sharp-buffer-file', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(inputJpgBuffer) .resize(width, height) - .toFile(outputJpg, function (err) { + .toFile(outputJpg, (err) => { if (err) { throw err; } else { @@ -217,10 +217,10 @@ async.series({ } }).add('sharp-buffer-buffer', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(inputJpgBuffer) .resize(width, height) - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -230,10 +230,10 @@ async.series({ } }).add('sharp-file-file', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(fixtures.inputJpg) .resize(width, height) - .toFile(outputJpg, function (err) { + .toFile(outputJpg, (err) => { if (err) { throw err; } else { @@ -243,10 +243,10 @@ async.series({ } }).add('sharp-stream-stream', { defer: true, - fn: function (deferred) { + fn: (deferred) => { const readable = fs.createReadStream(fixtures.inputJpg); const writable = fs.createWriteStream(outputJpg); - writable.on('finish', function () { + writable.on('finish', () => { deferred.resolve(); }); const pipeline = sharp() @@ -255,10 +255,10 @@ async.series({ } }).add('sharp-file-buffer', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(fixtures.inputJpg) .resize(width, height) - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -268,34 +268,34 @@ async.series({ } }).add('sharp-promise', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(inputJpgBuffer) .resize(width, height) .toBuffer() - .then(function () { + .then(() => { deferred.resolve(); }) - .catch(function (err) { + .catch((err) => { throw err; }); } - }).on('cycle', function (event) { + }).on('cycle', (event) => { console.log(`jpeg ${String(event.target)}`); }).on('complete', function () { callback(null, this.filter('fastest').map('name')); }).run(); }, // Effect of applying operations - operations: function (callback) { + operations: (callback) => { const inputJpgBuffer = fs.readFileSync(fixtures.inputJpg); const operationsSuite = new Benchmark.Suite('operations'); operationsSuite.add('sharp-sharpen-mild', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(inputJpgBuffer) .resize(width, height) .sharpen() - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -305,11 +305,11 @@ async.series({ } }).add('sharp-sharpen-radius', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(inputJpgBuffer) .resize(width, height) .sharpen(3, 1, 3) - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -319,11 +319,11 @@ async.series({ } }).add('sharp-blur-mild', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(inputJpgBuffer) .resize(width, height) .blur() - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -333,11 +333,11 @@ async.series({ } }).add('sharp-blur-radius', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(inputJpgBuffer) .resize(width, height) .blur(3) - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -347,11 +347,11 @@ async.series({ } }).add('sharp-gamma', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(inputJpgBuffer) .resize(width, height) .gamma() - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -361,11 +361,11 @@ async.series({ } }).add('sharp-normalise', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(inputJpgBuffer) .resize(width, height) .normalise() - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -375,11 +375,11 @@ async.series({ } }).add('sharp-greyscale', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(inputJpgBuffer) .resize(width, height) .greyscale() - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -389,12 +389,12 @@ async.series({ } }).add('sharp-greyscale-gamma', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(inputJpgBuffer) .resize(width, height) .gamma() .greyscale() - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -404,11 +404,11 @@ async.series({ } }).add('sharp-progressive', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(inputJpgBuffer) .resize(width, height) .jpeg({ progressive: true }) - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -418,11 +418,11 @@ async.series({ } }).add('sharp-without-chroma-subsampling', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(inputJpgBuffer) .resize(width, height) .jpeg({ chromaSubsampling: '4:4:4' }) - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -432,11 +432,11 @@ async.series({ } }).add('sharp-rotate', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(inputJpgBuffer) .rotate(90) .resize(width, height) - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -446,11 +446,11 @@ async.series({ } }).add('sharp-without-simd', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp.simd(false); sharp(inputJpgBuffer) .resize(width, height) - .toBuffer(function (err) { + .toBuffer((err) => { sharp.simd(true); if (err) { throw err; @@ -461,10 +461,10 @@ async.series({ } }).add('sharp-random-access-read', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(inputJpgBuffer, { sequentialRead: false }) .resize(width, height) - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -474,13 +474,13 @@ async.series({ } }).add('sharp-crop-entropy', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(inputJpgBuffer) .resize(width, height, { fit: 'cover', position: sharp.strategy.entropy }) - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -490,13 +490,13 @@ async.series({ } }).add('sharp-crop-attention', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(inputJpgBuffer) .resize(width, height, { fit: 'cover', position: sharp.strategy.attention }) - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -504,21 +504,21 @@ async.series({ } }); } - }).on('cycle', function (event) { + }).on('cycle', (event) => { console.log(`operations ${String(event.target)}`); }).on('complete', function () { callback(null, this.filter('fastest').map('name')); }).run(); }, // Comparative speed of kernels - kernels: function (callback) { + kernels: (callback) => { const inputJpgBuffer = fs.readFileSync(fixtures.inputJpg); (new Benchmark.Suite('kernels')).add('sharp-cubic', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(inputJpgBuffer) .resize(width, height, { kernel: 'cubic' }) - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -528,10 +528,10 @@ async.series({ } }).add('sharp-lanczos2', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(inputJpgBuffer) .resize(width, height, { kernel: 'lanczos2' }) - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -541,10 +541,10 @@ async.series({ } }).add('sharp-lanczos3', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(inputJpgBuffer) .resize(width, height, { kernel: 'lanczos3' }) - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -554,10 +554,10 @@ async.series({ } }).add('sharp-mks2013', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(inputJpgBuffer) .resize(width, height, { kernel: 'mks2013' }) - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -567,10 +567,10 @@ async.series({ } }).add('sharp-mks2021', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(inputJpgBuffer) .resize(width, height, { kernel: 'mks2021' }) - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -578,21 +578,21 @@ async.series({ } }); } - }).on('cycle', function (event) { + }).on('cycle', (event) => { console.log(`kernels ${String(event.target)}`); }).on('complete', function () { callback(null, this.filter('fastest').map('name')); }).run(); }, // PNG - png: function (callback) { + png: (callback) => { const inputPngBuffer = fs.readFileSync(fixtures.inputPngAlphaPremultiplicationLarge); const pngSuite = new Benchmark.Suite('png'); const minSamples = 64; // jimp pngSuite.add('jimp-buffer-buffer', { defer: true, - fn: async function (deferred) { + fn: async (deferred) => { const image = await Jimp.read(inputPngBuffer); await image .resize({ w: width, h: heightPng, mode: Jimp.RESIZE_BICUBIC }) @@ -601,7 +601,7 @@ async.series({ } }).add('jimp-file-file', { defer: true, - fn: async function (deferred) { + fn: async (deferred) => { const image = await Jimp.read(fixtures.inputPngAlphaPremultiplicationLarge); await image .resize({ w: width, h: heightPng, mode: Jimp.RESIZE_BICUBIC }) @@ -612,18 +612,18 @@ async.series({ // mapnik mapnik && pngSuite.add('mapnik-file-file', { defer: true, - fn: function (deferred) { - mapnik.Image.open(fixtures.inputPngAlphaPremultiplicationLarge, function (err, img) { + fn: (deferred) => { + mapnik.Image.open(fixtures.inputPngAlphaPremultiplicationLarge, (err, img) => { if (err) throw err; - img.premultiply(function (err, img) { + img.premultiply((err, img) => { if (err) throw err; img.resize(width, heightPng, { scaling_method: mapnik.imageScaling.lanczos - }, function (err, img) { + }, (err, img) => { if (err) throw err; - img.demultiply(function (err, img) { + img.demultiply((err, img) => { if (err) throw err; - img.save(outputPng, 'png32:f=no:z=6', function (err) { + img.save(outputPng, 'png32:f=no:z=6', (err) => { if (err) throw err; deferred.resolve(); }); @@ -634,18 +634,18 @@ async.series({ } }).add('mapnik-buffer-buffer', { defer: true, - fn: function (deferred) { - mapnik.Image.fromBytes(inputPngBuffer, { max_size: 3000 }, function (err, img) { + fn: (deferred) => { + mapnik.Image.fromBytes(inputPngBuffer, { max_size: 3000 }, (err, img) => { if (err) throw err; - img.premultiply(function (err, img) { + img.premultiply((err, img) => { if (err) throw err; img.resize(width, heightPng, { scaling_method: mapnik.imageScaling.lanczos - }, function (err, img) { + }, (err, img) => { if (err) throw err; - img.demultiply(function (err, img) { + img.demultiply((err, img) => { if (err) throw err; - img.encode('png32:f=no:z=6', function (err) { + img.encode('png32:f=no:z=6', (err) => { if (err) throw err; deferred.resolve(); }); @@ -658,7 +658,7 @@ async.series({ // imagemagick pngSuite.add('imagemagick-file-file', { defer: true, - fn: function (deferred) { + fn: (deferred) => { imagemagick.resize({ srcPath: fixtures.inputPngAlphaPremultiplicationLarge, dstPath: outputPng, @@ -669,7 +669,7 @@ async.series({ '-define', 'PNG:compression-level=6', '-define', 'PNG:compression-filter=0' ] - }, function (err) { + }, (err) => { if (err) { throw err; } else { @@ -681,13 +681,13 @@ async.series({ // gm pngSuite.add('gm-file-file', { defer: true, - fn: function (deferred) { + fn: (deferred) => { gm(fixtures.inputPngAlphaPremultiplicationLarge) .filter('Lanczos') .resize(width, heightPng) .define('PNG:compression-level=6') .define('PNG:compression-filter=0') - .write(outputPng, function (err) { + .write(outputPng, (err) => { if (err) { throw err; } else { @@ -697,13 +697,13 @@ async.series({ } }).add('gm-file-buffer', { defer: true, - fn: function (deferred) { + fn: (deferred) => { gm(fixtures.inputPngAlphaPremultiplicationLarge) .filter('Lanczos') .resize(width, heightPng) .define('PNG:compression-level=6') .define('PNG:compression-filter=0') - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -716,11 +716,11 @@ async.series({ pngSuite.add('sharp-buffer-file', { defer: true, minSamples, - fn: function (deferred) { + fn: (deferred) => { sharp(inputPngBuffer) .resize(width, heightPng) .png({ compressionLevel: 6 }) - .toFile(outputPng, function (err) { + .toFile(outputPng, (err) => { if (err) { throw err; } else { @@ -731,11 +731,11 @@ async.series({ }).add('sharp-buffer-buffer', { defer: true, minSamples, - fn: function (deferred) { + fn: (deferred) => { sharp(inputPngBuffer) .resize(width, heightPng) .png({ compressionLevel: 6 }) - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -746,11 +746,11 @@ async.series({ }).add('sharp-file-file', { defer: true, minSamples, - fn: function (deferred) { + fn: (deferred) => { sharp(fixtures.inputPngAlphaPremultiplicationLarge) .resize(width, heightPng) .png({ compressionLevel: 6 }) - .toFile(outputPng, function (err) { + .toFile(outputPng, (err) => { if (err) { throw err; } else { @@ -761,11 +761,11 @@ async.series({ }).add('sharp-file-buffer', { defer: true, minSamples, - fn: function (deferred) { + fn: (deferred) => { sharp(fixtures.inputPngAlphaPremultiplicationLarge) .resize(width, heightPng) .png({ compressionLevel: 6 }) - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -776,11 +776,11 @@ async.series({ }).add('sharp-progressive', { defer: true, minSamples, - fn: function (deferred) { + fn: (deferred) => { sharp(inputPngBuffer) .resize(width, heightPng) .png({ compressionLevel: 6, progressive: true }) - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -791,11 +791,11 @@ async.series({ }).add('sharp-adaptiveFiltering', { defer: true, minSamples, - fn: function (deferred) { + fn: (deferred) => { sharp(inputPngBuffer) .resize(width, heightPng) .png({ adaptiveFiltering: true, compressionLevel: 6 }) - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -806,11 +806,11 @@ async.series({ }).add('sharp-compressionLevel=9', { defer: true, minSamples, - fn: function (deferred) { + fn: (deferred) => { sharp(inputPngBuffer) .resize(width, heightPng) .png({ compressionLevel: 9 }) - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -819,21 +819,21 @@ async.series({ }); } }); - pngSuite.on('cycle', function (event) { + pngSuite.on('cycle', (event) => { console.log(` png ${String(event.target)}`); }).on('complete', function () { callback(null, this.filter('fastest').map('name')); }).run(); }, // WebP - webp: function (callback) { + webp: (callback) => { const inputWebPBuffer = fs.readFileSync(fixtures.inputWebP); (new Benchmark.Suite('webp')).add('sharp-buffer-file', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(inputWebPBuffer) .resize(width, height) - .toFile(outputWebP, function (err) { + .toFile(outputWebP, (err) => { if (err) { throw err; } else { @@ -843,10 +843,10 @@ async.series({ } }).add('sharp-buffer-buffer', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(inputWebPBuffer) .resize(width, height) - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -856,10 +856,10 @@ async.series({ } }).add('sharp-file-file', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(fixtures.inputWebP) .resize(width, height) - .toFile(outputWebP, function (err) { + .toFile(outputWebP, (err) => { if (err) { throw err; } else { @@ -869,10 +869,10 @@ async.series({ } }).add('sharp-file-buffer', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(fixtures.inputWebP) .resize(width, height) - .toBuffer(function (err) { + .toBuffer((err) => { if (err) { throw err; } else { @@ -880,17 +880,17 @@ async.series({ } }); } - }).on('cycle', function (event) { + }).on('cycle', (event) => { console.log(`webp ${String(event.target)}`); }).on('complete', function () { callback(null, this.filter('fastest').map('name')); }).run(); } -}, function (err, results) { +}, (err, results) => { if (err) { throw err; } - Object.keys(results).forEach(function (format) { + Object.keys(results).forEach((format) => { if (results[format].toString().substr(0, 5) !== 'sharp') { console.log(`sharp was slower than ${results[format]} for ${format}`); } diff --git a/test/bench/random.js b/test/bench/random.js index bc2f27dc8..33a2198da 100644 --- a/test/bench/random.js +++ b/test/bench/random.js @@ -16,13 +16,11 @@ sharp.cache(false); const min = 320; const max = 960; -const randomDimension = function () { - return Math.ceil((Math.random() * (max - min)) + min); -}; +const randomDimension = () => Math.ceil((Math.random() * (max - min)) + min); new Benchmark.Suite('random').add('imagemagick', { defer: true, - fn: function (deferred) { + fn: (deferred) => { imagemagick.resize({ srcPath: fixtures.inputJpg, dstPath: fixtures.path('output.jpg'), @@ -31,7 +29,7 @@ new Benchmark.Suite('random').add('imagemagick', { height: randomDimension(), format: 'jpg', filter: 'Lanczos' - }, function (err) { + }, (err) => { if (err) { throw err; } else { @@ -41,12 +39,12 @@ new Benchmark.Suite('random').add('imagemagick', { } }).add('gm', { defer: true, - fn: function (deferred) { + fn: (deferred) => { gm(fixtures.inputJpg) .resize(randomDimension(), randomDimension()) .filter('Lanczos') .quality(80) - .toBuffer(function (err, buffer) { + .toBuffer((err, buffer) => { if (err) { throw err; } else { @@ -57,10 +55,10 @@ new Benchmark.Suite('random').add('imagemagick', { } }).add('sharp', { defer: true, - fn: function (deferred) { + fn: (deferred) => { sharp(fixtures.inputJpg) .resize(randomDimension(), randomDimension()) - .toBuffer(function (err, buffer) { + .toBuffer((err, buffer) => { if (err) { throw err; } else { @@ -69,7 +67,7 @@ new Benchmark.Suite('random').add('imagemagick', { } }); } -}).on('cycle', function (event) { +}).on('cycle', (event) => { console.log(String(event.target)); }).on('complete', function () { const winner = this.filter('fastest').map('name'); diff --git a/test/fixtures/index.js b/test/fixtures/index.js index f86041da6..2448843e2 100644 --- a/test/fixtures/index.js +++ b/test/fixtures/index.js @@ -8,9 +8,7 @@ const sharp = require('../../'); const maxColourDistance = require('../../lib/sharp')._maxColourDistance; // Helpers -const getPath = function (filename) { - return path.join(__dirname, filename); -}; +const getPath = (filename) => path.join(__dirname, filename); // Generates a 64-bit-as-binary-string image fingerprint // Based on the dHash gradient method - see http://www.hackerfactor.com/blog/index.php?/archives/529-Kind-of-Like-That.html @@ -22,7 +20,7 @@ async function fingerprint (image) { .resize(9, 8, { fit: sharp.fit.fill }) .raw() .toBuffer() - .then(function (data) { + .then((data) => { let fingerprint = ''; for (let col = 0; col < 8; col++) { for (let row = 0; row < 8; row++) { @@ -148,14 +146,12 @@ module.exports = { path: getPath, // Path for expected output images - expected: function (filename) { - return getPath(path.join('expected', filename)); - }, + expected: (filename) => getPath(path.join('expected', filename)), // Verify similarity of expected vs actual images via fingerprint // Specify distance threshold using `options={threshold: 42}`, default // `threshold` is 5; - assertSimilar: async function (expectedImage, actualImage, options, callback) { + assertSimilar: async (expectedImage, actualImage, options, callback) => { if (typeof options === 'function') { callback = options; options = {}; @@ -195,7 +191,7 @@ module.exports = { } }, - assertMaxColourDistance: function (actualImagePath, expectedImagePath, acceptedDistance) { + assertMaxColourDistance: (actualImagePath, expectedImagePath, acceptedDistance) => { if (typeof actualImagePath !== 'string') { throw new TypeError(`\`actualImagePath\` must be a string; got ${actualImagePath}`); } diff --git a/test/unit/alpha.js b/test/unit/alpha.js index 59e05f103..42e178098 100644 --- a/test/unit/alpha.js +++ b/test/unit/alpha.js @@ -8,12 +8,12 @@ const assert = require('node:assert'); const fixtures = require('../fixtures'); const sharp = require('../../'); -describe('Alpha transparency', function () { - it('Flatten to black', function (_t, done) { +describe('Alpha transparency', () => { + it('Flatten to black', (_t, done) => { sharp(fixtures.inputPngWithTransparency) .flatten() .resize(400, 300) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(400, info.width); assert.strictEqual(300, info.height); @@ -21,14 +21,14 @@ describe('Alpha transparency', function () { }); }); - it('Flatten to RGB orange', function (_t, done) { + it('Flatten to RGB orange', (_t, done) => { sharp(fixtures.inputPngWithTransparency) .resize(400, 300) .flatten({ background: { r: 255, g: 102, b: 0 } }) .jpeg({ chromaSubsampling: '4:4:4' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(400, info.width); assert.strictEqual(300, info.height); @@ -36,12 +36,12 @@ describe('Alpha transparency', function () { }); }); - it('Flatten to CSS/hex orange', function (_t, done) { + it('Flatten to CSS/hex orange', (_t, done) => { sharp(fixtures.inputPngWithTransparency) .resize(400, 300) .flatten({ background: '#ff6600' }) .jpeg({ chromaSubsampling: '4:4:4' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(400, info.width); assert.strictEqual(300, info.height); @@ -49,13 +49,13 @@ describe('Alpha transparency', function () { }); }); - it('Flatten 16-bit PNG with transparency to orange', function (_t, done) { + it('Flatten 16-bit PNG with transparency to orange', (_t, done) => { const output = fixtures.path('output.flatten-rgb16-orange.jpg'); sharp(fixtures.inputPngWithTransparency16bit) .flatten({ background: { r: 255, g: 102, b: 0 } }) - .toFile(output, function (err, info) { + .toFile(output, (err, info) => { if (err) throw err; assert.strictEqual(true, info.size > 0); assert.strictEqual(32, info.width); @@ -65,10 +65,10 @@ describe('Alpha transparency', function () { }); }); - it('Do not flatten', function (_t, done) { + it('Do not flatten', (_t, done) => { sharp(fixtures.inputPngWithTransparency) .flatten(false) - .toBuffer(function (err, _data, info) { + .toBuffer((err, _data, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(4, info.channels); @@ -76,10 +76,10 @@ describe('Alpha transparency', function () { }); }); - it('Ignored for JPEG', function (_t, done) { + it('Ignored for JPEG', (_t, done) => { sharp(fixtures.inputJpg) .flatten({ background: '#ff0000' }) - .toBuffer(function (err, _data, info) { + .toBuffer((err, _data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(3, info.channels); @@ -99,68 +99,60 @@ describe('Alpha transparency', function () { }); }); - it('Enlargement with non-nearest neighbor interpolation shouldn’t cause dark edges', function () { + it('Enlargement with non-nearest neighbor interpolation shouldn’t cause dark edges', () => { const base = 'alpha-premultiply-enlargement-2048x1536-paper.png'; const actual = fixtures.path(`output.${base}`); const expected = fixtures.expected(base); return sharp(fixtures.inputPngAlphaPremultiplicationSmall) .resize(2048, 1536) .toFile(actual) - .then(function () { + .then(() => { fixtures.assertMaxColourDistance(actual, expected, 102); }); }); - it('Reduction with non-nearest neighbor interpolation shouldn’t cause dark edges', function () { + it('Reduction with non-nearest neighbor interpolation shouldn’t cause dark edges', () => { const base = 'alpha-premultiply-reduction-1024x768-paper.png'; const actual = fixtures.path(`output.${base}`); const expected = fixtures.expected(base); return sharp(fixtures.inputPngAlphaPremultiplicationLarge) .resize(1024, 768) .toFile(actual) - .then(function () { + .then(() => { fixtures.assertMaxColourDistance(actual, expected, 102); }); }); - it('Removes alpha from fixtures with transparency, ignores those without', function () { - return Promise.all([ + it('Removes alpha from fixtures with transparency, ignores those without', () => Promise.all([ fixtures.inputPngWithTransparency, fixtures.inputPngWithTransparency16bit, fixtures.inputWebPWithTransparency, fixtures.inputJpg, fixtures.inputPng, fixtures.inputWebP - ].map(function (input) { - return sharp(input) + ].map((input) => sharp(input) .resize(10) .removeAlpha() .toBuffer({ resolveWithObject: true }) - .then(function (result) { + .then((result) => { assert.strictEqual(3, result.info.channels); - }); - })); - }); + })))); - it('Ensures alpha from fixtures without transparency, ignores those with', function () { - return Promise.all([ + it('Ensures alpha from fixtures without transparency, ignores those with', () => Promise.all([ fixtures.inputPngWithTransparency, fixtures.inputPngWithTransparency16bit, fixtures.inputWebPWithTransparency, fixtures.inputJpg, fixtures.inputPng, fixtures.inputWebP - ].map(function (input) { - return sharp(input) + ].map((input) => sharp(input) .resize(10) .ensureAlpha() .png() .toBuffer({ resolveWithObject: true }) - .then(function (result) { + .then((result) => { assert.strictEqual(4, result.info.channels); - }); - })); - }); + })))); it('Valid ensureAlpha value used for alpha channel', async () => { const background = { r: 255, g: 0, b: 0 }; diff --git a/test/unit/bandbool.js b/test/unit/bandbool.js index a8678e767..073fb68ba 100644 --- a/test/unit/bandbool.js +++ b/test/unit/bandbool.js @@ -8,18 +8,18 @@ const assert = require('node:assert'); const fixtures = require('../fixtures'); const sharp = require('../../'); -describe('Bandbool per-channel boolean operations', function () { +describe('Bandbool per-channel boolean operations', () => { [ sharp.bool.and, sharp.bool.or, sharp.bool.eor ] - .forEach(function (op) { - it(`${op} operation`, function (_t, done) { + .forEach((op) => { + it(`${op} operation`, (_t, done) => { sharp(fixtures.inputPngBooleanNoAlpha) .bandbool(op) .toColourspace('b-w') - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(200, info.width); assert.strictEqual(200, info.height); @@ -29,24 +29,24 @@ describe('Bandbool per-channel boolean operations', function () { }); }); - it('sRGB image retains 3 channels', function (_t, done) { + it('sRGB image retains 3 channels', (_t, done) => { sharp(fixtures.inputJpg) .bandbool('and') - .toBuffer(function (err, _data, info) { + .toBuffer((err, _data, info) => { if (err) throw err; assert.strictEqual(3, info.channels); done(); }); }); - it('Invalid operation', function () { - assert.throws(function () { + it('Invalid operation', () => { + assert.throws(() => { sharp().bandbool('fail'); }); }); - it('Missing operation', function () { - assert.throws(function () { + it('Missing operation', () => { + assert.throws(() => { sharp().bandbool(); }); }); diff --git a/test/unit/blur.js b/test/unit/blur.js index 050168879..f5132098b 100644 --- a/test/unit/blur.js +++ b/test/unit/blur.js @@ -9,12 +9,12 @@ const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); -describe('Blur', function () { - it('specific radius 1', function (_t, done) { +describe('Blur', () => { + it('specific radius 1', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .blur(1) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -23,11 +23,11 @@ describe('Blur', function () { }); }); - it('specific radius 10', function (_t, done) { + it('specific radius 10', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .blur(10) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -36,11 +36,11 @@ describe('Blur', function () { }); }); - it('specific options.sigma 10', function (_t, done) { + it('specific options.sigma 10', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .blur({ sigma: 10 }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -49,11 +49,11 @@ describe('Blur', function () { }); }); - it('specific radius 0.3', function (_t, done) { + it('specific radius 0.3', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .blur(0.3) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -62,11 +62,11 @@ describe('Blur', function () { }); }); - it('mild blur', function (_t, done) { + it('mild blur', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .blur() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -75,17 +75,17 @@ describe('Blur', function () { }); }); - it('invalid radius', function () { - assert.throws(function () { + it('invalid radius', () => { + assert.throws(() => { sharp(fixtures.inputJpg).blur(0.1); }); }); - it('blurred image is smaller than non-blurred', function (_t, done) { + it('blurred image is smaller than non-blurred', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .blur(false) - .toBuffer(function (err, notBlurred, info) { + .toBuffer((err, notBlurred, info) => { if (err) throw err; assert.strictEqual(true, notBlurred.length > 0); assert.strictEqual('jpeg', info.format); @@ -94,7 +94,7 @@ describe('Blur', function () { sharp(fixtures.inputJpg) .resize(320, 240) .blur(true) - .toBuffer(function (err, blurred, info) { + .toBuffer((err, blurred, info) => { if (err) throw err; assert.strictEqual(true, blurred.length > 0); assert.strictEqual(true, blurred.length < notBlurred.length); @@ -106,18 +106,18 @@ describe('Blur', function () { }); }); - it('invalid precision', function () { - assert.throws(function () { + it('invalid precision', () => { + assert.throws(() => { sharp(fixtures.inputJpg).blur({ sigma: 1, precision: 'invalid' }); }, /Expected one of: integer, float, approximate for precision but received invalid of type string/); }); - it('invalid minAmplitude', function () { - assert.throws(function () { + it('invalid minAmplitude', () => { + assert.throws(() => { sharp(fixtures.inputJpg).blur({ sigma: 1, minAmplitude: 0 }); }, /Expected number between 0.001 and 1 for minAmplitude but received 0 of type number/); - assert.throws(function () { + assert.throws(() => { sharp(fixtures.inputJpg).blur({ sigma: 1, minAmplitude: 1.01 }); }, /Expected number between 0.001 and 1 for minAmplitude but received 1.01 of type number/); }); @@ -150,8 +150,8 @@ describe('Blur', function () { await fixtures.assertSimilar(fixtures.expected('blur-10.jpg'), minAmplitudeLow); }); - it('options.sigma is required if options object is passed', function () { - assert.throws(function () { + it('options.sigma is required if options object is passed', () => { + assert.throws(() => { sharp(fixtures.inputJpg).blur({ precision: 'invalid' }); }, /Expected number between 0.3 and 1000 for options.sigma but received undefined of type undefined/); }); diff --git a/test/unit/boolean.js b/test/unit/boolean.js index 1e23068d7..f85b376da 100644 --- a/test/unit/boolean.js +++ b/test/unit/boolean.js @@ -10,7 +10,7 @@ const assert = require('node:assert'); const fixtures = require('../fixtures'); const sharp = require('../../'); -describe('Boolean operation between two images', function () { +describe('Boolean operation between two images', () => { const inputJpgBooleanTestBuffer = fs.readFileSync(fixtures.inputJpgBooleanTest); [ @@ -18,12 +18,12 @@ describe('Boolean operation between two images', function () { sharp.bool.or, sharp.bool.eor ] - .forEach(function (op) { - it(`${op} operation, file`, function (_t, done) { + .forEach((op) => { + it(`${op} operation, file`, (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .boolean(fixtures.inputJpgBooleanTest, op) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); @@ -31,11 +31,11 @@ describe('Boolean operation between two images', function () { }); }); - it(`${op} operation, buffer`, function (_t, done) { + it(`${op} operation, buffer`, (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .boolean(inputJpgBooleanTestBuffer, op) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); @@ -43,15 +43,15 @@ describe('Boolean operation between two images', function () { }); }); - it(`${op} operation, raw`, function (_t, done) { + it(`${op} operation, raw`, (_t, done) => { sharp(fixtures.inputJpgBooleanTest) .raw() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; sharp(fixtures.inputJpg) .resize(320, 240) .boolean(data, op, { raw: info }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); @@ -61,20 +61,20 @@ describe('Boolean operation between two images', function () { }); }); - it('Invalid operation', function () { - assert.throws(function () { + it('Invalid operation', () => { + assert.throws(() => { sharp().boolean(fixtures.inputJpgBooleanTest, 'fail'); }); }); - it('Invalid operation, non-string', function () { - assert.throws(function () { + it('Invalid operation, non-string', () => { + assert.throws(() => { sharp().boolean(fixtures.inputJpgBooleanTest, null); }); }); - it('Missing input', function () { - assert.throws(function () { + it('Missing input', () => { + assert.throws(() => { sharp().boolean(); }); }); diff --git a/test/unit/clahe.js b/test/unit/clahe.js index e3f7cf528..f3d68ebbb 100644 --- a/test/unit/clahe.js +++ b/test/unit/clahe.js @@ -9,132 +9,132 @@ const assert = require('node:assert'); const sharp = require('../../lib'); const fixtures = require('../fixtures'); -describe('Clahe', function () { - it('width 5 width 5 maxSlope 0', function (_t, done) { +describe('Clahe', () => { + it('width 5 width 5 maxSlope 0', (_t, done) => { sharp(fixtures.inputJpgClahe) .clahe({ width: 5, height: 5, maxSlope: 0 }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); fixtures.assertSimilar(fixtures.expected('clahe-5-5-0.jpg'), data, { threshold: 10 }, done); }); }); - it('width 5 width 5 maxSlope 5', function (_t, done) { + it('width 5 width 5 maxSlope 5', (_t, done) => { sharp(fixtures.inputJpgClahe) .clahe({ width: 5, height: 5, maxSlope: 5 }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); fixtures.assertSimilar(fixtures.expected('clahe-5-5-5.jpg'), data, done); }); }); - it('width 11 width 25 maxSlope 14', function (_t, done) { + it('width 11 width 25 maxSlope 14', (_t, done) => { sharp(fixtures.inputJpgClahe) .clahe({ width: 11, height: 25, maxSlope: 14 }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); fixtures.assertSimilar(fixtures.expected('clahe-11-25-14.jpg'), data, done); }); }); - it('width 50 width 50 maxSlope 0', function (_t, done) { + it('width 50 width 50 maxSlope 0', (_t, done) => { sharp(fixtures.inputJpgClahe) .clahe({ width: 50, height: 50, maxSlope: 0 }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); fixtures.assertSimilar(fixtures.expected('clahe-50-50-0.jpg'), data, done); }); }); - it('width 50 width 50 maxSlope 14', function (_t, done) { + it('width 50 width 50 maxSlope 14', (_t, done) => { sharp(fixtures.inputJpgClahe) .clahe({ width: 50, height: 50, maxSlope: 14 }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); fixtures.assertSimilar(fixtures.expected('clahe-50-50-14.jpg'), data, done); }); }); - it('width 100 width 50 maxSlope 3', function (_t, done) { + it('width 100 width 50 maxSlope 3', (_t, done) => { sharp(fixtures.inputJpgClahe) .clahe({ width: 100, height: 50, maxSlope: 3 }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); fixtures.assertSimilar(fixtures.expected('clahe-100-50-3.jpg'), data, done); }); }); - it('width 100 width 100 maxSlope 0', function (_t, done) { + it('width 100 width 100 maxSlope 0', (_t, done) => { sharp(fixtures.inputJpgClahe) .clahe({ width: 100, height: 100, maxSlope: 0 }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); fixtures.assertSimilar(fixtures.expected('clahe-100-100-0.jpg'), data, done); }); }); - it('invalid maxSlope', function () { - assert.throws(function () { + it('invalid maxSlope', () => { + assert.throws(() => { sharp(fixtures.inputJpgClahe).clahe({ width: 100, height: 100, maxSlope: -5 }); }); - assert.throws(function () { + assert.throws(() => { sharp(fixtures.inputJpgClahe).clahe({ width: 100, height: 100, maxSlope: 110 }); }); - assert.throws(function () { + assert.throws(() => { sharp(fixtures.inputJpgClahe).clahe({ width: 100, height: 100, maxSlope: 5.5 }); }); - assert.throws(function () { + assert.throws(() => { sharp(fixtures.inputJpgClahe).clahe({ width: 100, height: 100, maxSlope: 'a string' }); }); }); - it('invalid width', function () { - assert.throws(function () { + it('invalid width', () => { + assert.throws(() => { sharp(fixtures.inputJpgClahe).clahe({ width: 100.5, height: 100 }); }); - assert.throws(function () { + assert.throws(() => { sharp(fixtures.inputJpgClahe).clahe({ width: -5, height: 100 }); }); - assert.throws(function () { + assert.throws(() => { sharp(fixtures.inputJpgClahe).clahe({ width: true, height: 100 }); }); - assert.throws(function () { + assert.throws(() => { sharp(fixtures.inputJpgClahe).clahe({ width: 'string test', height: 100 }); }); }); - it('invalid height', function () { - assert.throws(function () { + it('invalid height', () => { + assert.throws(() => { sharp(fixtures.inputJpgClahe).clahe({ width: 100, height: 100.5 }); }); - assert.throws(function () { + assert.throws(() => { sharp(fixtures.inputJpgClahe).clahe({ width: 100, height: -5 }); }); - assert.throws(function () { + assert.throws(() => { sharp(fixtures.inputJpgClahe).clahe({ width: 100, height: true }); }); - assert.throws(function () { + assert.throws(() => { sharp(fixtures.inputJpgClahe).clahe({ width: 100, height: 'string test' }); }); }); - it('invalid options object', function () { - assert.throws(function () { + it('invalid options object', () => { + assert.throws(() => { sharp(fixtures.inputJpgClahe).clahe(100, 100, 5); }); }); - it('uses default maxSlope of 3', function (_t, done) { + it('uses default maxSlope of 3', (_t, done) => { sharp(fixtures.inputJpgClahe) .clahe({ width: 100, height: 50 }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); fixtures.assertSimilar(fixtures.expected('clahe-100-50-3.jpg'), data, done); diff --git a/test/unit/clone.js b/test/unit/clone.js index 0b5b26e3b..dae53b20b 100644 --- a/test/unit/clone.js +++ b/test/unit/clone.js @@ -10,21 +10,21 @@ const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); -describe('Clone', function () { - beforeEach(function () { +describe('Clone', () => { + beforeEach(() => { sharp.cache(false); }); - afterEach(function () { + afterEach(() => { sharp.cache(true); }); - it('Read from Stream and write to multiple Streams', function (_t, done) { + it('Read from Stream and write to multiple Streams', (_t, done) => { let finishEventsExpected = 2; // Output stream 1 const output1 = fixtures.path('output.multi-stream.1.jpg'); const writable1 = fs.createWriteStream(output1); - writable1.on('finish', function () { - sharp(output1).toBuffer(function (err, data, info) { + writable1.on('finish', () => { + sharp(output1).toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual(data.length, info.size); @@ -41,8 +41,8 @@ describe('Clone', function () { // Output stream 2 const output2 = fixtures.path('output.multi-stream.2.jpg'); const writable2 = fs.createWriteStream(output2); - writable2.on('finish', function () { - sharp(output2).toBuffer(function (err, data, info) { + writable2.on('finish', () => { + sharp(output2).toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual(data.length, info.size); @@ -65,14 +65,14 @@ describe('Clone', function () { fs.createReadStream(fixtures.inputJpg).pipe(rotator); }); - it('Stream-based input attaches finish event listener to original', function () { + it('Stream-based input attaches finish event listener to original', () => { const original = sharp(); const clone = original.clone(); assert.strictEqual(1, original.listenerCount('finish')); assert.strictEqual(0, clone.listenerCount('finish')); }); - it('Non Stream-based input does not attach finish event listeners', function () { + it('Non Stream-based input does not attach finish event listeners', () => { const original = sharp(fixtures.inputJpg); const clone = original.clone(); assert.strictEqual(0, original.listenerCount('finish')); diff --git a/test/unit/colourspace.js b/test/unit/colourspace.js index cbcbfc783..9c908051c 100644 --- a/test/unit/colourspace.js +++ b/test/unit/colourspace.js @@ -9,15 +9,15 @@ const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); -describe('Colour space conversion', function () { - it('To greyscale', function (_t, done) { +describe('Colour space conversion', () => { + it('To greyscale', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .greyscale() .toFile(fixtures.path('output.greyscale-gamma-0.0.jpg'), done); }); - it('To greyscale with gamma correction', function (_t, done) { + it('To greyscale with gamma correction', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .gamma() @@ -25,19 +25,19 @@ describe('Colour space conversion', function () { .toFile(fixtures.path('output.greyscale-gamma-2.2.jpg'), done); }); - it('Not to greyscale', function (_t, done) { + it('Not to greyscale', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .greyscale(false) .toFile(fixtures.path('output.greyscale-not.jpg'), done); }); - it('Greyscale with single channel output', function (_t, done) { + it('Greyscale with single channel output', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .greyscale() .toColourspace('b-w') - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(1, info.channels); assert.strictEqual(320, info.width); @@ -56,10 +56,10 @@ describe('Colour space conversion', function () { assert.strictEqual(format, 'webp'); }); - it('From CMYK to sRGB', function (_t, done) { + it('From CMYK to sRGB', (_t, done) => { sharp(fixtures.inputJpgWithCmykProfile) .resize(320) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -68,13 +68,13 @@ describe('Colour space conversion', function () { }); }); - it('From CMYK to sRGB with white background, not yellow', function (_t, done) { + it('From CMYK to sRGB with white background, not yellow', (_t, done) => { sharp(fixtures.inputJpgWithCmykProfile) .resize(320, 240, { fit: sharp.fit.contain, background: 'white' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -83,10 +83,10 @@ describe('Colour space conversion', function () { }); }); - it('From profile-less CMYK to sRGB', function (_t, done) { + it('From profile-less CMYK to sRGB', (_t, done) => { sharp(fixtures.inputJpgWithCmykNoProfile) .resize(320) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -130,7 +130,7 @@ describe('Colour space conversion', function () { .pipelineColourspace('cmyk') .withIccProfile(fixtures.path('XCMYK 2017.icc')) .negate() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('tiff', info.format); assert.strictEqual(320, info.width); @@ -144,13 +144,13 @@ describe('Colour space conversion', function () { }); }); - it('From sRGB with RGB16 pipeline, resize with gamma, to sRGB', function (_t, done) { + it('From sRGB with RGB16 pipeline, resize with gamma, to sRGB', (_t, done) => { sharp(fixtures.inputPngGradients) .pipelineColourspace('rgb16') .resize(320) .gamma() .toColourspace('srgb') - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(320, info.width); fixtures.assertSimilar(fixtures.expected('colourspace-gradients-gamma-resize.png'), data, { @@ -178,15 +178,15 @@ describe('Colour space conversion', function () { assert.strictEqual(b, 34); }); - it('Invalid pipelineColourspace input', function () { - assert.throws(function () { + it('Invalid pipelineColourspace input', () => { + assert.throws(() => { sharp(fixtures.inputJpg) .pipelineColorspace(null); }, /Expected string for colourspace but received null of type object/); }); - it('Invalid toColourspace input', function () { - assert.throws(function () { + it('Invalid toColourspace input', () => { + assert.throws(() => { sharp(fixtures.inputJpg) .toColourspace(null); }); diff --git a/test/unit/convolve.js b/test/unit/convolve.js index 6317e77be..bc430178a 100644 --- a/test/unit/convolve.js +++ b/test/unit/convolve.js @@ -9,8 +9,8 @@ const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); -describe('Convolve', function () { - it('specific convolution kernel 1', function (_t, done) { +describe('Convolve', () => { + it('specific convolution kernel 1', (_t, done) => { sharp(fixtures.inputPngStripesV) .convolve({ width: 3, @@ -23,7 +23,7 @@ describe('Convolve', function () { 10, 20, 10 ] }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(320, info.width); @@ -32,7 +32,7 @@ describe('Convolve', function () { }); }); - it('specific convolution kernel 2', function (_t, done) { + it('specific convolution kernel 2', (_t, done) => { sharp(fixtures.inputPngStripesH) .convolve({ width: 3, @@ -43,7 +43,7 @@ describe('Convolve', function () { 1, 0, 1 ] }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(320, info.width); @@ -52,7 +52,7 @@ describe('Convolve', function () { }); }); - it('horizontal Sobel operator', function (_t, done) { + it('horizontal Sobel operator', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .convolve({ @@ -64,7 +64,7 @@ describe('Convolve', function () { -1, 0, 1 ] }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -73,14 +73,14 @@ describe('Convolve', function () { }); }); - describe('invalid kernel specification', function () { - it('missing', function () { - assert.throws(function () { + describe('invalid kernel specification', () => { + it('missing', () => { + assert.throws(() => { sharp(fixtures.inputJpg).convolve({}); }); }); - it('incorrect data format', function () { - assert.throws(function () { + it('incorrect data format', () => { + assert.throws(() => { sharp(fixtures.inputJpg).convolve({ width: 3, height: 3, @@ -88,8 +88,8 @@ describe('Convolve', function () { }); }); }); - it('incorrect dimensions', function () { - assert.throws(function () { + it('incorrect dimensions', () => { + assert.throws(() => { sharp(fixtures.inputJpg).convolve({ width: 3, height: 4, diff --git a/test/unit/dilate.js b/test/unit/dilate.js index d3de3b47b..f1f982cb6 100644 --- a/test/unit/dilate.js +++ b/test/unit/dilate.js @@ -4,11 +4,11 @@ const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); -describe('Dilate', function () { - it('dilate 1 png', function (_t, done) { +describe('Dilate', () => { + it('dilate 1 png', (_t, done) => { sharp(fixtures.inputPngDotAndLines) .dilate(1) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(100, info.width); @@ -17,10 +17,10 @@ describe('Dilate', function () { }); }); - it('dilate 1 png - default width', function (_t, done) { + it('dilate 1 png - default width', (_t, done) => { sharp(fixtures.inputPngDotAndLines) .dilate() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(100, info.width); @@ -29,8 +29,8 @@ describe('Dilate', function () { }); }); - it('invalid dilation width', function () { - assert.throws(function () { + it('invalid dilation width', () => { + assert.throws(() => { sharp(fixtures.inputJpg).dilate(-1); }); }); diff --git a/test/unit/erode.js b/test/unit/erode.js index 60d10e893..0afa874df 100644 --- a/test/unit/erode.js +++ b/test/unit/erode.js @@ -4,11 +4,11 @@ const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); -describe('Erode', function () { - it('erode 1 png', function (_t, done) { +describe('Erode', () => { + it('erode 1 png', (_t, done) => { sharp(fixtures.inputPngDotAndLines) .erode(1) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(100, info.width); @@ -17,10 +17,10 @@ describe('Erode', function () { }); }); - it('erode 1 png - default width', function (_t, done) { + it('erode 1 png - default width', (_t, done) => { sharp(fixtures.inputPngDotAndLines) .erode() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(100, info.width); @@ -29,8 +29,8 @@ describe('Erode', function () { }); }); - it('invalid erosion width', function () { - assert.throws(function () { + it('invalid erosion width', () => { + assert.throws(() => { sharp(fixtures.inputJpg).erode(-1); }); }); diff --git a/test/unit/extend.js b/test/unit/extend.js index eba41440e..f9d91112a 100644 --- a/test/unit/extend.js +++ b/test/unit/extend.js @@ -9,13 +9,13 @@ const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); -describe('Extend', function () { - describe('extend all sides equally via a single value', function () { - it('JPEG', function (_t, done) { +describe('Extend', () => { + describe('extend all sides equally via a single value', () => { + it('JPEG', (_t, done) => { sharp(fixtures.inputJpg) .resize(120) .extend(10) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(140, info.width); assert.strictEqual(118, info.height); @@ -23,11 +23,11 @@ describe('Extend', function () { }); }); - it('Animated WebP', function (_t, done) { + it('Animated WebP', (_t, done) => { sharp(fixtures.inputWebPAnimated, { pages: -1 }) .resize(120) .extend(10) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(140, info.width); assert.strictEqual(140 * 9, info.height); @@ -37,7 +37,7 @@ describe('Extend', function () { }); ['background', 'copy', 'mirror', 'repeat'].forEach(extendWith => { - it(`extends all sides with animated WebP (${extendWith})`, function (_t, done) { + it(`extends all sides with animated WebP (${extendWith})`, (_t, done) => { sharp(fixtures.inputWebPAnimated, { pages: -1 }) .resize(120) .extend({ @@ -47,7 +47,7 @@ describe('Extend', function () { left: 40, right: 40 }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(200, info.width); assert.strictEqual(200 * 9, info.height); @@ -55,7 +55,7 @@ describe('Extend', function () { }); }); - it(`extend all sides equally with RGB (${extendWith})`, function (_t, done) { + it(`extend all sides equally with RGB (${extendWith})`, (_t, done) => { sharp(fixtures.inputJpg) .resize(120) .extend({ @@ -66,7 +66,7 @@ describe('Extend', function () { right: 10, background: { r: 255, g: 0, b: 0 } }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(140, info.width); assert.strictEqual(118, info.height); @@ -74,7 +74,7 @@ describe('Extend', function () { }); }); - it(`extend sides unequally with RGBA (${extendWith})`, function (_t, done) { + it(`extend sides unequally with RGBA (${extendWith})`, (_t, done) => { sharp(fixtures.inputPngWithTransparency16bit) .resize(120) .extend({ @@ -84,7 +84,7 @@ describe('Extend', function () { right: 35, background: { r: 0, g: 0, b: 0, alpha: 0 } }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(165, info.width); assert.strictEqual(170, info.height); @@ -92,7 +92,7 @@ describe('Extend', function () { }); }); - it(`PNG with 2 channels (${extendWith})`, function (_t, done) { + it(`PNG with 2 channels (${extendWith})`, (_t, done) => { sharp(fixtures.inputPngWithGreyAlpha) .extend({ extendWith, @@ -102,7 +102,7 @@ describe('Extend', function () { right: 80, background: 'transparent' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -147,13 +147,13 @@ describe('Extend', function () { assert.strictEqual(1470, height); }); - it('missing parameter fails', function () { - assert.throws(function () { + it('missing parameter fails', () => { + assert.throws(() => { sharp().extend(); }); }); - it('negative fails', function () { - assert.throws(function () { + it('negative fails', () => { + assert.throws(() => { sharp().extend(-1); }); }); @@ -191,7 +191,7 @@ describe('Extend', function () { assert.doesNotThrow(() => sharp().extend({ top: 1, left: 2, bottom: 3 })); }); - it('should add alpha channel before extending with a transparent Background', function (_t, done) { + it('should add alpha channel before extending with a transparent Background', (_t, done) => { sharp(fixtures.inputJpgWithLandscapeExif1) .extend({ bottom: 10, @@ -199,7 +199,7 @@ describe('Extend', function () { background: { r: 0, g: 0, b: 0, alpha: 0 } }) .toFormat(sharp.format.png) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(610, info.width); assert.strictEqual(460, info.height); diff --git a/test/unit/extract.js b/test/unit/extract.js index 0901fcbe0..4fee38f08 100644 --- a/test/unit/extract.js +++ b/test/unit/extract.js @@ -9,11 +9,11 @@ const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); -describe('Partial image extraction', function () { - it('JPEG', function (_t, done) { +describe('Partial image extraction', () => { + it('JPEG', (_t, done) => { sharp(fixtures.inputJpg) .extract({ left: 2, top: 2, width: 20, height: 20 }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(20, info.width); assert.strictEqual(20, info.height); @@ -21,10 +21,10 @@ describe('Partial image extraction', function () { }); }); - it('PNG', function (_t, done) { + it('PNG', (_t, done) => { sharp(fixtures.inputPng) .extract({ left: 200, top: 300, width: 400, height: 200 }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(400, info.width); assert.strictEqual(200, info.height); @@ -32,10 +32,10 @@ describe('Partial image extraction', function () { }); }); - it('WebP', function (_t, done) { + it('WebP', (_t, done) => { sharp(fixtures.inputWebP) .extract({ left: 100, top: 50, width: 125, height: 200 }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(125, info.width); assert.strictEqual(200, info.height); @@ -43,12 +43,12 @@ describe('Partial image extraction', function () { }); }); - describe('Animated WebP', function () { - it('Before resize', function (_t, done) { + describe('Animated WebP', () => { + it('Before resize', (_t, done) => { sharp(fixtures.inputWebPAnimated, { pages: -1 }) .extract({ left: 0, top: 30, width: 80, height: 20 }) .resize(320, 80) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(80 * 9, info.height); @@ -56,11 +56,11 @@ describe('Partial image extraction', function () { }); }); - it('After resize', function (_t, done) { + it('After resize', (_t, done) => { sharp(fixtures.inputWebPAnimated, { pages: -1 }) .resize(320, 320) .extract({ left: 0, top: 120, width: 320, height: 80 }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(80 * 9, info.height); @@ -69,10 +69,10 @@ describe('Partial image extraction', function () { }); }); - it('TIFF', function (_t, done) { + it('TIFF', (_t, done) => { sharp(fixtures.inputTiff) .extract({ left: 34, top: 63, width: 341, height: 529 }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(341, info.width); assert.strictEqual(529, info.height); @@ -80,11 +80,11 @@ describe('Partial image extraction', function () { }); }); - it('Before resize', function (_t, done) { + it('Before resize', (_t, done) => { sharp(fixtures.inputJpg) .extract({ left: 10, top: 10, width: 10, height: 500 }) .resize(100, 100) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(100, info.width); assert.strictEqual(100, info.height); @@ -92,13 +92,13 @@ describe('Partial image extraction', function () { }); }); - it('After resize and crop', function (_t, done) { + it('After resize and crop', (_t, done) => { sharp(fixtures.inputJpg) .resize(500, 500, { position: sharp.gravity.north }) .extract({ left: 10, top: 10, width: 100, height: 100 }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(100, info.width); assert.strictEqual(100, info.height); @@ -106,14 +106,14 @@ describe('Partial image extraction', function () { }); }); - it('Before and after resize and crop', function (_t, done) { + it('Before and after resize and crop', (_t, done) => { sharp(fixtures.inputJpg) .extract({ left: 0, top: 0, width: 700, height: 700 }) .resize(500, 500, { position: sharp.gravity.north }) .extract({ left: 10, top: 10, width: 100, height: 100 }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(100, info.width); assert.strictEqual(100, info.height); @@ -121,12 +121,12 @@ describe('Partial image extraction', function () { }); }); - it('Extract then rotate', function (_t, done) { + it('Extract then rotate', (_t, done) => { sharp(fixtures.inputPngWithGreyAlpha) .extract({ left: 20, top: 10, width: 380, height: 280 }) .rotate(90) .jpeg() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(280, info.width); assert.strictEqual(380, info.height); @@ -134,11 +134,11 @@ describe('Partial image extraction', function () { }); }); - it('Rotate then extract', function (_t, done) { + it('Rotate then extract', (_t, done) => { sharp(fixtures.inputPngWithGreyAlpha) .rotate(90) .extract({ left: 20, top: 10, width: 280, height: 380 }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(280, info.width); assert.strictEqual(380, info.height); @@ -146,12 +146,12 @@ describe('Partial image extraction', function () { }); }); - it('Extract then rotate then extract', function (_t, done) { + it('Extract then rotate then extract', (_t, done) => { sharp(fixtures.inputPngWithGreyAlpha) .extract({ left: 20, top: 10, width: 180, height: 280 }) .rotate(90) .extract({ left: 20, top: 10, width: 200, height: 100 }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(200, info.width); assert.strictEqual(100, info.height); @@ -159,12 +159,12 @@ describe('Partial image extraction', function () { }); }); - it('Extract then rotate non-90 anagle', function (_t, done) { + it('Extract then rotate non-90 anagle', (_t, done) => { sharp(fixtures.inputPngWithGreyAlpha) .extract({ left: 20, top: 10, width: 380, height: 280 }) .rotate(45) .jpeg() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(467, info.width); assert.strictEqual(467, info.height); @@ -172,12 +172,12 @@ describe('Partial image extraction', function () { }); }); - it('Rotate then extract non-90 angle', function (_t, done) { + it('Rotate then extract non-90 angle', (_t, done) => { sharp(fixtures.inputPngWithGreyAlpha) .rotate(45) .extract({ left: 20, top: 10, width: 380, height: 280 }) .jpeg() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(380, info.width); assert.strictEqual(280, info.height); @@ -220,11 +220,11 @@ describe('Partial image extraction', function () { image: fixtures.inputJpgWithLandscapeExif8 } ].forEach(({ name, image }) => { - it(name, function (_t, done) { + it(name, (_t, done) => { sharp(image) .rotate() .extract({ left: 0, top: 208, width: 60, height: 40 }) - .toBuffer(function (err, data) { + .toBuffer((err, data) => { if (err) throw err; fixtures.assertSimilar(fixtures.expected('rotate-mirror-extract.jpg'), data, done); }); @@ -232,67 +232,67 @@ describe('Partial image extraction', function () { }); }); - describe('Invalid parameters', function () { - describe('using the legacy extract(top,left,width,height) syntax', function () { - it('String top', function () { - assert.throws(function () { + describe('Invalid parameters', () => { + describe('using the legacy extract(top,left,width,height) syntax', () => { + it('String top', () => { + assert.throws(() => { sharp(fixtures.inputJpg).extract('spoons', 10, 10, 10); }); }); - it('Non-integral left', function () { - assert.throws(function () { + it('Non-integral left', () => { + assert.throws(() => { sharp(fixtures.inputJpg).extract(10, 10.2, 10, 10); }); }); - it('Negative width - negative', function () { - assert.throws(function () { + it('Negative width - negative', () => { + assert.throws(() => { sharp(fixtures.inputJpg).extract(10, 10, -10, 10); }); }); - it('Null height', function () { - assert.throws(function () { + it('Null height', () => { + assert.throws(() => { sharp(fixtures.inputJpg).extract(10, 10, 10, null); }); }); }); - it('Undefined', function () { - assert.throws(function () { + it('Undefined', () => { + assert.throws(() => { sharp(fixtures.inputJpg).extract(); }); }); - it('String top', function () { - assert.throws(function () { + it('String top', () => { + assert.throws(() => { sharp(fixtures.inputJpg).extract({ left: 10, top: 'spoons', width: 10, height: 10 }); }); }); - it('Non-integral left', function () { - assert.throws(function () { + it('Non-integral left', () => { + assert.throws(() => { sharp(fixtures.inputJpg).extract({ left: 10.2, top: 10, width: 10, height: 10 }); }); }); - it('Negative width - negative', function () { - assert.throws(function () { + it('Negative width - negative', () => { + assert.throws(() => { sharp(fixtures.inputJpg).extract({ left: 10, top: 10, width: -10, height: 10 }); }); }); - it('Null height', function () { - assert.throws(function () { + it('Null height', () => { + assert.throws(() => { sharp(fixtures.inputJpg).extract({ left: 10, top: 10, width: 10, height: null }); }); }); - it('Bad image area', function (_t, done) { + it('Bad image area', (_t, done) => { sharp(fixtures.inputJpg) .extract({ left: 3000, top: 10, width: 10, height: 10 }) - .toBuffer(function (err) { + .toBuffer((err) => { assert(err instanceof Error); assert.strictEqual(err.message, 'extract_area: bad extract area'); done(); @@ -302,7 +302,7 @@ describe('Partial image extraction', function () { it('Multiple extract emits warning', () => { let warningMessage = ''; const s = sharp(); - s.on('warning', function (msg) { warningMessage = msg; }); + s.on('warning', (msg) => { warningMessage = msg; }); const options = { top: 0, left: 0, width: 1, height: 1 }; s.extract(options).extract(options); assert.strictEqual(warningMessage, ''); @@ -313,7 +313,7 @@ describe('Partial image extraction', function () { it('Multiple rotate+extract emits warning', () => { let warningMessage = ''; const s = sharp().rotate(); - s.on('warning', function (msg) { warningMessage = msg; }); + s.on('warning', (msg) => { warningMessage = msg; }); const options = { top: 0, left: 0, width: 1, height: 1 }; s.extract(options).extract(options); assert.strictEqual(warningMessage, ''); @@ -324,7 +324,7 @@ describe('Partial image extraction', function () { it('Multiple extract+resize emits warning', () => { let warningMessage = ''; const s = sharp(); - s.on('warning', function (msg) { warningMessage = msg; }); + s.on('warning', (msg) => { warningMessage = msg; }); const options = { top: 0, left: 0, width: 1, height: 1 }; s.extract(options).extract(options); assert.strictEqual(warningMessage, ''); diff --git a/test/unit/extractChannel.js b/test/unit/extractChannel.js index d1bd1e1ce..761b816df 100644 --- a/test/unit/extractChannel.js +++ b/test/unit/extractChannel.js @@ -9,12 +9,12 @@ const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); -describe('Image channel extraction', function () { - it('Red channel', function (_t, done) { +describe('Image channel extraction', () => { + it('Red channel', (_t, done) => { sharp(fixtures.inputJpg) .extractChannel('red') .resize(320, 240) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); @@ -22,11 +22,11 @@ describe('Image channel extraction', function () { }); }); - it('Green channel', function (_t, done) { + it('Green channel', (_t, done) => { sharp(fixtures.inputJpg) .extractChannel('green') .resize(320, 240) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); @@ -34,11 +34,11 @@ describe('Image channel extraction', function () { }); }); - it('Blue channel', function (_t, done) { + it('Blue channel', (_t, done) => { sharp(fixtures.inputJpg) .extractChannel('blue') .resize(320, 240) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); @@ -46,11 +46,11 @@ describe('Image channel extraction', function () { }); }); - it('Blue channel by number', function (_t, done) { + it('Blue channel by number', (_t, done) => { sharp(fixtures.inputJpg) .extractChannel(2) .resize(320, 240) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); @@ -67,23 +67,23 @@ describe('Image channel extraction', function () { assert.strictEqual(chroma, 104); }); - it('Alpha from 16-bit PNG', function (_t, done) { + it('Alpha from 16-bit PNG', (_t, done) => { const output = fixtures.path('output.extract-alpha-16bit.png'); sharp(fixtures.inputPngWithTransparency16bit) .resize(16) .extractChannel(3) - .toFile(output, function (err) { + .toFile(output, (err) => { if (err) throw err; fixtures.assertMaxColourDistance(output, fixtures.expected('extract-alpha-16bit.png')); done(); }); }); - it('Alpha from 2-channel input', function (_t, done) { + it('Alpha from 2-channel input', (_t, done) => { const output = fixtures.path('output.extract-alpha-2-channel.png'); sharp(fixtures.inputPngWithGreyAlpha) .extractChannel('alpha') - .toFile(output, function (err, info) { + .toFile(output, (err, info) => { if (err) throw err; assert.strictEqual(1, info.channels); fixtures.assertMaxColourDistance(output, fixtures.expected('extract-alpha-2-channel.png')); @@ -91,15 +91,15 @@ describe('Image channel extraction', function () { }); }); - it('Invalid channel number', function () { - assert.throws(function () { + it('Invalid channel number', () => { + assert.throws(() => { sharp(fixtures.inputJpg) .extractChannel(-1); }); }); - it('No arguments', function () { - assert.throws(function () { + it('No arguments', () => { + assert.throws(() => { sharp(fixtures.inputJpg) .extractChannel(); }); diff --git a/test/unit/failOn.js b/test/unit/failOn.js index f55791480..c4d44e892 100644 --- a/test/unit/failOn.js +++ b/test/unit/failOn.js @@ -11,10 +11,10 @@ const sharp = require('../../lib'); const fixtures = require('../fixtures'); describe('failOn', () => { - it('handles truncated JPEG', function (_t, done) { + it('handles truncated JPEG', (_t, done) => { sharp(fixtures.inputJpgTruncated, { failOn: 'none' }) .resize(32, 24) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(32, info.width); @@ -23,17 +23,17 @@ describe('failOn', () => { }); }); - it('handles truncated PNG, emits warnings', function (_t, done) { + it('handles truncated PNG, emits warnings', (_t, done) => { let isWarningEmitted = false; sharp(fixtures.inputPngTruncated, { failOn: 'none' }) - .on('warning', function (warning) { + .on('warning', (warning) => { assert.ok( ['read gave 2 warnings', 'not enough data', 'end of stream'] .some(m => warning.includes(m))); isWarningEmitted = true; }) .resize(32, 24) - .toBuffer(function (err, _data, info) { + .toBuffer((err, _data, info) => { if (err) throw err; assert.strictEqual(true, isWarningEmitted); assert.strictEqual('png', info.format); @@ -71,8 +71,8 @@ describe('failOn', () => { ); }); - it('returns errors to callback for truncated JPEG', function (_t, done) { - sharp(fixtures.inputJpgTruncated, { failOn: 'truncated' }).toBuffer(function (err, data, info) { + it('returns errors to callback for truncated JPEG', (_t, done) => { + sharp(fixtures.inputJpgTruncated, { failOn: 'truncated' }).toBuffer((err, data, info) => { assert.ok(err.message.includes('VipsJpeg: premature end of'), err); assert.strictEqual(data, undefined); assert.strictEqual(info, undefined); @@ -80,8 +80,8 @@ describe('failOn', () => { }); }); - it('returns errors to callback for truncated PNG', function (_t, done) { - sharp(fixtures.inputPngTruncated, { failOn: 'truncated' }).toBuffer(function (err, data, info) { + it('returns errors to callback for truncated PNG', (_t, done) => { + sharp(fixtures.inputPngTruncated, { failOn: 'truncated' }).toBuffer((err, data, info) => { assert.ok(err.message.includes('read error'), err); assert.strictEqual(data, undefined); assert.strictEqual(info, undefined); @@ -89,7 +89,7 @@ describe('failOn', () => { }); }); - it('rejects promises for truncated JPEG', function (_t, done) { + it('rejects promises for truncated JPEG', (_t, done) => { sharp(fixtures.inputJpgTruncated, { failOn: 'error' }) .toBuffer() .then(() => { diff --git a/test/unit/fixtures.js b/test/unit/fixtures.js index b97edec39..9d4583ea2 100644 --- a/test/unit/fixtures.js +++ b/test/unit/fixtures.js @@ -7,23 +7,23 @@ const { describe, it } = require('node:test'); const assert = require('node:assert'); const fixtures = require('../fixtures'); -describe('Test fixtures', function () { - describe('assertMaxColourDistance', function () { - it('should throw an Error when images have a different number of channels', function () { - assert.throws(function () { +describe('Test fixtures', () => { + describe('assertMaxColourDistance', () => { + it('should throw an Error when images have a different number of channels', () => { + assert.throws(() => { fixtures.assertMaxColourDistance(fixtures.inputPngOverlayLayer1, fixtures.inputJpg); }); }); - it('should throw an Error when images have different dimensions', function () { - assert.throws(function () { + it('should throw an Error when images have different dimensions', () => { + assert.throws(() => { fixtures.assertMaxColourDistance(fixtures.inputJpg, fixtures.inputJpgWithExif); }); }); - it('should accept a zero threshold when comparing an image to itself', function () { + it('should accept a zero threshold when comparing an image to itself', () => { const image = fixtures.inputPngOverlayLayer0; fixtures.assertMaxColourDistance(image, image, 0); }); - it('should accept a numeric threshold for two different images', function () { + it('should accept a numeric threshold for two different images', () => { fixtures.assertMaxColourDistance(fixtures.inputPngOverlayLayer0, fixtures.inputPngOverlayLayer1, 100); }); }); diff --git a/test/unit/gamma.js b/test/unit/gamma.js index 4af5e0777..2e0b3fcde 100644 --- a/test/unit/gamma.js +++ b/test/unit/gamma.js @@ -9,11 +9,11 @@ const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); -describe('Gamma correction', function () { - it('value of 0.0 (disabled)', function (_t, done) { +describe('Gamma correction', () => { + it('value of 0.0 (disabled)', (_t, done) => { sharp(fixtures.inputJpgWithGammaHoliness) .resize(129, 111) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(129, info.width); @@ -22,11 +22,11 @@ describe('Gamma correction', function () { }); }); - it('value of 2.2 (default)', function (_t, done) { + it('value of 2.2 (default)', (_t, done) => { sharp(fixtures.inputJpgWithGammaHoliness) .resize(129, 111) .gamma() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(129, info.width); @@ -35,11 +35,11 @@ describe('Gamma correction', function () { }); }); - it('value of 3.0', function (_t, done) { + it('value of 3.0', (_t, done) => { sharp(fixtures.inputJpgWithGammaHoliness) .resize(129, 111) .gamma(3) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(129, info.width); @@ -48,11 +48,11 @@ describe('Gamma correction', function () { }); }); - it('input value of 2.2, output value of 3.0', function (_t, done) { + it('input value of 2.2, output value of 3.0', (_t, done) => { sharp(fixtures.inputJpgWithGammaHoliness) .resize(129, 111) .gamma(2.2, 3.0) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(129, info.width); @@ -61,12 +61,12 @@ describe('Gamma correction', function () { }); }); - it('alpha transparency', function (_t, done) { + it('alpha transparency', (_t, done) => { sharp(fixtures.inputPngOverlayLayer1) .resize(320) .gamma() .jpeg() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -74,14 +74,14 @@ describe('Gamma correction', function () { }); }); - it('invalid first parameter value', function () { - assert.throws(function () { + it('invalid first parameter value', () => { + assert.throws(() => { sharp(fixtures.inputJpgWithGammaHoliness).gamma(4); }); }); - it('invalid second parameter value', function () { - assert.throws(function () { + it('invalid second parameter value', () => { + assert.throws(() => { sharp(fixtures.inputJpgWithGammaHoliness).gamma(2.2, 4); }); }); diff --git a/test/unit/gif.js b/test/unit/gif.js index 976ad96b0..4b7d4a76a 100644 --- a/test/unit/gif.js +++ b/test/unit/gif.js @@ -199,11 +199,11 @@ describe('GIF input', () => { ); }); - it('should work with streams when only animated is set', function (_t, done) { + it('should work with streams when only animated is set', (_t, done) => { fs.createReadStream(fixtures.inputGifAnimated) .pipe(sharp({ animated: true })) .gif() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('gif', info.format); @@ -211,11 +211,11 @@ describe('GIF input', () => { }); }); - it('should work with streams when only pages is set', function (_t, done) { + it('should work with streams when only pages is set', (_t, done) => { fs.createReadStream(fixtures.inputGifAnimated) .pipe(sharp({ pages: -1 })) .gif() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('gif', info.format); diff --git a/test/unit/io.js b/test/unit/io.js index 4388507e7..ad13f48b6 100644 --- a/test/unit/io.js +++ b/test/unit/io.js @@ -13,18 +13,18 @@ const fixtures = require('../fixtures'); const outputJpg = fixtures.path('output.jpg'); -describe('Input/output', function () { - beforeEach(function () { +describe('Input/output', () => { + beforeEach(() => { sharp.cache(false); }); - afterEach(function () { + afterEach(() => { sharp.cache(true); }); - it('Read from File and write to Stream', function (_t, done) { + it('Read from File and write to Stream', (_t, done) => { const writable = fs.createWriteStream(outputJpg); - writable.on('close', function () { - sharp(outputJpg).toBuffer(function (err, data, info) { + writable.on('close', () => { + sharp(outputJpg).toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual(data.length, info.size); @@ -37,11 +37,11 @@ describe('Input/output', function () { sharp(fixtures.inputJpg).resize(320, 240).pipe(writable); }); - it('Read from Buffer and write to Stream', function (_t, done) { + it('Read from Buffer and write to Stream', (_t, done) => { const inputJpgBuffer = fs.readFileSync(fixtures.inputJpg); const writable = fs.createWriteStream(outputJpg); - writable.on('close', function () { - sharp(outputJpg).toBuffer(function (err, data, info) { + writable.on('close', () => { + sharp(outputJpg).toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual(data.length, info.size); @@ -54,9 +54,9 @@ describe('Input/output', function () { sharp(inputJpgBuffer).resize(320, 240).pipe(writable); }); - it('Read from Stream and write to File', function (_t, done) { + it('Read from Stream and write to File', (_t, done) => { const readable = fs.createReadStream(fixtures.inputJpg); - const pipeline = sharp().resize(320, 240).toFile(outputJpg, function (err, info) { + const pipeline = sharp().resize(320, 240).toFile(outputJpg, (err, info) => { if (err) throw err; assert.strictEqual(true, info.size > 0); assert.strictEqual('jpeg', info.format); @@ -67,9 +67,9 @@ describe('Input/output', function () { readable.pipe(pipeline); }); - it('Read from Stream and write to Buffer', function (_t, done) { + it('Read from Stream and write to Buffer', (_t, done) => { const readable = fs.createReadStream(fixtures.inputJpg); - const pipeline = sharp().resize(320, 240).toBuffer(function (err, data, info) { + const pipeline = sharp().resize(320, 240).toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual(data.length, info.size); @@ -81,23 +81,23 @@ describe('Input/output', function () { readable.pipe(pipeline); }); - it('Read from Stream and write to Buffer via Promise resolved with Buffer', function () { + it('Read from Stream and write to Buffer via Promise resolved with Buffer', () => { const pipeline = sharp().resize(1, 1); fs.createReadStream(fixtures.inputJpg).pipe(pipeline); return pipeline .toBuffer({ resolveWithObject: false }) - .then(function (data) { + .then((data) => { assert.strictEqual(true, data instanceof Buffer); assert.strictEqual(true, data.length > 0); }); }); - it('Read from Stream and write to Buffer via Promise resolved with Object', function () { + it('Read from Stream and write to Buffer via Promise resolved with Object', () => { const pipeline = sharp().resize(1, 1); fs.createReadStream(fixtures.inputJpg).pipe(pipeline); return pipeline .toBuffer({ resolveWithObject: true }) - .then(function (object) { + .then((object) => { assert.strictEqual('object', typeof object); assert.strictEqual('object', typeof object.info); assert.strictEqual('jpeg', object.info.format); @@ -109,21 +109,18 @@ describe('Input/output', function () { }); }); - it('Read from File and write to Buffer via Promise resolved with Buffer', function () { - return sharp(fixtures.inputJpg) + it('Read from File and write to Buffer via Promise resolved with Buffer', () => sharp(fixtures.inputJpg) .resize(1, 1) .toBuffer({ resolveWithObject: false }) - .then(function (data) { + .then((data) => { assert.strictEqual(true, data instanceof Buffer); assert.strictEqual(true, data.length > 0); - }); - }); + })); - it('Read from File and write to Buffer via Promise resolved with Object', function () { - return sharp(fixtures.inputJpg) + it('Read from File and write to Buffer via Promise resolved with Object', () => sharp(fixtures.inputJpg) .resize(1, 1) .toBuffer({ resolveWithObject: true }) - .then(function (object) { + .then((object) => { assert.strictEqual('object', typeof object); assert.strictEqual('object', typeof object.info); assert.strictEqual('jpeg', object.info.format); @@ -132,14 +129,13 @@ describe('Input/output', function () { assert.strictEqual(3, object.info.channels); assert.strictEqual(true, object.data instanceof Buffer); assert.strictEqual(true, object.data.length > 0); - }); - }); + })); - it('Read from Stream and write to Stream', function (_t, done) { + it('Read from Stream and write to Stream', (_t, done) => { const readable = fs.createReadStream(fixtures.inputJpg); const writable = fs.createWriteStream(outputJpg); - writable.on('close', function () { - sharp(outputJpg).toBuffer(function (err, data, info) { + writable.on('close', () => { + sharp(outputJpg).toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual(data.length, info.size); @@ -220,46 +216,46 @@ describe('Input/output', function () { assert.strictEqual(info.height, 1); }); - it('Stream should emit info event', function (_t, done) { + it('Stream should emit info event', (_t, done) => { const readable = fs.createReadStream(fixtures.inputJpg); const writable = fs.createWriteStream(outputJpg); const pipeline = sharp().resize(320, 240); let infoEventEmitted = false; - pipeline.on('info', function (info) { + pipeline.on('info', (info) => { assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); assert.strictEqual(3, info.channels); infoEventEmitted = true; }); - writable.on('close', function () { + writable.on('close', () => { assert.strictEqual(true, infoEventEmitted); fs.rm(outputJpg, done); }); readable.pipe(pipeline).pipe(writable); }); - it('Stream should emit close event', function (_t, done) { + it('Stream should emit close event', (_t, done) => { const readable = fs.createReadStream(fixtures.inputJpg); const writable = fs.createWriteStream(outputJpg); const pipeline = sharp().resize(320, 240); let closeEventEmitted = false; - pipeline.on('close', function () { + pipeline.on('close', () => { closeEventEmitted = true; }); - writable.on('close', function () { + writable.on('close', () => { assert.strictEqual(true, closeEventEmitted); fs.rm(outputJpg, done); }); readable.pipe(pipeline).pipe(writable); }); - it('Handle Stream to Stream error ', function (_t, done) { + it('Handle Stream to Stream error ', (_t, done) => { const pipeline = sharp().resize(320, 240); let anErrorWasEmitted = false; - pipeline.on('error', function (err) { + pipeline.on('error', (err) => { anErrorWasEmitted = !!err; - }).on('end', function () { + }).on('end', () => { assert(anErrorWasEmitted); fs.rm(outputJpg, done); }); @@ -268,12 +264,12 @@ describe('Input/output', function () { readableButNotAnImage.pipe(pipeline).pipe(writable); }); - it('Handle File to Stream error', function (_t, done) { + it('Handle File to Stream error', (_t, done) => { const readableButNotAnImage = sharp(__filename).resize(320, 240); let anErrorWasEmitted = false; - readableButNotAnImage.on('error', function (err) { + readableButNotAnImage.on('error', (err) => { anErrorWasEmitted = !!err; - }).on('end', function () { + }).on('end', () => { assert(anErrorWasEmitted); fs.rm(outputJpg, done); }); @@ -281,11 +277,11 @@ describe('Input/output', function () { readableButNotAnImage.pipe(writable); }); - it('Readable side of Stream can start flowing after Writable side has finished', function (_t, done) { + it('Readable side of Stream can start flowing after Writable side has finished', (_t, done) => { const readable = fs.createReadStream(fixtures.inputJpg); const writable = fs.createWriteStream(outputJpg); - writable.on('close', function () { - sharp(outputJpg).toBuffer(function (err, data, info) { + writable.on('close', () => { + sharp(outputJpg).toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual(data.length, info.size); @@ -297,7 +293,7 @@ describe('Input/output', function () { }); const pipeline = sharp().resize(320, 240); readable.pipe(pipeline); - pipeline.on('finish', function () { + pipeline.on('finish', () => { pipeline.pipe(writable); }); }); @@ -350,11 +346,11 @@ describe('Input/output', function () { }) ); - it('Support output to jpg format', function (_t, done) { + it('Support output to jpg format', (_t, done) => { sharp(fixtures.inputPng) .resize(320, 240) .toFormat('jpg') - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual(data.length, info.size); @@ -365,11 +361,11 @@ describe('Input/output', function () { }); }); - it('Support output to tif format', function (_t, done) { + it('Support output to tif format', (_t, done) => { sharp(fixtures.inputTiff) .resize(320, 240) .toFormat('tif') - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual(data.length, info.size); @@ -394,76 +390,76 @@ describe('Input/output', function () { assert.strictEqual(Buffer.isBuffer(data), true); }); - it('Fail when output File is input File', function (_t, done) { - sharp(fixtures.inputJpg).toFile(fixtures.inputJpg, function (err) { + it('Fail when output File is input File', (_t, done) => { + sharp(fixtures.inputJpg).toFile(fixtures.inputJpg, (err) => { assert(err instanceof Error); assert.strictEqual('Cannot use same file for input and output', err.message); done(); }); }); - it('Fail when output File is input File via Promise', function (_t, done) { - sharp(fixtures.inputJpg).toFile(fixtures.inputJpg).then(function () { + it('Fail when output File is input File via Promise', (_t, done) => { + sharp(fixtures.inputJpg).toFile(fixtures.inputJpg).then(() => { done(new Error('Unexpectedly resolved Promise')); - }).catch(function (err) { + }).catch((err) => { assert(err instanceof Error); assert.strictEqual('Cannot use same file for input and output', err.message); done(); }); }); - it('Fail when output File is input File (relative output, absolute input)', function (_t, done) { + it('Fail when output File is input File (relative output, absolute input)', (_t, done) => { const relativePath = path.relative(process.cwd(), fixtures.inputJpg); - sharp(fixtures.inputJpg).toFile(relativePath, function (err) { + sharp(fixtures.inputJpg).toFile(relativePath, (err) => { assert(err instanceof Error); assert.strictEqual('Cannot use same file for input and output', err.message); done(); }); }); - it('Fail when output File is input File via Promise (relative output, absolute input)', function (_t, done) { + it('Fail when output File is input File via Promise (relative output, absolute input)', (_t, done) => { const relativePath = path.relative(process.cwd(), fixtures.inputJpg); - sharp(fixtures.inputJpg).toFile(relativePath).then(function () { + sharp(fixtures.inputJpg).toFile(relativePath).then(() => { done(new Error('Unexpectedly resolved Promise')); - }).catch(function (err) { + }).catch((err) => { assert(err instanceof Error); assert.strictEqual('Cannot use same file for input and output', err.message); done(); }); }); - it('Fail when output File is input File (relative input, absolute output)', function (_t, done) { + it('Fail when output File is input File (relative input, absolute output)', (_t, done) => { const relativePath = path.relative(process.cwd(), fixtures.inputJpg); - sharp(relativePath).toFile(fixtures.inputJpg, function (err) { + sharp(relativePath).toFile(fixtures.inputJpg, (err) => { assert(err instanceof Error); assert.strictEqual('Cannot use same file for input and output', err.message); done(); }); }); - it('Fail when output File is input File via Promise (relative input, absolute output)', function (_t, done) { + it('Fail when output File is input File via Promise (relative input, absolute output)', (_t, done) => { const relativePath = path.relative(process.cwd(), fixtures.inputJpg); - sharp(relativePath).toFile(fixtures.inputJpg).then(function () { + sharp(relativePath).toFile(fixtures.inputJpg).then(() => { done(new Error('Unexpectedly resolved Promise')); - }).catch(function (err) { + }).catch((err) => { assert(err instanceof Error); assert.strictEqual('Cannot use same file for input and output', err.message); done(); }); }); - it('Fail when output File is empty', function (_t, done) { - sharp(fixtures.inputJpg).toFile('', function (err) { + it('Fail when output File is empty', (_t, done) => { + sharp(fixtures.inputJpg).toFile('', (err) => { assert(err instanceof Error); assert.strictEqual('Missing output file path', err.message); done(); }); }); - it('Fail when output File is empty via Promise', function (_t, done) { - sharp(fixtures.inputJpg).toFile('').then(function () { + it('Fail when output File is empty via Promise', (_t, done) => { + sharp(fixtures.inputJpg).toFile('').then(() => { done(new Error('Unexpectedly resolved Promise')); - }).catch(function (err) { + }).catch((err) => { assert(err instanceof Error); assert.strictEqual('Missing output file path', err.message); done(); @@ -494,41 +490,39 @@ describe('Input/output', function () { ) ); - describe('Fail for unsupported input', function () { - it('Undefined', function () { - assert.throws(function () { + describe('Fail for unsupported input', () => { + it('Undefined', () => { + assert.throws(() => { sharp(undefined); }); }); - it('Null', function () { - assert.throws(function () { + it('Null', () => { + assert.throws(() => { sharp(null); }); }); - it('Numeric', function () { - assert.throws(function () { + it('Numeric', () => { + assert.throws(() => { sharp(1); }); }); - it('Boolean', function () { - assert.throws(function () { + it('Boolean', () => { + assert.throws(() => { sharp(true); }); }); - it('Error Object', function () { - assert.throws(function () { + it('Error Object', () => { + assert.throws(() => { sharp(new Error()); }); }); }); - it('Promises/A+', function () { - return sharp(fixtures.inputJpg) + it('Promises/A+', () => sharp(fixtures.inputJpg) .resize(320, 240) - .toBuffer(); - }); + .toBuffer()); - it('Invalid output format', function (_t, done) { + it('Invalid output format', (_t, done) => { let isValid = false; try { sharp().toFormat('zoinks'); @@ -538,30 +532,30 @@ describe('Input/output', function () { done(); }); - it('File input with corrupt header fails gracefully', function (_t, done) { + it('File input with corrupt header fails gracefully', (_t, done) => { sharp(fixtures.inputJpgWithCorruptHeader) - .toBuffer(function (err) { + .toBuffer((err) => { assert.strictEqual(true, !!err); done(); }); }); - it('Buffer input with corrupt header fails gracefully', function (_t, done) { + it('Buffer input with corrupt header fails gracefully', (_t, done) => { sharp(fs.readFileSync(fixtures.inputJpgWithCorruptHeader)) - .toBuffer(function (err) { + .toBuffer((err) => { assert.strictEqual(true, !!err); done(); }); }); - it('Stream input with corrupt header fails gracefully', function (_t, done) { + it('Stream input with corrupt header fails gracefully', (_t, done) => { const transformer = sharp(); transformer .toBuffer() - .then(function () { + .then(() => { done(new Error('Unexpectedly resolved Promise')); }) - .catch(function (err) { + .catch((err) => { assert.strictEqual(true, !!err); done(); }); @@ -570,13 +564,13 @@ describe('Input/output', function () { .pipe(transformer); }); - describe('Output filename with unknown extension', function () { + describe('Output filename with unknown extension', () => { const outputZoinks = fixtures.path('output.zoinks'); - it('Match JPEG input', function (_t, done) { + it('Match JPEG input', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 80) - .toFile(outputZoinks, function (err, info) { + .toFile(outputZoinks, (err, info) => { if (err) throw err; assert.strictEqual(true, info.size > 0); assert.strictEqual('jpeg', info.format); @@ -586,10 +580,10 @@ describe('Input/output', function () { }); }); - it('Match PNG input', function (_t, done) { + it('Match PNG input', (_t, done) => { sharp(fixtures.inputPng) .resize(320, 80) - .toFile(outputZoinks, function (err, info) { + .toFile(outputZoinks, (err, info) => { if (err) throw err; assert.strictEqual(true, info.size > 0); assert.strictEqual('png', info.format); @@ -599,10 +593,10 @@ describe('Input/output', function () { }); }); - it('Match WebP input', function (_t, done) { + it('Match WebP input', (_t, done) => { sharp(fixtures.inputWebP) .resize(320, 80) - .toFile(outputZoinks, function (err, info) { + .toFile(outputZoinks, (err, info) => { if (err) throw err; assert.strictEqual(true, info.size > 0); assert.strictEqual('webp', info.format); @@ -612,10 +606,10 @@ describe('Input/output', function () { }); }); - it('Match TIFF input', function (_t, done) { + it('Match TIFF input', (_t, done) => { sharp(fixtures.inputTiff) .resize(320, 80) - .toFile(outputZoinks, function (err, info) { + .toFile(outputZoinks, (err, info) => { if (err) throw err; assert.strictEqual(true, info.size > 0); assert.strictEqual('tiff', info.format); @@ -625,11 +619,11 @@ describe('Input/output', function () { }); }); - it('Force JPEG format for PNG input', function (_t, done) { + it('Force JPEG format for PNG input', (_t, done) => { sharp(fixtures.inputPng) .resize(320, 80) .jpeg() - .toFile(outputZoinks, function (err, info) { + .toFile(outputZoinks, (err, info) => { if (err) throw err; assert.strictEqual(true, info.size > 0); assert.strictEqual('jpeg', info.format); @@ -640,11 +634,11 @@ describe('Input/output', function () { }); }); - it('Input and output formats match when not forcing', function (_t, done) { + it('Input and output formats match when not forcing', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .png({ compressionLevel: 1, force: false }) - .toBuffer(function (err, _data, info) { + .toBuffer((err, _data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -653,44 +647,42 @@ describe('Input/output', function () { }); }); - it('Can force output format with output chaining', function () { - return sharp(fixtures.inputJpg) + it('Can force output format with output chaining', () => sharp(fixtures.inputJpg) .resize(320, 240) .png({ force: true }) .jpeg({ force: false }) .toBuffer({ resolveWithObject: true }) - .then(function (out) { + .then((out) => { assert.strictEqual('png', out.info.format); - }); - }); + })); - it('toFormat=JPEG takes precedence over WebP extension', function (_t, done) { + it('toFormat=JPEG takes precedence over WebP extension', (_t, done) => { const outputWebP = fixtures.path('output.webp'); sharp(fixtures.inputPng) .resize(8) .jpeg() - .toFile(outputWebP, function (err, info) { + .toFile(outputWebP, (err, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); fs.rm(outputWebP, done); }); }); - it('toFormat=WebP takes precedence over JPEG extension', function (_t, done) { + it('toFormat=WebP takes precedence over JPEG extension', (_t, done) => { sharp(fixtures.inputPng) .resize(8) .webp() - .toFile(outputJpg, function (err, info) { + .toFile(outputJpg, (err, info) => { if (err) throw err; assert.strictEqual('webp', info.format); done(); }); }); - it('Load Vips V file', function (_t, done) { + it('Load Vips V file', (_t, done) => { sharp(fixtures.inputV) .jpeg() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -700,11 +692,11 @@ describe('Input/output', function () { }); }); - it('Save Vips V file', function (_t, done) { + it('Save Vips V file', (_t, done) => { const outputV = fixtures.path('output.v'); sharp(fixtures.inputJpg) .extract({ left: 910, top: 1105, width: 70, height: 60 }) - .toFile(outputV, function (err, info) { + .toFile(outputV, (err, info) => { if (err) throw err; assert.strictEqual(true, info.size > 0); assert.strictEqual('v', info.format); @@ -827,62 +819,62 @@ describe('Input/output', function () { ); }); - describe('Input options', function () { - it('Option-less', function () { + describe('Input options', () => { + it('Option-less', () => { sharp(); }); - it('Ignore unknown attribute', function () { + it('Ignore unknown attribute', () => { sharp({ unknown: true }); }); - it('undefined with options fails', function () { - assert.throws(function () { + it('undefined with options fails', () => { + assert.throws(() => { sharp(undefined, {}); }, /Unsupported input 'undefined' of type undefined when also providing options of type object/); }); - it('null with options fails', function () { - assert.throws(function () { + it('null with options fails', () => { + assert.throws(() => { sharp(null, {}); }, /Unsupported input 'null' of type object when also providing options of type object/); }); - it('Non-Object options fails', function () { - assert.throws(function () { + it('Non-Object options fails', () => { + assert.throws(() => { sharp('test', 'zoinks'); }, /Invalid input options zoinks/); }); - it('Invalid density: string', function () { - assert.throws(function () { + it('Invalid density: string', () => { + assert.throws(() => { sharp({ density: 'zoinks' }); }, /Expected number between 1 and 100000 for density but received zoinks of type string/); }); - it('Invalid ignoreIcc: string', function () { - assert.throws(function () { + it('Invalid ignoreIcc: string', () => { + assert.throws(() => { sharp({ ignoreIcc: 'zoinks' }); }, /Expected boolean for ignoreIcc but received zoinks of type string/); }); - it('Setting animated property updates pages property', function () { + it('Setting animated property updates pages property', () => { assert.strictEqual(sharp({ animated: false }).options.input.pages, 1); assert.strictEqual(sharp({ animated: true }).options.input.pages, -1); }); - it('Invalid animated property throws', function () { - assert.throws(function () { + it('Invalid animated property throws', () => { + assert.throws(() => { sharp({ animated: -1 }); }, /Expected boolean for animated but received -1 of type number/); }); - it('Invalid page property throws', function () { - assert.throws(function () { + it('Invalid page property throws', () => { + assert.throws(() => { sharp({ page: -1 }); }, /Expected integer between 0 and 100000 for page but received -1 of type number/); }); - it('Invalid pages property throws', function () { - assert.throws(function () { + it('Invalid pages property throws', () => { + assert.throws(() => { sharp({ pages: '1' }); }, /Expected integer between -1 and 100000 for pages but received 1 of type string/); }); - it('Valid openSlide.level property', function () { + it('Valid openSlide.level property', () => { sharp({ openSlide: { level: 1 } }); sharp({ level: 1 }); }); - it('Invalid openSlide.level property (string) throws', function () { + it('Invalid openSlide.level property (string) throws', () => { assert.throws( () => sharp({ openSlide: { level: '1' } }), /Expected integer between 0 and 256 for openSlide.level but received 1 of type string/ @@ -892,7 +884,7 @@ describe('Input/output', function () { /Expected integer between 0 and 256 for level but received 1 of type string/ ); }); - it('Invalid openSlide.level property (negative) throws', function () { + it('Invalid openSlide.level property (negative) throws', () => { assert.throws( () => sharp({ openSlide: { level: -1 } }), /Expected integer between 0 and 256 for openSlide\.level but received -1 of type number/ @@ -902,11 +894,11 @@ describe('Input/output', function () { /Expected integer between 0 and 256 for level but received -1 of type number/ ); }); - it('Valid tiff.subifd property', function () { + it('Valid tiff.subifd property', () => { sharp({ tiff: { subifd: 1 } }); sharp({ subifd: 1 }); }); - it('Invalid tiff.subifd property (string) throws', function () { + it('Invalid tiff.subifd property (string) throws', () => { assert.throws( () => sharp({ tiff: { subifd: '1' } }), /Expected integer between -1 and 100000 for tiff\.subifd but received 1 of type string/ @@ -916,7 +908,7 @@ describe('Input/output', function () { /Expected integer between -1 and 100000 for subifd but received 1 of type string/ ); }); - it('Invalid tiff.subifd property (float) throws', function () { + it('Invalid tiff.subifd property (float) throws', () => { assert.throws( () => sharp({ tiff: { subifd: 1.2 } }), /Expected integer between -1 and 100000 for tiff\.subifd but received 1.2 of type number/ @@ -926,15 +918,15 @@ describe('Input/output', function () { /Expected integer between -1 and 100000 for subifd but received 1.2 of type number/ ); }); - it('Valid pdf.background property (string)', function () { + it('Valid pdf.background property (string)', () => { sharp({ pdf: { background: '#00ff00' } }); sharp({ pdfBackground: '#00ff00' }); }); - it('Valid pdf.background property (object)', function () { + it('Valid pdf.background property (object)', () => { sharp({ pdf: { background: { r: 0, g: 255, b: 0 } } }); sharp({ pdfBackground: { r: 0, g: 255, b: 0 } }); }); - it('Invalid pdf.background property (string) throws', function () { + it('Invalid pdf.background property (string) throws', () => { assert.throws( () => sharp({ pdf: { background: '00ff00' } }), /Unable to parse color from string/ @@ -944,7 +936,7 @@ describe('Input/output', function () { /Unable to parse color from string/ ); }); - it('Invalid pdf.background property (number) throws', function () { + it('Invalid pdf.background property (number) throws', () => { assert.throws( () => sharp({ pdf: { background: 255 } }), /Expected object or string for background/ @@ -954,7 +946,7 @@ describe('Input/output', function () { /Expected object or string for background/ ); }); - it('Invalid pdf.background property (object)', function () { + it('Invalid pdf.background property (object)', () => { assert.throws( () => sharp({ pdf: { background: { red: 0, green: 255, blue: 0 } } }), /Unable to parse color from object/ @@ -979,8 +971,8 @@ describe('Input/output', function () { ); }); - describe('create new image', function () { - it('RGB', function (_t, done) { + describe('create new image', () => { + it('RGB', (_t, done) => { const create = { width: 10, height: 20, @@ -989,7 +981,7 @@ describe('Input/output', function () { }; sharp({ create }) .jpeg() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(create.width, info.width); assert.strictEqual(create.height, info.height); @@ -998,7 +990,7 @@ describe('Input/output', function () { fixtures.assertSimilar(fixtures.expected('create-rgb.jpg'), data, done); }); }); - it('RGBA', function (_t, done) { + it('RGBA', (_t, done) => { const create = { width: 20, height: 10, @@ -1007,7 +999,7 @@ describe('Input/output', function () { }; sharp({ create }) .png() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(create.width, info.width); assert.strictEqual(create.height, info.height); @@ -1016,40 +1008,40 @@ describe('Input/output', function () { fixtures.assertSimilar(fixtures.expected('create-rgba.png'), data, done); }); }); - it('Invalid channels', function () { + it('Invalid channels', () => { const create = { width: 10, height: 20, channels: 2, background: { r: 0, g: 0, b: 0 } }; - assert.throws(function () { + assert.throws(() => { sharp({ create }); }); }); - it('Missing background', function () { + it('Missing background', () => { const create = { width: 10, height: 20, channels: 3 }; - assert.throws(function () { + assert.throws(() => { sharp({ create }); }); }); }); - it('Queue length change events', function (_t, done) { + it('Queue length change events', (_t, done) => { let eventCounter = 0; - const queueListener = function (queueLength) { + const queueListener = (queueLength) => { assert.strictEqual(true, queueLength === 0 || queueLength === 1); eventCounter++; }; sharp.queue.on('change', queueListener); sharp(fixtures.inputJpg) .resize(320, 240) - .toBuffer(function (err) { - process.nextTick(function () { + .toBuffer((err) => { + process.nextTick(() => { sharp.queue.removeListener('change', queueListener); if (err) throw err; assert.strictEqual(2, eventCounter); @@ -1058,19 +1050,19 @@ describe('Input/output', function () { }); }); - it('Info event data', function (_t, done) { + it('Info event data', (_t, done) => { const readable = fs.createReadStream(fixtures.inputJPGBig); const inPipeline = sharp() .resize(840, 472) .raw() - .on('info', function (info) { + .on('info', (info) => { assert.strictEqual(840, info.width); assert.strictEqual(472, info.height); assert.strictEqual(3, info.channels); }); const badPipeline = sharp({ raw: { width: 840, height: 500, channels: 3 } }) .toFormat('jpeg') - .toBuffer(function (err) { + .toBuffer((err) => { assert.strictEqual(err.message.indexOf('memory area too small') > 0, true); const readable = fs.createReadStream(fixtures.inputJPGBig); const inPipeline = sharp() diff --git a/test/unit/join.js b/test/unit/join.js index 3aea9ce36..c95c35626 100644 --- a/test/unit/join.js +++ b/test/unit/join.js @@ -9,7 +9,7 @@ const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); -describe('Join input images together', function () { +describe('Join input images together', () => { it('Join two images horizontally', async () => { const data = await sharp([ fixtures.inputPngPalette, diff --git a/test/unit/joinChannel.js b/test/unit/joinChannel.js index e1b743151..feebb1337 100644 --- a/test/unit/joinChannel.js +++ b/test/unit/joinChannel.js @@ -10,13 +10,13 @@ const fs = require('node:fs'); const sharp = require('../../'); const fixtures = require('../fixtures'); -describe('Image channel insertion', function () { - it('Grayscale to RGB, buffer', function (_t, done) { +describe('Image channel insertion', () => { + it('Grayscale to RGB, buffer', (_t, done) => { sharp(fixtures.inputPng) // gray -> red .resize(320, 240) .joinChannel(fixtures.inputPngTestJoinChannel) // new green channel .joinChannel(fixtures.inputPngStripesH) // new blue channel - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); @@ -25,12 +25,12 @@ describe('Image channel insertion', function () { }); }); - it('Grayscale to RGB, file', function (_t, done) { + it('Grayscale to RGB, file', (_t, done) => { sharp(fixtures.inputPng) // gray -> red .resize(320, 240) .joinChannel(fs.readFileSync(fixtures.inputPngTestJoinChannel)) // new green channel .joinChannel(fs.readFileSync(fixtures.inputPngStripesH)) // new blue channel - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); @@ -39,7 +39,7 @@ describe('Image channel insertion', function () { }); }); - it('Grayscale to RGBA, buffer', function (_t, done) { + it('Grayscale to RGBA, buffer', (_t, done) => { sharp(fixtures.inputPng) // gray -> red .resize(320, 240) .joinChannel([ @@ -48,7 +48,7 @@ describe('Image channel insertion', function () { fixtures.inputPngStripesV ]) // new green + blue + alpha channel .toColourspace(sharp.colourspace.srgb) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); @@ -57,7 +57,7 @@ describe('Image channel insertion', function () { }); }); - it('Grayscale to RGBA, file', function (_t, done) { + it('Grayscale to RGBA, file', (_t, done) => { sharp(fixtures.inputPng) // gray -> red .resize(320, 240) .joinChannel([ @@ -66,7 +66,7 @@ describe('Image channel insertion', function () { fs.readFileSync(fixtures.inputPngStripesV) // new alpha channel ]) .toColourspace('srgb') - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); @@ -75,7 +75,7 @@ describe('Image channel insertion', function () { }); }); - it('Grayscale to CMYK, buffers', function (_t, done) { + it('Grayscale to CMYK, buffers', (_t, done) => { sharp(fixtures.inputPng) // gray -> magenta .resize(320, 240) .joinChannel([ @@ -85,7 +85,7 @@ describe('Image channel insertion', function () { ]) .toColorspace('cmyk') .toFormat('jpeg') - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); @@ -94,12 +94,12 @@ describe('Image channel insertion', function () { }); }); - it('Join raw buffers to RGB', function (_t, done) { + it('Join raw buffers to RGB', (_t, done) => { Promise.all([ sharp(fixtures.inputPngTestJoinChannel).toColourspace('b-w').raw().toBuffer(), sharp(fixtures.inputPngStripesH).toColourspace('b-w').raw().toBuffer() ]) - .then(function (buffers) { + .then((buffers) => { sharp(fixtures.inputPng) .resize(320, 240) .joinChannel(buffers, { @@ -109,7 +109,7 @@ describe('Image channel insertion', function () { channels: 1 } }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); @@ -117,12 +117,12 @@ describe('Image channel insertion', function () { fixtures.assertSimilar(fixtures.expected('joinChannel-rgb.jpg'), data, done); }); }) - .catch(function (err) { + .catch((err) => { throw err; }); }); - it('Grayscale to RGBA, files, two arrays', function (_t, done) { + it('Grayscale to RGBA, files, two arrays', (_t, done) => { sharp(fixtures.inputPng) // gray -> red .resize(320, 240) .joinChannel([fs.readFileSync(fixtures.inputPngTestJoinChannel)]) // new green channel @@ -131,7 +131,7 @@ describe('Image channel insertion', function () { fs.readFileSync(fixtures.inputPngStripesV) // new alpha channel ]) .toColourspace('srgb') - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); @@ -140,20 +140,20 @@ describe('Image channel insertion', function () { }); }); - it('Invalid raw buffer description', function () { - assert.throws(function () { + it('Invalid raw buffer description', () => { + assert.throws(() => { sharp().joinChannel(fs.readFileSync(fixtures.inputPng), { raw: {} }); }); }); - it('Invalid input', function () { - assert.throws(function () { + it('Invalid input', () => { + assert.throws(() => { sharp(fixtures.inputJpg).joinChannel(1); }); }); - it('No arguments', function () { - assert.throws(function () { + it('No arguments', () => { + assert.throws(() => { sharp(fixtures.inputJpg).joinChannel(); }); }); diff --git a/test/unit/jp2.js b/test/unit/jp2.js index de70ab6f2..1f9dcb1ba 100644 --- a/test/unit/jp2.js +++ b/test/unit/jp2.js @@ -49,15 +49,15 @@ describe('JP2 output', () => { }); }); - it('JP2 quality', function (done) { + it('JP2 quality', (done) => { sharp(fixtures.inputJp2) .resize(320, 240) .jp2({ quality: 70 }) - .toBuffer(function (err, buffer70) { + .toBuffer((err, buffer70) => { if (err) throw err; sharp(fixtures.inputJp2) .resize(320, 240) - .toBuffer(function (err, buffer80) { + .toBuffer((err, buffer80) => { if (err) throw err; assert(buffer70.length < buffer80.length); done(); @@ -65,12 +65,12 @@ describe('JP2 output', () => { }); }); - it('Without chroma subsampling generates larger file', function (done) { + it('Without chroma subsampling generates larger file', (done) => { // First generate with chroma subsampling (default) sharp(fixtures.inputJp2) .resize(320, 240) .jp2({ chromaSubsampling: '4:2:0' }) - .toBuffer(function (err, withChromaSubsamplingData, withChromaSubsamplingInfo) { + .toBuffer((err, withChromaSubsamplingData, withChromaSubsamplingInfo) => { if (err) throw err; assert.strictEqual(true, withChromaSubsamplingData.length > 0); assert.strictEqual(withChromaSubsamplingData.length, withChromaSubsamplingInfo.size); @@ -81,7 +81,7 @@ describe('JP2 output', () => { sharp(fixtures.inputJp2) .resize(320, 240) .jp2({ chromaSubsampling: '4:4:4' }) - .toBuffer(function (err, withoutChromaSubsamplingData, withoutChromaSubsamplingInfo) { + .toBuffer((err, withoutChromaSubsamplingData, withoutChromaSubsamplingInfo) => { if (err) throw err; assert.strictEqual(true, withoutChromaSubsamplingData.length > 0); assert.strictEqual(withoutChromaSubsamplingData.length, withoutChromaSubsamplingInfo.size); diff --git a/test/unit/jpeg.js b/test/unit/jpeg.js index a089e0a75..9a802cb8f 100644 --- a/test/unit/jpeg.js +++ b/test/unit/jpeg.js @@ -9,21 +9,21 @@ const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); -describe('JPEG', function () { - it('JPEG quality', function (_t, done) { +describe('JPEG', () => { + it('JPEG quality', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .jpeg({ quality: 70 }) - .toBuffer(function (err, buffer70) { + .toBuffer((err, buffer70) => { if (err) throw err; sharp(fixtures.inputJpg) .resize(320, 240) - .toBuffer(function (err, buffer80) { + .toBuffer((err, buffer80) => { if (err) throw err; sharp(fixtures.inputJpg) .resize(320, 240) .jpeg({ quality: 90 }) - .toBuffer(function (err, buffer90) { + .toBuffer((err, buffer90) => { if (err) throw err; assert(buffer70.length < buffer80.length); assert(buffer80.length < buffer90.length); @@ -33,31 +33,31 @@ describe('JPEG', function () { }); }); - describe('Invalid JPEG quality', function () { - [-1, 88.2, 'test'].forEach(function (quality) { - it(quality.toString(), function () { - assert.throws(function () { + describe('Invalid JPEG quality', () => { + [-1, 88.2, 'test'].forEach((quality) => { + it(quality.toString(), () => { + assert.throws(() => { sharp().jpeg({ quality }); }); }); }); }); - describe('Invalid JPEG quantisation table', function () { - [-1, 88.2, 'test'].forEach(function (table) { - it(table.toString(), function () { - assert.throws(function () { + describe('Invalid JPEG quantisation table', () => { + [-1, 88.2, 'test'].forEach((table) => { + it(table.toString(), () => { + assert.throws(() => { sharp().jpeg({ quantisationTable: table }); }); }); }); }); - it('Progressive JPEG image', function (_t, done) { + it('Progressive JPEG image', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .jpeg({ progressive: false }) - .toBuffer(function (err, nonProgressiveData, nonProgressiveInfo) { + .toBuffer((err, nonProgressiveData, nonProgressiveInfo) => { if (err) throw err; assert.strictEqual(true, nonProgressiveData.length > 0); assert.strictEqual(nonProgressiveData.length, nonProgressiveInfo.size); @@ -67,7 +67,7 @@ describe('JPEG', function () { sharp(fixtures.inputJpg) .resize(320, 240) .jpeg({ progressive: true }) - .toBuffer(function (err, progressiveData, progressiveInfo) { + .toBuffer((err, progressiveData, progressiveInfo) => { if (err) throw err; assert.strictEqual(true, progressiveData.length > 0); assert.strictEqual(progressiveData.length, progressiveInfo.size); @@ -80,12 +80,12 @@ describe('JPEG', function () { }); }); - it('Without chroma subsampling generates larger file', function (_t, done) { + it('Without chroma subsampling generates larger file', (_t, done) => { // First generate with chroma subsampling (default) sharp(fixtures.inputJpg) .resize(320, 240) .jpeg({ chromaSubsampling: '4:2:0' }) - .toBuffer(function (err, withChromaSubsamplingData, withChromaSubsamplingInfo) { + .toBuffer((err, withChromaSubsamplingData, withChromaSubsamplingInfo) => { if (err) throw err; assert.strictEqual(true, withChromaSubsamplingData.length > 0); assert.strictEqual(withChromaSubsamplingData.length, withChromaSubsamplingInfo.size); @@ -96,7 +96,7 @@ describe('JPEG', function () { sharp(fixtures.inputJpg) .resize(320, 240) .jpeg({ chromaSubsampling: '4:4:4' }) - .toBuffer(function (err, withoutChromaSubsamplingData, withoutChromaSubsamplingInfo) { + .toBuffer((err, withoutChromaSubsamplingData, withoutChromaSubsamplingInfo) => { if (err) throw err; assert.strictEqual(true, withoutChromaSubsamplingData.length > 0); assert.strictEqual(withoutChromaSubsamplingData.length, withoutChromaSubsamplingInfo.size); @@ -109,18 +109,18 @@ describe('JPEG', function () { }); }); - it('Invalid JPEG chromaSubsampling value throws error', function () { - assert.throws(function () { + it('Invalid JPEG chromaSubsampling value throws error', () => { + assert.throws(() => { sharp().jpeg({ chromaSubsampling: '4:2:2' }); }); }); - it('Trellis quantisation', function (_t, done) { + it('Trellis quantisation', (_t, done) => { // First generate without sharp(fixtures.inputJpg) .resize(320, 240) .jpeg({ trellisQuantisation: false }) - .toBuffer(function (err, withoutData, withoutInfo) { + .toBuffer((err, withoutData, withoutInfo) => { if (err) throw err; assert.strictEqual(true, withoutData.length > 0); assert.strictEqual(withoutData.length, withoutInfo.size); @@ -131,7 +131,7 @@ describe('JPEG', function () { sharp(fixtures.inputJpg) .resize(320, 240) .jpeg({ trellisQuantization: true }) - .toBuffer(function (err, withData, withInfo) { + .toBuffer((err, withData, withInfo) => { if (err) throw err; assert.strictEqual(true, withData.length > 0); assert.strictEqual(withData.length, withInfo.size); @@ -145,12 +145,12 @@ describe('JPEG', function () { }); }); - it('Overshoot deringing', function (_t, done) { + it('Overshoot deringing', (_t, done) => { // First generate without sharp(fixtures.inputJpg) .resize(320, 240) .jpeg({ overshootDeringing: false }) - .toBuffer(function (err, withoutData, withoutInfo) { + .toBuffer((err, withoutData, withoutInfo) => { if (err) throw err; assert.strictEqual(true, withoutData.length > 0); assert.strictEqual(withoutData.length, withoutInfo.size); @@ -161,7 +161,7 @@ describe('JPEG', function () { sharp(fixtures.inputJpg) .resize(320, 240) .jpeg({ overshootDeringing: true }) - .toBuffer(function (err, withData, withInfo) { + .toBuffer((err, withData, withInfo) => { if (err) throw err; assert.strictEqual(true, withData.length > 0); assert.strictEqual(withData.length, withInfo.size); @@ -173,12 +173,12 @@ describe('JPEG', function () { }); }); - it('Optimise scans generates different output length', function (_t, done) { + it('Optimise scans generates different output length', (_t, done) => { // First generate without sharp(fixtures.inputJpg) .resize(320, 240) .jpeg({ optimiseScans: false }) - .toBuffer(function (err, withoutData, withoutInfo) { + .toBuffer((err, withoutData, withoutInfo) => { if (err) throw err; assert.strictEqual(true, withoutData.length > 0); assert.strictEqual(withoutData.length, withoutInfo.size); @@ -189,7 +189,7 @@ describe('JPEG', function () { sharp(fixtures.inputJpg) .resize(320, 240) .jpeg({ optimizeScans: true }) - .toBuffer(function (err, withData, withInfo) { + .toBuffer((err, withData, withInfo) => { if (err) throw err; assert.strictEqual(true, withData.length > 0); assert.strictEqual(withData.length, withInfo.size); @@ -203,12 +203,12 @@ describe('JPEG', function () { }); }); - it('Optimise coding generates smaller output length', function (_t, done) { + it('Optimise coding generates smaller output length', (_t, done) => { // First generate with optimize coding enabled (default) sharp(fixtures.inputJpg) .resize(320, 240) .jpeg() - .toBuffer(function (err, withOptimiseCoding, withInfo) { + .toBuffer((err, withOptimiseCoding, withInfo) => { if (err) throw err; assert.strictEqual(true, withOptimiseCoding.length > 0); assert.strictEqual(withOptimiseCoding.length, withInfo.size); @@ -219,7 +219,7 @@ describe('JPEG', function () { sharp(fixtures.inputJpg) .resize(320, 240) .jpeg({ optimizeCoding: false }) - .toBuffer(function (err, withoutOptimiseCoding, withoutInfo) { + .toBuffer((err, withoutOptimiseCoding, withoutInfo) => { if (err) throw err; assert.strictEqual(true, withoutOptimiseCoding.length > 0); assert.strictEqual(withoutOptimiseCoding.length, withoutInfo.size); @@ -233,12 +233,12 @@ describe('JPEG', function () { }); }); - it('Specifying quantisation table provides different JPEG', function (_t, done) { + it('Specifying quantisation table provides different JPEG', (_t, done) => { // First generate with default quantisation table sharp(fixtures.inputJpg) .resize(320, 240) .jpeg({ optimiseCoding: false }) - .toBuffer(function (err, withDefaultQuantisationTable, withInfo) { + .toBuffer((err, withDefaultQuantisationTable, withInfo) => { if (err) throw err; assert.strictEqual(true, withDefaultQuantisationTable.length > 0); assert.strictEqual(withDefaultQuantisationTable.length, withInfo.size); @@ -249,7 +249,7 @@ describe('JPEG', function () { sharp(fixtures.inputJpg) .resize(320, 240) .jpeg({ optimiseCoding: false, quantisationTable: 3 }) - .toBuffer(function (err, withQuantTable3, withoutInfo) { + .toBuffer((err, withQuantTable3, withoutInfo) => { if (err) throw err; assert.strictEqual(true, withQuantTable3.length > 0); assert.strictEqual(withQuantTable3.length, withoutInfo.size); @@ -264,12 +264,12 @@ describe('JPEG', function () { }); }); - it('Specifying quantization table provides different JPEG', function (_t, done) { + it('Specifying quantization table provides different JPEG', (_t, done) => { // First generate with default quantization table sharp(fixtures.inputJpg) .resize(320, 240) .jpeg({ optimiseCoding: false }) - .toBuffer(function (err, withDefaultQuantizationTable, withInfo) { + .toBuffer((err, withDefaultQuantizationTable, withInfo) => { if (err) throw err; assert.strictEqual(true, withDefaultQuantizationTable.length > 0); assert.strictEqual(withDefaultQuantizationTable.length, withInfo.size); @@ -280,7 +280,7 @@ describe('JPEG', function () { sharp(fixtures.inputJpg) .resize(320, 240) .jpeg({ optimiseCoding: false, quantizationTable: 3 }) - .toBuffer(function (err, withQuantTable3, withoutInfo) { + .toBuffer((err, withQuantTable3, withoutInfo) => { if (err) throw err; assert.strictEqual(true, withQuantTable3.length > 0); assert.strictEqual(withQuantTable3.length, withoutInfo.size); diff --git a/test/unit/libvips.js b/test/unit/libvips.js index 6cab3cce1..8ed822458 100644 --- a/test/unit/libvips.js +++ b/test/unit/libvips.js @@ -11,55 +11,55 @@ const libvips = require('../../lib/libvips'); const originalPlatform = process.platform; -const setPlatform = function (platform) { +const setPlatform = (platform) => { Object.defineProperty(process, 'platform', { value: platform }); }; -const restorePlatform = function () { +const restorePlatform = () => { setPlatform(originalPlatform); }; -describe('libvips binaries', function () { - describe('Windows platform', function () { - before(function () { setPlatform('win32'); }); +describe('libvips binaries', () => { + describe('Windows platform', () => { + before(() => { setPlatform('win32'); }); after(restorePlatform); - it('pkgConfigPath returns empty string', function () { + it('pkgConfigPath returns empty string', () => { assert.strictEqual('', libvips.pkgConfigPath()); }); - it('globalLibvipsVersion returns empty string', function () { + it('globalLibvipsVersion returns empty string', () => { assert.strictEqual('', libvips.globalLibvipsVersion()); }); - it('globalLibvipsVersion is always false', function () { + it('globalLibvipsVersion is always false', () => { assert.strictEqual(false, libvips.useGlobalLibvips()); }); }); - describe('non-Windows platforms', function () { - before(function () { setPlatform('linux'); }); + describe('non-Windows platforms', () => { + before(() => { setPlatform('linux'); }); after(restorePlatform); - it('pkgConfigPath returns a string', function () { + it('pkgConfigPath returns a string', () => { const pkgConfigPath = libvips.pkgConfigPath(); assert.strictEqual('string', typeof pkgConfigPath); }); - it('globalLibvipsVersion returns a string', function () { + it('globalLibvipsVersion returns a string', () => { const globalLibvipsVersion = libvips.globalLibvipsVersion(); assert.strictEqual('string', typeof globalLibvipsVersion); }); - it('globalLibvipsVersion returns a boolean', function () { + it('globalLibvipsVersion returns a boolean', () => { const useGlobalLibvips = libvips.useGlobalLibvips(); assert.strictEqual('boolean', typeof useGlobalLibvips); }); }); - describe('platform agnostic', function () { - it('minimumLibvipsVersion returns a valid semver', function () { + describe('platform agnostic', () => { + it('minimumLibvipsVersion returns a valid semver', () => { const minimumLibvipsVersion = libvips.minimumLibvipsVersion; assert.strictEqual('string', typeof minimumLibvipsVersion); assert.notStrictEqual(null, semver.valid(minimumLibvipsVersion)); }); - it('useGlobalLibvips can be ignored via an env var', function () { + it('useGlobalLibvips can be ignored via an env var', () => { process.env.SHARP_IGNORE_GLOBAL_LIBVIPS = 1; const useGlobalLibvips = libvips.useGlobalLibvips(); @@ -67,14 +67,14 @@ describe('libvips binaries', function () { delete process.env.SHARP_IGNORE_GLOBAL_LIBVIPS; }); - it('useGlobalLibvips can be forced via an env var', function () { + it('useGlobalLibvips can be forced via an env var', () => { process.env.SHARP_FORCE_GLOBAL_LIBVIPS = 1; const useGlobalLibvips = libvips.useGlobalLibvips(); assert.strictEqual(true, useGlobalLibvips); let logged = false; - const logger = function (message) { + const logger = (message) => { assert.strictEqual(message, 'Detected SHARP_FORCE_GLOBAL_LIBVIPS, skipping search for globally-installed libvips'); logged = true; }; @@ -146,25 +146,25 @@ describe('libvips binaries', function () { }); }); - describe('logger', function () { + describe('logger', () => { const consoleLog = console.log; const consoleError = console.error; - after(function () { + after(() => { console.log = consoleLog; console.error = consoleError; }); - it('logs an info message', function (_t, done) { - console.log = function (msg) { + it('logs an info message', (_t, done) => { + console.log = (msg) => { assert.strictEqual(msg, 'sharp: progress'); done(); }; libvips.log('progress'); }); - it('logs an error message', function (_t, done) { - console.error = function (msg) { + it('logs an error message', (_t, done) => { + console.error = (msg) => { assert.strictEqual(msg, 'sharp: Installation error: problem'); done(); }; diff --git a/test/unit/linear.js b/test/unit/linear.js index 500d63326..c6d29a7de 100644 --- a/test/unit/linear.js +++ b/test/unit/linear.js @@ -9,82 +9,82 @@ const fixtures = require('../fixtures'); const { describe, it } = require('node:test'); const assert = require('node:assert'); -describe('Linear adjustment', function () { +describe('Linear adjustment', () => { const blackPoint = 70; const whitePoint = 203; const a = 255 / (whitePoint - blackPoint); const b = -blackPoint * a; - it('applies linear levels adjustment w/o alpha ch', function (_t, done) { + it('applies linear levels adjustment w/o alpha ch', (_t, done) => { sharp(fixtures.inputJpgWithLowContrast) .linear(a, b) - .toBuffer(function (err, data) { + .toBuffer((err, data) => { if (err) throw err; fixtures.assertSimilar(fixtures.expected('low-contrast-linear.jpg'), data, done); }); }); - it('applies slope level adjustment w/o alpha ch', function (_t, done) { + it('applies slope level adjustment w/o alpha ch', (_t, done) => { sharp(fixtures.inputJpgWithLowContrast) .linear(a) - .toBuffer(function (err, data) { + .toBuffer((err, data) => { if (err) throw err; fixtures.assertSimilar(fixtures.expected('low-contrast-slope.jpg'), data, done); }); }); - it('applies offset level adjustment w/o alpha ch', function (_t, done) { + it('applies offset level adjustment w/o alpha ch', (_t, done) => { sharp(fixtures.inputJpgWithLowContrast) .linear(null, b) - .toBuffer(function (err, data) { + .toBuffer((err, data) => { if (err) throw err; fixtures.assertSimilar(fixtures.expected('low-contrast-offset.jpg'), data, done); }); }); - it('applies linear levels adjustment w alpha ch', function (_t, done) { + it('applies linear levels adjustment w alpha ch', (_t, done) => { sharp(fixtures.inputPngOverlayLayer1) .resize(240) .linear(a, b) - .toBuffer(function (err, data) { + .toBuffer((err, data) => { if (err) throw err; fixtures.assertSimilar(fixtures.expected('alpha-layer-1-fill-linear.png'), data, done); }); }); - it('applies linear levels adjustment to 16-bit w alpha ch', function (_t, done) { + it('applies linear levels adjustment to 16-bit w alpha ch', (_t, done) => { sharp(fixtures.inputPngWithTransparency16bit) .linear(a, b) .png({ compressionLevel: 0 }) - .toBuffer(function (err, data) { + .toBuffer((err, data) => { if (err) throw err; fixtures.assertSimilar(fixtures.expected('linear-16bit.png'), data, done); }); }); - it('applies slope level adjustment w alpha ch', function (_t, done) { + it('applies slope level adjustment w alpha ch', (_t, done) => { sharp(fixtures.inputPngOverlayLayer1) .resize(240) .linear(a) - .toBuffer(function (err, data) { + .toBuffer((err, data) => { if (err) throw err; fixtures.assertSimilar(fixtures.expected('alpha-layer-1-fill-slope.png'), data, done); }); }); - it('applies offset level adjustment w alpha ch', function (_t, done) { + it('applies offset level adjustment w alpha ch', (_t, done) => { sharp(fixtures.inputPngOverlayLayer1) .resize(240) .linear(null, b) - .toBuffer(function (err, data) { + .toBuffer((err, data) => { if (err) throw err; fixtures.assertSimilar(fixtures.expected('alpha-layer-1-fill-offset.png'), data, done); }); }); - it('per channel level adjustment', function (_t, done) { + it('per channel level adjustment', (_t, done) => { sharp(fixtures.inputWebP) - .linear([0.25, 0.5, 0.75], [150, 100, 50]).toBuffer(function (err, data) { + .linear([0.25, 0.5, 0.75], [150, 100, 50]).toBuffer((err, data) => { if (err) throw err; fixtures.assertSimilar(fixtures.expected('linear-per-channel.jpg'), data, done); }); @@ -112,7 +112,7 @@ describe('Linear adjustment', function () { assert.strictEqual(depth, 'uchar'); }); - it('Invalid linear arguments', function () { + it('Invalid linear arguments', () => { assert.throws( () => sharp().linear('foo'), /Expected number or array of numbers for a but received foo of type string/ diff --git a/test/unit/median.js b/test/unit/median.js index 97b706512..14d63d566 100644 --- a/test/unit/median.js +++ b/test/unit/median.js @@ -16,7 +16,7 @@ const raw = { channels: 1 }; -describe('Median filter', function () { +describe('Median filter', () => { it('default window (3x3)', async () => { const data = await sharp(input, { raw }) .median() diff --git a/test/unit/metadata.js b/test/unit/metadata.js index 75a6919c7..0e7b4747b 100644 --- a/test/unit/metadata.js +++ b/test/unit/metadata.js @@ -14,9 +14,9 @@ const fixtures = require('../fixtures'); const create = { width: 1, height: 1, channels: 3, background: 'red' }; -describe('Image metadata', function () { - it('JPEG', function (_t, done) { - sharp(fixtures.inputJpg).metadata(function (err, metadata) { +describe('Image metadata', () => { + it('JPEG', (_t, done) => { + sharp(fixtures.inputJpg).metadata((err, metadata) => { if (err) throw err; assert.strictEqual('jpeg', metadata.format); assert.strictEqual('undefined', typeof metadata.size); @@ -37,8 +37,8 @@ describe('Image metadata', function () { }); }); - it('JPEG with EXIF/ICC', function (_t, done) { - sharp(fixtures.inputJpgWithExif).metadata(function (err, metadata) { + it('JPEG with EXIF/ICC', (_t, done) => { + sharp(fixtures.inputJpgWithExif).metadata((err, metadata) => { if (err) throw err; assert.strictEqual('jpeg', metadata.format); assert.strictEqual('undefined', typeof metadata.size); @@ -70,8 +70,8 @@ describe('Image metadata', function () { }); }); - it('JPEG with IPTC/XMP', function (_t, done) { - sharp(fixtures.inputJpgWithIptcAndXmp).metadata(function (err, metadata) { + it('JPEG with IPTC/XMP', (_t, done) => { + sharp(fixtures.inputJpgWithIptcAndXmp).metadata((err, metadata) => { if (err) throw err; // IPTC assert.strictEqual('object', typeof metadata.iptc); @@ -88,8 +88,8 @@ describe('Image metadata', function () { }); }); - it('TIFF', function (_t, done) { - sharp(fixtures.inputTiff).metadata(function (err, metadata) { + it('TIFF', (_t, done) => { + sharp(fixtures.inputTiff).metadata((err, metadata) => { if (err) throw err; assert.strictEqual('tiff', metadata.format); assert.strictEqual('undefined', typeof metadata.size); @@ -115,8 +115,8 @@ describe('Image metadata', function () { }); }); - it('Multipage TIFF', function (_t, done) { - sharp(fixtures.inputTiffMultipage).metadata(function (err, metadata) { + it('Multipage TIFF', (_t, done) => { + sharp(fixtures.inputTiffMultipage).metadata((err, metadata) => { if (err) throw err; assert.strictEqual('tiff', metadata.format); assert.strictEqual('undefined', typeof metadata.size); @@ -138,8 +138,8 @@ describe('Image metadata', function () { }); }); - it('PNG', function (_t, done) { - sharp(fixtures.inputPng).metadata(function (err, metadata) { + it('PNG', (_t, done) => { + sharp(fixtures.inputPng).metadata((err, metadata) => { if (err) throw err; assert.strictEqual('png', metadata.format); assert.strictEqual('undefined', typeof metadata.size); @@ -162,8 +162,8 @@ describe('Image metadata', function () { }); }); - it('PNG with comment', function (_t, done) { - sharp(fixtures.inputPngTestJoinChannel).metadata(function (err, metadata) { + it('PNG with comment', (_t, done) => { + sharp(fixtures.inputPngTestJoinChannel).metadata((err, metadata) => { if (err) throw err; assert.strictEqual('png', metadata.format); assert.strictEqual('undefined', typeof metadata.size); @@ -187,8 +187,8 @@ describe('Image metadata', function () { }); }); - it('Transparent PNG', function (_t, done) { - sharp(fixtures.inputPngWithTransparency).metadata(function (err, metadata) { + it('Transparent PNG', (_t, done) => { + sharp(fixtures.inputPngWithTransparency).metadata((err, metadata) => { if (err) throw err; assert.strictEqual('png', metadata.format); assert.strictEqual('undefined', typeof metadata.size); @@ -259,8 +259,8 @@ describe('Image metadata', function () { }); }); - it('WebP', function (_t, done) { - sharp(fixtures.inputWebP).metadata(function (err, metadata) { + it('WebP', (_t, done) => { + sharp(fixtures.inputWebP).metadata((err, metadata) => { if (err) throw err; assert.strictEqual('webp', metadata.format); assert.strictEqual('undefined', typeof metadata.size); @@ -351,8 +351,8 @@ describe('Image metadata', function () { }) ); - it('GIF', function (_t, done) { - sharp(fixtures.inputGif).metadata(function (err, metadata) { + it('GIF', (_t, done) => { + sharp(fixtures.inputGif).metadata((err, metadata) => { if (err) throw err; assert.strictEqual('gif', metadata.format); assert.strictEqual('undefined', typeof metadata.size); @@ -371,8 +371,8 @@ describe('Image metadata', function () { done(); }); }); - it('GIF grey+alpha', function (_t, done) { - sharp(fixtures.inputGifGreyPlusAlpha).metadata(function (err, metadata) { + it('GIF grey+alpha', (_t, done) => { + sharp(fixtures.inputGifGreyPlusAlpha).metadata((err, metadata) => { if (err) throw err; assert.strictEqual('gif', metadata.format); assert.strictEqual('undefined', typeof metadata.size); @@ -459,8 +459,8 @@ describe('Image metadata', function () { }) ); - it('File in, Promise out', function (_t, done) { - sharp(fixtures.inputJpg).metadata().then(function (metadata) { + it('File in, Promise out', (_t, done) => { + sharp(fixtures.inputJpg).metadata().then((metadata) => { assert.strictEqual('jpeg', metadata.format); assert.strictEqual('undefined', typeof metadata.size); assert.strictEqual(2725, metadata.width); @@ -503,10 +503,10 @@ describe('Image metadata', function () { ); }); - it('Stream in, Promise out', function (_t, done) { + it('Stream in, Promise out', (_t, done) => { const readable = fs.createReadStream(fixtures.inputJpg); const pipeline = sharp(); - pipeline.metadata().then(function (metadata) { + pipeline.metadata().then((metadata) => { assert.strictEqual('jpeg', metadata.format); assert.strictEqual(829183, metadata.size); assert.strictEqual(2725, metadata.width); @@ -554,9 +554,9 @@ describe('Image metadata', function () { }, 500); }); - it('Stream', function (_t, done) { + it('Stream', (_t, done) => { const readable = fs.createReadStream(fixtures.inputJpg); - const pipeline = sharp().metadata(function (err, metadata) { + const pipeline = sharp().metadata((err, metadata) => { if (err) throw err; assert.strictEqual('jpeg', metadata.format); assert.strictEqual(829183, metadata.size); @@ -578,9 +578,9 @@ describe('Image metadata', function () { readable.pipe(pipeline); }); - it('Resize to half width using metadata', function (_t, done) { + it('Resize to half width using metadata', (_t, done) => { const image = sharp(fixtures.inputJpg); - image.metadata(function (err, metadata) { + image.metadata((err, metadata) => { if (err) throw err; assert.strictEqual('jpeg', metadata.format); assert.strictEqual('undefined', typeof metadata.size); @@ -597,7 +597,7 @@ describe('Image metadata', function () { assert.strictEqual('undefined', typeof metadata.orientation); assert.strictEqual('undefined', typeof metadata.exif); assert.strictEqual('undefined', typeof metadata.icc); - image.resize(Math.floor(metadata.width / 2)).toBuffer(function (err, data, info) { + image.resize(Math.floor(metadata.width / 2)).toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual(1362, info.width); @@ -607,13 +607,13 @@ describe('Image metadata', function () { }); }); - it('Keep EXIF metadata and add sRGB profile after a resize', function (_t, done) { + it('Keep EXIF metadata and add sRGB profile after a resize', (_t, done) => { sharp(fixtures.inputJpgWithExif) .resize(320, 240) .withMetadata() - .toBuffer(function (err, buffer) { + .toBuffer((err, buffer) => { if (err) throw err; - sharp(buffer).metadata(function (err, metadata) { + sharp(buffer).metadata((err, metadata) => { if (err) throw err; assert.strictEqual(true, metadata.hasProfile); assert.strictEqual(8, metadata.orientation); @@ -727,14 +727,14 @@ describe('Image metadata', function () { assert.strictEqual(undefined, metadata.icc); }); - it('Apply CMYK output ICC profile', function (_t, done) { + it('Apply CMYK output ICC profile', (_t, done) => { const output = fixtures.path('output.icc-cmyk.jpg'); sharp(fixtures.inputJpg) .resize(64) .withIccProfile('cmyk') - .toFile(output, function (err) { + .toFile(output, (err) => { if (err) throw err; - sharp(output).metadata(function (err, metadata) { + sharp(output).metadata((err, metadata) => { if (err) throw err; assert.strictEqual(true, metadata.hasProfile); assert.strictEqual('cmyk', metadata.space); @@ -752,12 +752,12 @@ describe('Image metadata', function () { }); }); - it('Apply custom output ICC profile', function (_t, done) { + it('Apply custom output ICC profile', (_t, done) => { const output = fixtures.path('output.hilutite.jpg'); sharp(fixtures.inputJpg) .resize(64) .withIccProfile(fixtures.path('hilutite.icm')) - .toFile(output, function (err) { + .toFile(output, (err) => { if (err) throw err; fixtures.assertMaxColourDistance(output, fixtures.expected('hilutite.jpg'), 9); done(); @@ -792,12 +792,12 @@ describe('Image metadata', function () { ) ); - it('Remove EXIF metadata after a resize', function (_t, done) { + it('Remove EXIF metadata after a resize', (_t, done) => { sharp(fixtures.inputJpgWithExif) .resize(320, 240) - .toBuffer(function (err, buffer) { + .toBuffer((err, buffer) => { if (err) throw err; - sharp(buffer).metadata(function (err, metadata) { + sharp(buffer).metadata((err, metadata) => { if (err) throw err; assert.strictEqual(false, metadata.hasProfile); assert.strictEqual('undefined', typeof metadata.orientation); @@ -808,12 +808,12 @@ describe('Image metadata', function () { }); }); - it('Remove metadata from PNG output', function (_t, done) { + it('Remove metadata from PNG output', (_t, done) => { sharp(fixtures.inputJpgWithExif) .png() - .toBuffer(function (err, buffer) { + .toBuffer((err, buffer) => { if (err) throw err; - sharp(buffer).metadata(function (err, metadata) { + sharp(buffer).metadata((err, metadata) => { if (err) throw err; assert.strictEqual(false, metadata.hasProfile); assert.strictEqual('undefined', typeof metadata.orientation); @@ -865,55 +865,41 @@ describe('Image metadata', function () { assert.strictEqual(density, 96); }); - it('chromaSubsampling 4:4:4:4 CMYK JPEG', function () { - return sharp(fixtures.inputJpgWithCmykProfile) + it('chromaSubsampling 4:4:4:4 CMYK JPEG', () => sharp(fixtures.inputJpgWithCmykProfile) .metadata() - .then(function (metadata) { + .then((metadata) => { assert.strictEqual('4:4:4:4', metadata.chromaSubsampling); - }); - }); + })); - it('chromaSubsampling 4:4:4 RGB JPEG', function () { - return sharp(fixtures.inputJpg) + it('chromaSubsampling 4:4:4 RGB JPEG', () => sharp(fixtures.inputJpg) .resize(10, 10) .jpeg({ chromaSubsampling: '4:4:4' }) .toBuffer() - .then(function (data) { - return sharp(data) + .then((data) => sharp(data) .metadata() - .then(function (metadata) { + .then((metadata) => { assert.strictEqual('4:4:4', metadata.chromaSubsampling); - }); - }); - }); + }))); - it('isProgressive JPEG', function () { - return sharp(fixtures.inputJpg) + it('isProgressive JPEG', () => sharp(fixtures.inputJpg) .resize(10, 10) .jpeg({ progressive: true }) .toBuffer() - .then(function (data) { - return sharp(data) + .then((data) => sharp(data) .metadata() - .then(function (metadata) { + .then((metadata) => { assert.strictEqual(true, metadata.isProgressive); - }); - }); - }); + }))); - it('isProgressive PNG', function () { - return sharp(fixtures.inputJpg) + it('isProgressive PNG', () => sharp(fixtures.inputJpg) .resize(10, 10) .png({ progressive: true }) .toBuffer() - .then(function (data) { - return sharp(data) + .then((data) => sharp(data) .metadata() - .then(function (metadata) { + .then((metadata) => { assert.strictEqual(true, metadata.isProgressive); - }); - }); - }); + }))); it('16-bit TIFF with TIFFTAG_PHOTOSHOP metadata', () => sharp(fixtures.inputTifftagPhotoshop) @@ -995,18 +981,18 @@ describe('Image metadata', function () { assert.strictEqual(description, 'sP3C'); }); - it('File input with corrupt header fails gracefully', function (_t, done) { + it('File input with corrupt header fails gracefully', (_t, done) => { sharp(fixtures.inputJpgWithCorruptHeader) - .metadata(function (err) { + .metadata((err) => { assert.strictEqual(true, !!err); assert.ok(err.message.includes('Input file has corrupt header: VipsJpeg: premature end of'), err); done(); }); }); - it('Buffer input with corrupt header fails gracefully', function (_t, done) { + it('Buffer input with corrupt header fails gracefully', (_t, done) => { sharp(fs.readFileSync(fixtures.inputJpgWithCorruptHeader)) - .metadata(function (err) { + .metadata((err) => { assert.strictEqual(true, !!err); assert.ok(err.message.includes('Input buffer has corrupt header: VipsJpeg: premature end of'), err); done(); @@ -1114,7 +1100,7 @@ describe('Image metadata', function () { assert.strictEqual(exif2.Image.Software, 'sharp'); }); - describe('XMP metadata tests', function () { + describe('XMP metadata tests', () => { it('withMetadata preserves existing XMP metadata from input', async () => { const data = await sharp(fixtures.inputJpgWithIptcAndXmp) .resize(320, 240) @@ -1256,21 +1242,21 @@ describe('Image metadata', function () { assert.strictEqual(true, xmpString.includes('image/webp')); }); - it('withXmp XMP validation - non-string input', function () { + it('withXmp XMP validation - non-string input', () => { assert.throws( () => sharp().withXmp(123), /Expected non-empty string for xmp but received 123 of type number/ ); }); - it('withXmp XMP validation - null input', function () { + it('withXmp XMP validation - null input', () => { assert.throws( () => sharp().withXmp(null), /Expected non-empty string for xmp but received null of type object/ ); }); - it('withXmp XMP validation - empty string', function () { + it('withXmp XMP validation - empty string', () => { assert.throws( () => sharp().withXmp(''), /Expected non-empty string for xmp/ @@ -1278,54 +1264,54 @@ describe('Image metadata', function () { }); }); - describe('Invalid parameters', function () { - it('String orientation', function () { - assert.throws(function () { + describe('Invalid parameters', () => { + it('String orientation', () => { + assert.throws(() => { sharp().withMetadata({ orientation: 'zoinks' }); }); }); - it('Negative orientation', function () { - assert.throws(function () { + it('Negative orientation', () => { + assert.throws(() => { sharp().withMetadata({ orientation: -1 }); }); }); - it('Zero orientation', function () { - assert.throws(function () { + it('Zero orientation', () => { + assert.throws(() => { sharp().withMetadata({ orientation: 0 }); }); }); - it('Too large orientation', function () { - assert.throws(function () { + it('Too large orientation', () => { + assert.throws(() => { sharp().withMetadata({ orientation: 9 }); }); }); - it('Non-numeric density', function () { - assert.throws(function () { + it('Non-numeric density', () => { + assert.throws(() => { sharp().withMetadata({ density: '1' }); }); }); - it('Negative density', function () { - assert.throws(function () { + it('Negative density', () => { + assert.throws(() => { sharp().withMetadata({ density: -1 }); }); }); - it('Non string icc', function () { - assert.throws(function () { + it('Non string icc', () => { + assert.throws(() => { sharp().withMetadata({ icc: true }); }); }); - it('Non object exif', function () { - assert.throws(function () { + it('Non object exif', () => { + assert.throws(() => { sharp().withMetadata({ exif: false }); }); }); - it('Non string value in object exif', function () { - assert.throws(function () { + it('Non string value in object exif', () => { + assert.throws(() => { sharp().withMetadata({ exif: { ifd0: false } }); }); }); - it('Non string value in nested object exif', function () { - assert.throws(function () { + it('Non string value in nested object exif', () => { + assert.throws(() => { sharp().withMetadata({ exif: { ifd0: { fail: false } } }); }); }); diff --git a/test/unit/modulate.js b/test/unit/modulate.js index fcf0935b2..40c5b83f1 100644 --- a/test/unit/modulate.js +++ b/test/unit/modulate.js @@ -8,8 +8,8 @@ const { describe, it } = require('node:test'); const assert = require('node:assert'); const fixtures = require('../fixtures'); -describe('Modulate', function () { - describe('Invalid options', function () { +describe('Modulate', () => { + describe('Invalid options', () => { [ null, undefined, @@ -25,9 +25,9 @@ describe('Modulate', function () { { hue: null }, { lightness: '+50' }, { lightness: null } - ].forEach(function (options) { - it('should throw', function () { - assert.throws(function () { + ].forEach((options) => { + it('should throw', () => { + assert.throws(() => { sharp(fixtures.inputJpg).modulate(options); }); }); diff --git a/test/unit/negate.js b/test/unit/negate.js index 825f26700..87196a592 100644 --- a/test/unit/negate.js +++ b/test/unit/negate.js @@ -9,12 +9,12 @@ const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); -describe('Negate', function () { - it('negate (jpeg)', function (_t, done) { +describe('Negate', () => { + it('negate (jpeg)', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .negate() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -23,11 +23,11 @@ describe('Negate', function () { }); }); - it('negate (png)', function (_t, done) { + it('negate (png)', (_t, done) => { sharp(fixtures.inputPng) .resize(320, 240) .negate() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(320, info.width); @@ -36,11 +36,11 @@ describe('Negate', function () { }); }); - it('negate (png, trans)', function (_t, done) { + it('negate (png, trans)', (_t, done) => { sharp(fixtures.inputPngWithTransparency) .resize(320, 240) .negate() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(320, info.width); @@ -49,11 +49,11 @@ describe('Negate', function () { }); }); - it('negate (png, alpha)', function (_t, done) { + it('negate (png, alpha)', (_t, done) => { sharp(fixtures.inputPngWithGreyAlpha) .resize(320, 240) .negate() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(320, info.width); @@ -62,11 +62,11 @@ describe('Negate', function () { }); }); - it('negate (webp)', function (_t, done) { + it('negate (webp)', (_t, done) => { sharp(fixtures.inputWebP) .resize(320, 240) .negate() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('webp', info.format); assert.strictEqual(320, info.width); @@ -75,11 +75,11 @@ describe('Negate', function () { }); }); - it('negate (webp, trans)', function (_t, done) { + it('negate (webp, trans)', (_t, done) => { sharp(fixtures.inputWebPWithTransparency) .resize(320, 240) .negate() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('webp', info.format); assert.strictEqual(320, info.width); @@ -88,11 +88,11 @@ describe('Negate', function () { }); }); - it('negate (true)', function (_t, done) { + it('negate (true)', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .negate(true) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -101,22 +101,22 @@ describe('Negate', function () { }); }); - it('negate (false)', function (_t, done) { + it('negate (false)', (_t, done) => { const output = fixtures.path('output.unmodified-by-negate.png'); sharp(fixtures.inputJpgWithLowContrast) .negate(false) - .toFile(output, function (err) { + .toFile(output, (err) => { if (err) throw err; fixtures.assertMaxColourDistance(output, fixtures.inputJpgWithLowContrast, 0); done(); }); }); - it('negate ({alpha: true})', function (_t, done) { + it('negate ({alpha: true})', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .negate({ alpha: true }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -125,11 +125,11 @@ describe('Negate', function () { }); }); - it('negate non-alpha channels (png)', function (_t, done) { + it('negate non-alpha channels (png)', (_t, done) => { sharp(fixtures.inputPng) .resize(320, 240) .negate({ alpha: false }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(320, info.width); @@ -138,11 +138,11 @@ describe('Negate', function () { }); }); - it('negate non-alpha channels (png, trans)', function (_t, done) { + it('negate non-alpha channels (png, trans)', (_t, done) => { sharp(fixtures.inputPngWithTransparency) .resize(320, 240) .negate({ alpha: false }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(320, info.width); @@ -151,11 +151,11 @@ describe('Negate', function () { }); }); - it('negate non-alpha channels (png, alpha)', function (_t, done) { + it('negate non-alpha channels (png, alpha)', (_t, done) => { sharp(fixtures.inputPngWithGreyAlpha) .resize(320, 240) .negate({ alpha: false }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(320, info.width); @@ -164,11 +164,11 @@ describe('Negate', function () { }); }); - it('negate non-alpha channels (webp)', function (_t, done) { + it('negate non-alpha channels (webp)', (_t, done) => { sharp(fixtures.inputWebP) .resize(320, 240) .negate({ alpha: false }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('webp', info.format); assert.strictEqual(320, info.width); @@ -177,11 +177,11 @@ describe('Negate', function () { }); }); - it('negate non-alpha channels (webp, trans)', function (_t, done) { + it('negate non-alpha channels (webp, trans)', (_t, done) => { sharp(fixtures.inputWebPWithTransparency) .resize(320, 240) .negate({ alpha: false }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('webp', info.format); assert.strictEqual(320, info.width); @@ -206,8 +206,8 @@ describe('Negate', function () { assert.deepStrictEqual({ r, g, b }, { r: 245, g: 235, b: 225 }); }); - it('invalid alpha value', function () { - assert.throws(function () { + it('invalid alpha value', () => { + assert.throws(() => { sharp(fixtures.inputWebPWithTransparency).negate({ alpha: 'non-bool' }); }); }); diff --git a/test/unit/noise.js b/test/unit/noise.js index 8a606a710..c95006b6d 100644 --- a/test/unit/noise.js +++ b/test/unit/noise.js @@ -9,8 +9,8 @@ const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); -describe('Gaussian noise', function () { - it('generate single-channel gaussian noise', function (_t, done) { +describe('Gaussian noise', () => { + it('generate single-channel gaussian noise', (_t, done) => { const output = fixtures.path('output.noise-1-channel.png'); const noise = sharp({ create: { @@ -24,13 +24,13 @@ describe('Gaussian noise', function () { } } }).toColourspace('b-w'); - noise.toFile(output, function (err, info) { + noise.toFile(output, (err, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(1024, info.width); assert.strictEqual(768, info.height); assert.strictEqual(1, info.channels); - sharp(output).metadata(function (err, metadata) { + sharp(output).metadata((err, metadata) => { if (err) throw err; assert.strictEqual('b-w', metadata.space); assert.strictEqual('uchar', metadata.depth); @@ -39,7 +39,7 @@ describe('Gaussian noise', function () { }); }); - it('generate 3-channels gaussian noise', function (_t, done) { + it('generate 3-channels gaussian noise', (_t, done) => { const output = fixtures.path('output.noise-3-channels.png'); const noise = sharp({ create: { @@ -53,13 +53,13 @@ describe('Gaussian noise', function () { } } }); - noise.toFile(output, function (err, info) { + noise.toFile(output, (err, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(1024, info.width); assert.strictEqual(768, info.height); assert.strictEqual(3, info.channels); - sharp(output).metadata(function (err, metadata) { + sharp(output).metadata((err, metadata) => { if (err) throw err; assert.strictEqual('srgb', metadata.space); assert.strictEqual('uchar', metadata.depth); @@ -68,7 +68,7 @@ describe('Gaussian noise', function () { }); }); - it('overlay 3-channels gaussian noise over image', function (_t, done) { + it('overlay 3-channels gaussian noise over image', (_t, done) => { const output = fixtures.path('output.noise-image.jpg'); const noise = sharp({ create: { @@ -82,7 +82,7 @@ describe('Gaussian noise', function () { } } }); - noise.toBuffer(function (err, data, info) { + noise.toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(3, info.channels); sharp(fixtures.inputJpg) @@ -98,14 +98,14 @@ describe('Gaussian noise', function () { } } ]) - .toFile(output, function (err, info) { + .toFile(output, (err, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); assert.strictEqual(3, info.channels); // perceptual hashing detects that images are the same (difference is <=1%) - fixtures.assertSimilar(output, fixtures.inputJpg, function (err) { + fixtures.assertSimilar(output, fixtures.inputJpg, (err) => { if (err) throw err; done(); }); @@ -113,7 +113,7 @@ describe('Gaussian noise', function () { }); }); - it('overlay strong single-channel (sRGB) gaussian noise with 25% transparency over transparent png image', function (_t, done) { + it('overlay strong single-channel (sRGB) gaussian noise with 25% transparency over transparent png image', (_t, done) => { const output = fixtures.path('output.noise-image-transparent.png'); const width = 320; const height = 240; @@ -136,14 +136,14 @@ describe('Gaussian noise', function () { }); noise .toColourspace('b-w') - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(1, info.channels); sharp(data, { raw: rawData }) .joinChannel(data, { raw: rawData }) // r channel .joinChannel(data, { raw: rawData }) // b channel .joinChannel(Buffer.alloc(width * height, 64), { raw: rawData }) // alpha channel - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(4, info.channels); sharp(fixtures.inputPngRGBWithAlpha) @@ -159,13 +159,13 @@ describe('Gaussian noise', function () { } } ]) - .toFile(output, function (err, info) { + .toFile(output, (err, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(width, info.width); assert.strictEqual(height, info.height); assert.strictEqual(4, info.channels); - fixtures.assertSimilar(output, fixtures.inputPngRGBWithAlpha, { threshold: 10 }, function (err) { + fixtures.assertSimilar(output, fixtures.inputPngRGBWithAlpha, { threshold: 10 }, (err) => { if (err) throw err; done(); }); @@ -194,16 +194,16 @@ describe('Gaussian noise', function () { assert.strictEqual(delay.length, 4); }); - it('no create object properties specified', function () { - assert.throws(function () { + it('no create object properties specified', () => { + assert.throws(() => { sharp({ create: {} }); }); }); - it('invalid noise object', function () { - assert.throws(function () { + it('invalid noise object', () => { + assert.throws(() => { sharp({ create: { width: 100, @@ -215,8 +215,8 @@ describe('Gaussian noise', function () { }); }); - it('unknown type of noise', function () { - assert.throws(function () { + it('unknown type of noise', () => { + assert.throws(() => { sharp({ create: { width: 100, @@ -230,8 +230,8 @@ describe('Gaussian noise', function () { }); }); - it('gaussian noise, invalid amount of channels', function () { - assert.throws(function () { + it('gaussian noise, invalid amount of channels', () => { + assert.throws(() => { sharp({ create: { width: 100, @@ -247,8 +247,8 @@ describe('Gaussian noise', function () { }); }); - it('gaussian noise, invalid mean', function () { - assert.throws(function () { + it('gaussian noise, invalid mean', () => { + assert.throws(() => { sharp({ create: { width: 100, @@ -264,8 +264,8 @@ describe('Gaussian noise', function () { }); }); - it('gaussian noise, invalid sigma', function () { - assert.throws(function () { + it('gaussian noise, invalid sigma', () => { + assert.throws(() => { sharp({ create: { width: 100, diff --git a/test/unit/normalize.js b/test/unit/normalize.js index 748b68343..2c0cf32c6 100644 --- a/test/unit/normalize.js +++ b/test/unit/normalize.js @@ -9,7 +9,7 @@ const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); -const assertNormalized = function (data) { +const assertNormalized = (data) => { let min = 255; let max = 0; for (let i = 0; i < data.length; i++) { @@ -20,48 +20,48 @@ const assertNormalized = function (data) { assert.ok(max > 248, 'max too low'); }; -describe('Normalization', function () { - it('spreads rgb image values between 0 and 255', function (_t, done) { +describe('Normalization', () => { + it('spreads rgb image values between 0 and 255', (_t, done) => { sharp(fixtures.inputJpgWithLowContrast) .normalise() .raw() - .toBuffer(function (err, data) { + .toBuffer((err, data) => { if (err) throw err; assertNormalized(data); done(); }); }); - it('spreads grayscaled image values between 0 and 255', function (_t, done) { + it('spreads grayscaled image values between 0 and 255', (_t, done) => { sharp(fixtures.inputJpgWithLowContrast) .greyscale() .normalize() .raw() - .toBuffer(function (err, data) { + .toBuffer((err, data) => { if (err) throw err; assertNormalized(data); done(); }); }); - it('stretches greyscale images with alpha channel', function (_t, done) { + it('stretches greyscale images with alpha channel', (_t, done) => { sharp(fixtures.inputPngWithGreyAlpha) .normalise() .raw() - .toBuffer(function (err, data) { + .toBuffer((err, data) => { if (err) throw err; assertNormalized(data); done(); }); }); - it('keeps an existing alpha channel', function (_t, done) { + it('keeps an existing alpha channel', (_t, done) => { sharp(fixtures.inputPngWithTransparency) .resize(8, 8) .normalize() - .toBuffer(function (err, data) { + .toBuffer((err, data) => { if (err) throw err; - sharp(data).metadata(function (err, metadata) { + sharp(data).metadata((err, metadata) => { if (err) return done(err); assert.strictEqual(4, metadata.channels); assert.strictEqual(true, metadata.hasAlpha); @@ -71,13 +71,13 @@ describe('Normalization', function () { }); }); - it('keeps the alpha channel of greyscale images intact', function (_t, done) { + it('keeps the alpha channel of greyscale images intact', (_t, done) => { sharp(fixtures.inputPngWithGreyAlpha) .resize(8, 8) .normalise() - .toBuffer(function (err, data) { + .toBuffer((err, data) => { if (err) throw err; - sharp(data).metadata(function (err, metadata) { + sharp(data).metadata((err, metadata) => { if (err) return done(err); assert.strictEqual(true, metadata.hasAlpha); assert.strictEqual(4, metadata.channels); @@ -87,76 +87,76 @@ describe('Normalization', function () { }); }); - it('does not alter images with only one color', function (_t, done) { + it('does not alter images with only one color', (_t, done) => { const output = fixtures.path('output.unmodified-png-with-one-color.png'); sharp(fixtures.inputPngWithOneColor) .normalize() - .toFile(output, function (err) { + .toFile(output, (err) => { if (err) done(err); fixtures.assertMaxColourDistance(output, fixtures.inputPngWithOneColor, 0); done(); }); }); - it('works with 16-bit RGBA images', function (_t, done) { + it('works with 16-bit RGBA images', (_t, done) => { sharp(fixtures.inputPngWithTransparency16bit) .normalise() .raw() - .toBuffer(function (err, data) { + .toBuffer((err, data) => { if (err) throw err; assertNormalized(data); done(); }); }); - it('should handle luminance range', function (_t, done) { + it('should handle luminance range', (_t, done) => { sharp(fixtures.inputJpgWithLowContrast) .normalise({ lower: 10, upper: 70 }) .raw() - .toBuffer(function (err, data) { + .toBuffer((err, data) => { if (err) throw err; assertNormalized(data); done(); }); }); - it('should allow lower without upper', function () { + it('should allow lower without upper', () => { assert.doesNotThrow(() => sharp().normalize({ lower: 2 })); }); - it('should allow upper without lower', function () { + it('should allow upper without lower', () => { assert.doesNotThrow(() => sharp().normalize({ upper: 98 })); }); - it('should throw when lower is out of range', function () { + it('should throw when lower is out of range', () => { assert.throws( () => sharp().normalise({ lower: -10 }), /Expected number between 0 and 99 for lower but received -10 of type number/ ); }); - it('should throw when upper is out of range', function () { + it('should throw when upper is out of range', () => { assert.throws( () => sharp().normalise({ upper: 110 }), /Expected number between 1 and 100 for upper but received 110 of type number/ ); }); - it('should throw when lower is not a number', function () { + it('should throw when lower is not a number', () => { assert.throws( () => sharp().normalise({ lower: 'fail' }), /Expected number between 0 and 99 for lower but received fail of type string/ ); }); - it('should throw when upper is not a number', function () { + it('should throw when upper is not a number', () => { assert.throws( () => sharp().normalise({ upper: 'fail' }), /Expected number between 1 and 100 for upper but received fail of type string/ ); }); - it('should throw when the lower and upper are equal', function () { + it('should throw when the lower and upper are equal', () => { assert.throws( () => sharp().normalise({ lower: 2, upper: 2 }), /Expected lower to be less than upper for range but received 2 >= 2/ ); }); - it('should throw when the lower is greater than upper', function () { + it('should throw when the lower is greater than upper', () => { assert.throws( () => sharp().normalise({ lower: 3, upper: 2 }), /Expected lower to be less than upper for range but received 3 >= 2/ diff --git a/test/unit/png.js b/test/unit/png.js index d7eb31218..81800e1a7 100644 --- a/test/unit/png.js +++ b/test/unit/png.js @@ -10,25 +10,25 @@ const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); -describe('PNG', function () { - it('compression level is valid', function () { - assert.doesNotThrow(function () { +describe('PNG', () => { + it('compression level is valid', () => { + assert.doesNotThrow(() => { sharp().png({ compressionLevel: 0 }); }); }); - it('compression level is invalid', function () { - assert.throws(function () { + it('compression level is invalid', () => { + assert.throws(() => { sharp().png({ compressionLevel: -1 }); }); }); - it('default compressionLevel generates smaller file than compressionLevel=0', function (_t, done) { + it('default compressionLevel generates smaller file than compressionLevel=0', (_t, done) => { // First generate with default compressionLevel sharp(fixtures.inputPng) .resize(320, 240) .png() - .toBuffer(function (err, defaultData, defaultInfo) { + .toBuffer((err, defaultData, defaultInfo) => { if (err) throw err; assert.strictEqual(true, defaultData.length > 0); assert.strictEqual('png', defaultInfo.format); @@ -36,7 +36,7 @@ describe('PNG', function () { sharp(fixtures.inputPng) .resize(320, 240) .png({ compressionLevel: 0 }) - .toBuffer(function (err, largerData, largerInfo) { + .toBuffer((err, largerData, largerInfo) => { if (err) throw err; assert.strictEqual(true, largerData.length > 0); assert.strictEqual('png', largerInfo.format); @@ -46,12 +46,12 @@ describe('PNG', function () { }); }); - it('without adaptiveFiltering generates smaller file', function (_t, done) { + it('without adaptiveFiltering generates smaller file', (_t, done) => { // First generate with adaptive filtering sharp(fixtures.inputPng) .resize(320, 240) .png({ adaptiveFiltering: true }) - .toBuffer(function (err, adaptiveData, adaptiveInfo) { + .toBuffer((err, adaptiveData, adaptiveInfo) => { if (err) throw err; assert.strictEqual(true, adaptiveData.length > 0); assert.strictEqual(adaptiveData.length, adaptiveInfo.size); @@ -62,7 +62,7 @@ describe('PNG', function () { sharp(fixtures.inputPng) .resize(320, 240) .png({ adaptiveFiltering: false }) - .toBuffer(function (err, withoutAdaptiveData, withoutAdaptiveInfo) { + .toBuffer((err, withoutAdaptiveData, withoutAdaptiveInfo) => { if (err) throw err; assert.strictEqual(true, withoutAdaptiveData.length > 0); assert.strictEqual(withoutAdaptiveData.length, withoutAdaptiveInfo.size); @@ -75,17 +75,17 @@ describe('PNG', function () { }); }); - it('Invalid PNG adaptiveFiltering value throws error', function () { - assert.throws(function () { + it('Invalid PNG adaptiveFiltering value throws error', () => { + assert.throws(() => { sharp().png({ adaptiveFiltering: 1 }); }); }); - it('Progressive PNG image', function (_t, done) { + it('Progressive PNG image', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .png({ progressive: false }) - .toBuffer(function (err, nonProgressiveData, nonProgressiveInfo) { + .toBuffer((err, nonProgressiveData, nonProgressiveInfo) => { if (err) throw err; assert.strictEqual(true, nonProgressiveData.length > 0); assert.strictEqual(nonProgressiveData.length, nonProgressiveInfo.size); @@ -94,7 +94,7 @@ describe('PNG', function () { assert.strictEqual(240, nonProgressiveInfo.height); sharp(nonProgressiveData) .png({ progressive: true }) - .toBuffer(function (err, progressiveData, progressiveInfo) { + .toBuffer((err, progressiveData, progressiveInfo) => { if (err) throw err; assert.strictEqual(true, progressiveData.length > 0); assert.strictEqual(progressiveData.length, progressiveInfo.size); @@ -107,11 +107,11 @@ describe('PNG', function () { }); }); - it('16-bit grey+alpha PNG identity transform', function () { + it('16-bit grey+alpha PNG identity transform', () => { const actual = fixtures.path('output.16-bit-grey-alpha-identity.png'); return sharp(fixtures.inputPng16BitGreyAlpha) .toFile(actual) - .then(function () { + .then(() => { fixtures.assertMaxColourDistance(actual, fixtures.expected('16-bit-grey-alpha-identity.png')); }); }); @@ -160,30 +160,30 @@ describe('PNG', function () { }); }); - it('Valid PNG libimagequant palette value does not throw error', function () { - assert.doesNotThrow(function () { + it('Valid PNG libimagequant palette value does not throw error', () => { + assert.doesNotThrow(() => { sharp().png({ palette: false }); }); }); - it('Invalid PNG libimagequant palette value throws error', function () { - assert.throws(function () { + it('Invalid PNG libimagequant palette value throws error', () => { + assert.throws(() => { sharp().png({ palette: 'fail' }); }); }); - it('Valid PNG libimagequant quality value produces image of same size or smaller', function () { + it('Valid PNG libimagequant quality value produces image of same size or smaller', () => { const inputPngBuffer = fs.readFileSync(fixtures.inputPng); return Promise.all([ sharp(inputPngBuffer).resize(10).png({ effort: 1, quality: 80 }).toBuffer(), sharp(inputPngBuffer).resize(10).png({ effort: 1, quality: 100 }).toBuffer() - ]).then(function (data) { + ]).then((data) => { assert.strictEqual(true, data[0].length <= data[1].length); }); }); - it('Invalid PNG libimagequant quality value throws error', function () { - assert.throws(function () { + it('Invalid PNG libimagequant quality value throws error', () => { + assert.throws(() => { sharp().png({ quality: 101 }); }); }); @@ -194,24 +194,24 @@ describe('PNG', function () { }); }); - it('Valid PNG libimagequant colours value produces image of same size or smaller', function () { + it('Valid PNG libimagequant colours value produces image of same size or smaller', () => { const inputPngBuffer = fs.readFileSync(fixtures.inputPng); return Promise.all([ sharp(inputPngBuffer).resize(10).png({ colours: 100 }).toBuffer(), sharp(inputPngBuffer).resize(10).png({ colours: 200 }).toBuffer() - ]).then(function (data) { + ]).then((data) => { assert.strictEqual(true, data[0].length <= data[1].length); }); }); - it('Invalid PNG libimagequant colours value throws error', function () { - assert.throws(function () { + it('Invalid PNG libimagequant colours value throws error', () => { + assert.throws(() => { sharp().png({ colours: -1 }); }); }); - it('Invalid PNG libimagequant colors value throws error', function () { - assert.throws(function () { + it('Invalid PNG libimagequant colors value throws error', () => { + assert.throws(() => { sharp().png({ colors: 0.1 }); }); }); @@ -235,18 +235,18 @@ describe('PNG', function () { assert.strictEqual(space, 'b-w'); }); - it('Valid PNG libimagequant dither value produces image of same size or smaller', function () { + it('Valid PNG libimagequant dither value produces image of same size or smaller', () => { const inputPngBuffer = fs.readFileSync(fixtures.inputPng); return Promise.all([ sharp(inputPngBuffer).resize(10).png({ dither: 0.1 }).toBuffer(), sharp(inputPngBuffer).resize(10).png({ dither: 0.9 }).toBuffer() - ]).then(function (data) { + ]).then((data) => { assert.strictEqual(true, data[0].length <= data[1].length); }); }); - it('Invalid PNG libimagequant dither value throws error', function () { - assert.throws(function () { + it('Invalid PNG libimagequant dither value throws error', () => { + assert.throws(() => { sharp().png({ dither: 'fail' }); }); }); diff --git a/test/unit/raw.js b/test/unit/raw.js index 7afca4284..a3e9d563d 100644 --- a/test/unit/raw.js +++ b/test/unit/raw.js @@ -9,49 +9,49 @@ const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); -describe('Raw pixel data', function () { - describe('Raw pixel input', function () { - it('Empty data', function () { - assert.throws(function () { +describe('Raw pixel data', () => { + describe('Raw pixel input', () => { + it('Empty data', () => { + assert.throws(() => { sharp(Buffer.from('')); }, /empty/); - assert.throws(function () { + assert.throws(() => { sharp(new ArrayBuffer(0)); }, /empty/); - assert.throws(function () { + assert.throws(() => { sharp(new Uint8Array(0)); }, /empty/); - assert.throws(function () { + assert.throws(() => { sharp(new Uint8ClampedArray(0)); }, /empty/); }); - it('Missing options', function () { - assert.throws(function () { + it('Missing options', () => { + assert.throws(() => { sharp({ raw: {} }); }); }); - it('Incomplete options', function () { - assert.throws(function () { + it('Incomplete options', () => { + assert.throws(() => { sharp({ raw: { width: 1, height: 1 } }); }); }); - it('Invalid channels', function () { - assert.throws(function () { + it('Invalid channels', () => { + assert.throws(() => { sharp({ raw: { width: 1, height: 1, channels: 5 } }); }); }); - it('Invalid height', function () { - assert.throws(function () { + it('Invalid height', () => { + assert.throws(() => { sharp({ raw: { width: 1, height: 0, channels: 4 } }); }); }); - it('Invalid width', function () { - assert.throws(function () { + it('Invalid width', () => { + assert.throws(() => { sharp({ raw: { width: 'zoinks', height: 1, channels: 4 } }); }); }); @@ -85,12 +85,12 @@ describe('Raw pixel data', function () { ); }); - it('RGB', function (_t, done) { + it('RGB', (_t, done) => { // Convert to raw pixel data sharp(fixtures.inputJpg) .resize(256) .raw() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(256, info.width); assert.strictEqual(209, info.height); @@ -104,7 +104,7 @@ describe('Raw pixel data', function () { } }) .jpeg() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(256, info.width); assert.strictEqual(209, info.height); @@ -114,12 +114,12 @@ describe('Raw pixel data', function () { }); }); - it('RGBA', function (_t, done) { + it('RGBA', (_t, done) => { // Convert to raw pixel data sharp(fixtures.inputPngOverlayLayer1) .resize(256) .raw() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(256, info.width); assert.strictEqual(192, info.height); @@ -133,7 +133,7 @@ describe('Raw pixel data', function () { } }) .png() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(256, info.width); assert.strictEqual(192, info.height); @@ -143,12 +143,12 @@ describe('Raw pixel data', function () { }); }); - it('RGBA premultiplied', function (_t, done) { + it('RGBA premultiplied', (_t, done) => { // Convert to raw pixel data sharp(fixtures.inputPngSolidAlpha) .resize(256) .raw() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(256, info.width); assert.strictEqual(192, info.height); @@ -178,7 +178,7 @@ describe('Raw pixel data', function () { } }) .raw() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(256, info.width); assert.strictEqual(192, info.height); @@ -189,7 +189,7 @@ describe('Raw pixel data', function () { }); }); - it('JPEG to raw Stream and back again', function (_t, done) { + it('JPEG to raw Stream and back again', (_t, done) => { const width = 32; const height = 24; const writable = sharp({ @@ -201,7 +201,7 @@ describe('Raw pixel data', function () { }); writable .jpeg() - .toBuffer(function (err, _data, info) { + .toBuffer((err, _data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(32, info.width); @@ -215,13 +215,13 @@ describe('Raw pixel data', function () { }); }); - describe('Output raw, uncompressed image data', function () { - it('1 channel greyscale image', function (_t, done) { + describe('Output raw, uncompressed image data', () => { + it('1 channel greyscale image', (_t, done) => { sharp(fixtures.inputJpg) .greyscale() .resize(32, 24) .raw() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(32 * 24 * 1, info.size); assert.strictEqual(data.length, info.size); @@ -233,11 +233,11 @@ describe('Raw pixel data', function () { }); }); - it('3 channel colour image without transparency', function (_t, done) { + it('3 channel colour image without transparency', (_t, done) => { sharp(fixtures.inputJpg) .resize(32, 24) .toFormat('raw') - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(32 * 24 * 3, info.size); assert.strictEqual(data.length, info.size); @@ -248,11 +248,11 @@ describe('Raw pixel data', function () { }); }); - it('4 channel colour image with transparency', function (_t, done) { + it('4 channel colour image with transparency', (_t, done) => { sharp(fixtures.inputPngWithTransparency) .resize(32, 24) .toFormat(sharp.format.raw) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(32 * 24 * 4, info.size); assert.strictEqual(data.length, info.size); @@ -278,9 +278,9 @@ describe('Raw pixel data', function () { ); }); - describe('Raw pixel depths', function () { - it('Invalid depth', function () { - assert.throws(function () { + describe('Raw pixel depths', () => { + it('Invalid depth', () => { + assert.throws(() => { sharp(Buffer.alloc(3), { raw: { width: 1, height: 1, channels: 3 } }) .raw({ depth: 'zoinks' }); }); diff --git a/test/unit/recomb.js b/test/unit/recomb.js index d16019f31..ec05eb502 100644 --- a/test/unit/recomb.js +++ b/test/unit/recomb.js @@ -15,12 +15,12 @@ const sepia = [ [0.2392, 0.4696, 0.0912] ]; -describe('Recomb', function () { - it('applies a sepia filter using recomb', function (_t, done) { +describe('Recomb', () => { + it('applies a sepia filter using recomb', (_t, done) => { const output = fixtures.path('output.recomb-sepia.jpg'); sharp(fixtures.inputJpgWithLandscapeExif1) .recomb(sepia) - .toFile(output, function (err, info) { + .toFile(output, (err, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(600, info.width); @@ -34,11 +34,11 @@ describe('Recomb', function () { }); }); - it('applies a sepia filter using recomb to an PNG with Alpha', function (_t, done) { + it('applies a sepia filter using recomb to an PNG with Alpha', (_t, done) => { const output = fixtures.path('output.recomb-sepia.png'); sharp(fixtures.inputPngAlphaPremultiplicationSmall) .recomb(sepia) - .toFile(output, function (err, info) { + .toFile(output, (err, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(1024, info.width); @@ -66,7 +66,7 @@ describe('Recomb', function () { assert.strictEqual(3, info.channels); }); - it('applies a different sepia filter using recomb', function (_t, done) { + it('applies a different sepia filter using recomb', (_t, done) => { const output = fixtures.path('output.recomb-sepia2.jpg'); sharp(fixtures.inputJpgWithLandscapeExif1) .recomb([ @@ -74,7 +74,7 @@ describe('Recomb', function () { [0.349, 0.686, 0.168], [0.272, 0.534, 0.131] ]) - .toFile(output, function (err, info) { + .toFile(output, (err, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(600, info.width); @@ -87,7 +87,7 @@ describe('Recomb', function () { done(); }); }); - it('increases the saturation of the image', function (_t, done) { + it('increases the saturation of the image', (_t, done) => { const saturationLevel = 1; const output = fixtures.path('output.recomb-saturation.jpg'); sharp(fixtures.inputJpgWithLandscapeExif1) @@ -108,7 +108,7 @@ describe('Recomb', function () { saturationLevel + 1 - 0.114 ] ]) - .toFile(output, function (err, info) { + .toFile(output, (err, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(600, info.width); @@ -122,7 +122,7 @@ describe('Recomb', function () { }); }); - it('applies opacity 30% to the image', function (_t, done) { + it('applies opacity 30% to the image', (_t, done) => { const output = fixtures.path('output.recomb-opacity.png'); sharp(fixtures.inputPngWithTransparent) .recomb([ @@ -131,7 +131,7 @@ describe('Recomb', function () { [0, 0, 1, 0], [0, 0, 0, 0.3] ]) - .toFile(output, function (err, info) { + .toFile(output, (err, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(48, info.width); @@ -145,19 +145,19 @@ describe('Recomb', function () { }); }); - describe('invalid matrix specification', function () { - it('missing', function () { - assert.throws(function () { + describe('invalid matrix specification', () => { + it('missing', () => { + assert.throws(() => { sharp(fixtures.inputJpg).recomb(); }); }); - it('incorrect flat data', function () { - assert.throws(function () { + it('incorrect flat data', () => { + assert.throws(() => { sharp(fixtures.inputJpg).recomb([1, 2, 3, 4, 5, 6, 7, 8, 9]); }); }); - it('incorrect sub size', function () { - assert.throws(function () { + it('incorrect sub size', () => { + assert.throws(() => { sharp(fixtures.inputJpg).recomb([ [1, 2, 3, 4], [5, 6, 7, 8], @@ -165,8 +165,8 @@ describe('Recomb', function () { ]); }); }); - it('incorrect top size', function () { - assert.throws(function () { + it('incorrect top size', () => { + assert.throws(() => { sharp(fixtures.inputJpg).recomb([[1, 2, 3, 4], [5, 6, 7, 8]]); }); }); diff --git a/test/unit/resize-contain.js b/test/unit/resize-contain.js index dc5bdb410..36cc4518e 100644 --- a/test/unit/resize-contain.js +++ b/test/unit/resize-contain.js @@ -9,15 +9,15 @@ const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); -describe('Resize fit=contain', function () { - it('Allows specifying the position as a string', function (_t, done) { +describe('Resize fit=contain', () => { + it('Allows specifying the position as a string', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240, { fit: 'contain', position: 'center' }) .png() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); @@ -25,11 +25,11 @@ describe('Resize fit=contain', function () { }); }); - it('JPEG within PNG, no alpha channel', function (_t, done) { + it('JPEG within PNG, no alpha channel', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240, { fit: 'contain' }) .png() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -40,14 +40,14 @@ describe('Resize fit=contain', function () { }); }); - it('JPEG within WebP, to include alpha channel', function (_t, done) { + it('JPEG within WebP, to include alpha channel', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } }) .webp() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('webp', info.format); @@ -58,10 +58,10 @@ describe('Resize fit=contain', function () { }); }); - it('PNG with alpha channel', function (_t, done) { + it('PNG with alpha channel', (_t, done) => { sharp(fixtures.inputPngWithTransparency) .resize(50, 50, { fit: 'contain' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -72,10 +72,10 @@ describe('Resize fit=contain', function () { }); }); - it('16-bit PNG with alpha channel', function (_t, done) { + it('16-bit PNG with alpha channel', (_t, done) => { sharp(fixtures.inputPngWithTransparency16bit) .resize(32, 16, { fit: 'contain' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -86,13 +86,13 @@ describe('Resize fit=contain', function () { }); }); - it('16-bit PNG with alpha channel onto RGBA', function (_t, done) { + it('16-bit PNG with alpha channel onto RGBA', (_t, done) => { sharp(fixtures.inputPngWithTransparency16bit) .resize(32, 16, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -103,13 +103,13 @@ describe('Resize fit=contain', function () { }); }); - it('PNG with 2 channels', function (_t, done) { + it('PNG with 2 channels', (_t, done) => { sharp(fixtures.inputPngWithGreyAlpha) .resize(32, 16, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -120,14 +120,14 @@ describe('Resize fit=contain', function () { }); }); - it('TIFF in LAB colourspace onto RGBA background', function (_t, done) { + it('TIFF in LAB colourspace onto RGBA background', (_t, done) => { sharp(fixtures.inputTiffCielab) .resize(64, 128, { fit: 'contain', background: { r: 255, g: 102, b: 0, alpha: 0.5 } }) .png() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -138,10 +138,10 @@ describe('Resize fit=contain', function () { }); }); - it('Enlarge', function (_t, done) { + it('Enlarge', (_t, done) => { sharp(fixtures.inputPngWithOneColor) .resize(320, 240, { fit: 'contain' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -152,14 +152,14 @@ describe('Resize fit=contain', function () { }); }); - describe('Animated WebP', function () { - it('Width only', function (_t, done) { + describe('Animated WebP', () => { + it('Width only', (_t, done) => { sharp(fixtures.inputWebPAnimated, { pages: -1 }) .resize(320, 240, { fit: 'contain', background: { r: 255, g: 0, b: 0 } }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('webp', info.format); @@ -170,13 +170,13 @@ describe('Resize fit=contain', function () { }); }); - it('Height only', function (_t, done) { + it('Height only', (_t, done) => { sharp(fixtures.inputWebPAnimated, { pages: -1 }) .resize(240, 320, { fit: 'contain', background: { r: 255, g: 0, b: 0 } }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('webp', info.format); @@ -188,22 +188,22 @@ describe('Resize fit=contain', function () { }); }); - it('Invalid position values should fail', function () { - [-1, 8.1, 9, 1000000, false, 'vallejo'].forEach(function (position) { - assert.throws(function () { + it('Invalid position values should fail', () => { + [-1, 8.1, 9, 1000000, false, 'vallejo'].forEach((position) => { + assert.throws(() => { sharp().resize(null, null, { fit: 'contain', position }); }); }); }); - it('Position horizontal top', function (_t, done) { + it('Position horizontal top', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: 'top' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -214,14 +214,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal right top', function (_t, done) { + it('Position horizontal right top', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: 'right top' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -232,14 +232,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal right', function (_t, done) { + it('Position horizontal right', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: 'right' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -250,14 +250,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal right bottom', function (_t, done) { + it('Position horizontal right bottom', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: 'right bottom' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -268,14 +268,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal bottom', function (_t, done) { + it('Position horizontal bottom', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: 'bottom' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -286,14 +286,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal left bottom', function (_t, done) { + it('Position horizontal left bottom', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: 'left bottom' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -304,14 +304,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal left', function (_t, done) { + it('Position horizontal left', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: 'left' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -322,14 +322,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal left top', function (_t, done) { + it('Position horizontal left top', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: 'left top' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -340,14 +340,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal north', function (_t, done) { + it('Position horizontal north', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: sharp.gravity.north }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -358,14 +358,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal northeast', function (_t, done) { + it('Position horizontal northeast', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: sharp.gravity.northeast }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -376,14 +376,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal east', function (_t, done) { + it('Position horizontal east', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: sharp.gravity.east }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -394,14 +394,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal southeast', function (_t, done) { + it('Position horizontal southeast', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: sharp.gravity.southeast }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -412,14 +412,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal south', function (_t, done) { + it('Position horizontal south', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: sharp.gravity.south }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -430,14 +430,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal southwest', function (_t, done) { + it('Position horizontal southwest', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: sharp.gravity.southwest }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -448,14 +448,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal west', function (_t, done) { + it('Position horizontal west', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: sharp.gravity.west }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -466,14 +466,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal northwest', function (_t, done) { + it('Position horizontal northwest', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: sharp.gravity.northwest }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -484,14 +484,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position horizontal center', function (_t, done) { + it('Position horizontal center', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 100, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: sharp.gravity.center }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -502,14 +502,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical top', function (_t, done) { + it('Position vertical top', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: 'top' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -520,14 +520,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical right top', function (_t, done) { + it('Position vertical right top', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: 'right top' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -538,14 +538,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical right', function (_t, done) { + it('Position vertical right', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: 'right' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -556,14 +556,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical right bottom', function (_t, done) { + it('Position vertical right bottom', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: 'right bottom' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -574,14 +574,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical bottom', function (_t, done) { + it('Position vertical bottom', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: 'bottom' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -592,14 +592,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical left bottom', function (_t, done) { + it('Position vertical left bottom', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: 'left bottom' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -610,14 +610,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical left', function (_t, done) { + it('Position vertical left', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: 'left' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -628,14 +628,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical left top', function (_t, done) { + it('Position vertical left top', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: 'left top' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -646,14 +646,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical north', function (_t, done) { + it('Position vertical north', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: sharp.gravity.north }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -664,14 +664,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical northeast', function (_t, done) { + it('Position vertical northeast', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: sharp.gravity.northeast }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -682,14 +682,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical east', function (_t, done) { + it('Position vertical east', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: sharp.gravity.east }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -700,14 +700,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical southeast', function (_t, done) { + it('Position vertical southeast', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: sharp.gravity.southeast }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -718,14 +718,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical south', function (_t, done) { + it('Position vertical south', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: sharp.gravity.south }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -736,14 +736,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical southwest', function (_t, done) { + it('Position vertical southwest', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: sharp.gravity.southwest }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -754,14 +754,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical west', function (_t, done) { + it('Position vertical west', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: sharp.gravity.west }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -772,14 +772,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical northwest', function (_t, done) { + it('Position vertical northwest', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: sharp.gravity.northwest }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -790,14 +790,14 @@ describe('Resize fit=contain', function () { }); }); - it('Position vertical center', function (_t, done) { + it('Position vertical center', (_t, done) => { sharp(fixtures.inputPngEmbed) .resize(200, 200, { fit: sharp.fit.contain, background: { r: 0, g: 0, b: 0, alpha: 0 }, position: sharp.gravity.center }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); diff --git a/test/unit/resize-cover.js b/test/unit/resize-cover.js index 09ae42d62..4e2dda737 100644 --- a/test/unit/resize-cover.js +++ b/test/unit/resize-cover.js @@ -9,7 +9,7 @@ const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); -describe('Resize fit=cover', function () { +describe('Resize fit=cover', () => { [ // Position { @@ -202,14 +202,14 @@ describe('Resize fit=cover', function () { gravity: sharp.gravity.northwest, fixture: 'gravity-west.jpg' } - ].forEach(function (settings) { - it(settings.name, function (_t, done) { + ].forEach((settings) => { + it(settings.name, (_t, done) => { sharp(fixtures.inputJpg) .resize(settings.width, settings.height, { fit: sharp.fit.cover, position: settings.gravity }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(settings.width, info.width); assert.strictEqual(settings.height, info.height); @@ -218,13 +218,13 @@ describe('Resize fit=cover', function () { }); }); - it('Allows specifying the gravity as a string', function (_t, done) { + it('Allows specifying the gravity as a string', (_t, done) => { sharp(fixtures.inputJpg) .resize(80, 320, { fit: sharp.fit.cover, position: 'east' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(80, info.width); assert.strictEqual(320, info.height); @@ -232,52 +232,48 @@ describe('Resize fit=cover', function () { }); }); - it('Invalid position values fail', function () { - assert.throws(function () { + it('Invalid position values fail', () => { + assert.throws(() => { sharp().resize(null, null, { fit: 'cover', position: 9 }); }, /Expected valid position\/gravity\/strategy for position but received 9 of type number/); - assert.throws(function () { + assert.throws(() => { sharp().resize(null, null, { fit: 'cover', position: 1.1 }); }, /Expected valid position\/gravity\/strategy for position but received 1.1 of type number/); - assert.throws(function () { + assert.throws(() => { sharp().resize(null, null, { fit: 'cover', position: -1 }); }, /Expected valid position\/gravity\/strategy for position but received -1 of type number/); - assert.throws(function () { + assert.throws(() => { sharp().resize(null, null, { fit: 'cover', position: 'zoinks' }).crop(); }, /Expected valid position\/gravity\/strategy for position but received zoinks of type string/); }); - it('Uses default value when none specified', function () { - assert.doesNotThrow(function () { + it('Uses default value when none specified', () => { + assert.doesNotThrow(() => { sharp().resize(null, null, { fit: 'cover' }); }); }); - it('Skip crop when post-resize dimensions are at target', function () { - return sharp(fixtures.inputJpg) + it('Skip crop when post-resize dimensions are at target', () => sharp(fixtures.inputJpg) .resize(1600, 1200) .toBuffer() - .then(function (input) { - return sharp(input) + .then((input) => sharp(input) .resize(1110, null, { fit: sharp.fit.cover, position: sharp.strategy.attention }) .toBuffer({ resolveWithObject: true }) - .then(function (result) { + .then((result) => { assert.strictEqual(1110, result.info.width); assert.strictEqual(832, result.info.height); assert.strictEqual(undefined, result.info.cropOffsetLeft); assert.strictEqual(undefined, result.info.cropOffsetTop); - }); - }); - }); + }))); - describe('Animated WebP', function () { - it('Width only', function (_t, done) { + describe('Animated WebP', () => { + it('Width only', (_t, done) => { sharp(fixtures.inputWebPAnimated, { pages: -1 }) .resize(80, 320, { fit: sharp.fit.cover }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(80, info.width); assert.strictEqual(320 * 9, info.height); @@ -285,10 +281,10 @@ describe('Resize fit=cover', function () { }); }); - it('Height only', function (_t, done) { + it('Height only', (_t, done) => { sharp(fixtures.inputWebPAnimated, { pages: -1 }) .resize(320, 80, { fit: sharp.fit.cover }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(80 * 9, info.height); @@ -297,14 +293,14 @@ describe('Resize fit=cover', function () { }); }); - describe('Entropy-based strategy', function () { - it('JPEG', function (_t, done) { + describe('Entropy-based strategy', () => { + it('JPEG', (_t, done) => { sharp(fixtures.inputJpg) .resize(80, 320, { fit: 'cover', position: sharp.strategy.entropy }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(3, info.channels); @@ -316,13 +312,13 @@ describe('Resize fit=cover', function () { }); }); - it('PNG', function (_t, done) { + it('PNG', (_t, done) => { sharp(fixtures.inputPngWithTransparency) .resize(320, 80, { fit: 'cover', position: sharp.strategy.entropy }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(4, info.channels); @@ -334,13 +330,13 @@ describe('Resize fit=cover', function () { }); }); - it('supports the strategy passed as a string', function (_t, done) { + it('supports the strategy passed as a string', (_t, done) => { sharp(fixtures.inputPngWithTransparency) .resize(320, 80, { fit: 'cover', position: 'entropy' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(4, info.channels); @@ -365,14 +361,14 @@ describe('Resize fit=cover', function () { ); }); - describe('Attention strategy', function () { - it('JPEG', function (_t, done) { + describe('Attention strategy', () => { + it('JPEG', (_t, done) => { sharp(fixtures.inputJpg) .resize(80, 320, { fit: 'cover', position: sharp.strategy.attention }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(3, info.channels); @@ -386,13 +382,13 @@ describe('Resize fit=cover', function () { }); }); - it('PNG', function (_t, done) { + it('PNG', (_t, done) => { sharp(fixtures.inputPngWithTransparency) .resize(320, 80, { fit: 'cover', position: sharp.strategy.attention }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(4, info.channels); @@ -406,13 +402,13 @@ describe('Resize fit=cover', function () { }); }); - it('WebP', function (_t, done) { + it('WebP', (_t, done) => { sharp(fixtures.inputWebP) .resize(320, 80, { fit: 'cover', position: sharp.strategy.attention }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('webp', info.format); assert.strictEqual(3, info.channels); @@ -426,13 +422,13 @@ describe('Resize fit=cover', function () { }); }); - it('supports the strategy passed as a string', function (_t, done) { + it('supports the strategy passed as a string', (_t, done) => { sharp(fixtures.inputPngWithTransparency) .resize(320, 80, { fit: 'cover', position: 'attention' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(4, info.channels); diff --git a/test/unit/resize.js b/test/unit/resize.js index ff6420104..e0a001543 100644 --- a/test/unit/resize.js +++ b/test/unit/resize.js @@ -9,9 +9,9 @@ const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); -describe('Resize dimensions', function () { - it('Exact crop', function (_t, done) { - sharp(fixtures.inputJpg).resize(320, 240).toBuffer(function (err, data, info) { +describe('Resize dimensions', () => { + it('Exact crop', (_t, done) => { + sharp(fixtures.inputJpg).resize(320, 240).toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -21,8 +21,8 @@ describe('Resize dimensions', function () { }); }); - it('Fixed width', function (_t, done) { - sharp(fixtures.inputJpg).resize(320).toBuffer(function (err, data, info) { + it('Fixed width', (_t, done) => { + sharp(fixtures.inputJpg).resize(320).toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -32,8 +32,8 @@ describe('Resize dimensions', function () { }); }); - it('Fixed height', function (_t, done) { - sharp(fixtures.inputJpg).resize(null, 320).toBuffer(function (err, data, info) { + it('Fixed height', (_t, done) => { + sharp(fixtures.inputJpg).resize(null, 320).toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -43,8 +43,8 @@ describe('Resize dimensions', function () { }); }); - it('Identity transform', function (_t, done) { - sharp(fixtures.inputJpg).toBuffer(function (err, data, info) { + it('Identity transform', (_t, done) => { + sharp(fixtures.inputJpg).toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -54,10 +54,10 @@ describe('Resize dimensions', function () { }); }); - it('Upscale', function (_t, done) { + it('Upscale', (_t, done) => { sharp(fixtures.inputJpg) .resize(3000) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -67,26 +67,26 @@ describe('Resize dimensions', function () { }); }); - it('Invalid width - NaN', function () { - assert.throws(function () { + it('Invalid width - NaN', () => { + assert.throws(() => { sharp().resize('spoons', 240); }, /Expected positive integer for width but received spoons of type string/); }); - it('Invalid height - NaN', function () { - assert.throws(function () { + it('Invalid height - NaN', () => { + assert.throws(() => { sharp().resize(320, 'spoons'); }, /Expected positive integer for height but received spoons of type string/); }); - it('Invalid width - float', function () { - assert.throws(function () { + it('Invalid width - float', () => { + assert.throws(() => { sharp().resize(1.5, 240); }, /Expected positive integer for width but received 1.5 of type number/); }); - it('Invalid height - float', function () { - assert.throws(function () { + it('Invalid height - float', () => { + assert.throws(() => { sharp().resize(320, 1.5); }, /Expected positive integer for height but received 1.5 of type number/); }); @@ -103,34 +103,34 @@ describe('Resize dimensions', function () { }, /Expected positive integer for height but received 1.5 of type number/); }); - it('Invalid width - too large', function (_t, done) { + it('Invalid width - too large', (_t, done) => { sharp(fixtures.inputJpg) .resize(0x4000, 1) .webp() - .toBuffer(function (err) { + .toBuffer((err) => { assert.strictEqual(true, err instanceof Error); assert.strictEqual('Processed image is too large for the WebP format', err.message); done(); }); }); - it('Invalid height - too large', function (_t, done) { + it('Invalid height - too large', (_t, done) => { sharp(fixtures.inputJpg) .resize(1, 0x4000) .webp() - .toBuffer(function (err) { + .toBuffer((err) => { assert.strictEqual(true, err instanceof Error); assert.strictEqual('Processed image is too large for the WebP format', err.message); done(); }); }); - it('Webp resize then extract large image', function (_t, done) { + it('Webp resize then extract large image', (_t, done) => { sharp(fixtures.inputWebP) .resize(0x4000, 0x4000) .extract({ top: 0x2000, left: 0x2000, width: 256, height: 256 }) .webp() - .toBuffer(function (err, _data, info) { + .toBuffer((err, _data, info) => { if (err) throw err; assert.strictEqual('webp', info.format); assert.strictEqual(256, info.width); @@ -139,18 +139,18 @@ describe('Resize dimensions', function () { }); }); - it('WebP shrink-on-load rounds to zero, ensure recalculation is correct', function (_t, done) { + it('WebP shrink-on-load rounds to zero, ensure recalculation is correct', (_t, done) => { sharp(fixtures.inputJpg) .resize(1080, 607) .webp() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('webp', info.format); assert.strictEqual(1080, info.width); assert.strictEqual(607, info.height); sharp(data) .resize(233, 131) - .toBuffer(function (err, _data, info) { + .toBuffer((err, _data, info) => { if (err) throw err; assert.strictEqual('webp', info.format); assert.strictEqual(233, info.width); @@ -160,17 +160,17 @@ describe('Resize dimensions', function () { }); }); - it('JPEG shrink-on-load with 90 degree rotation, ensure recalculation is correct', function (_t, done) { + it('JPEG shrink-on-load with 90 degree rotation, ensure recalculation is correct', (_t, done) => { sharp(fixtures.inputJpg) .resize(1920, 1280) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(1920, info.width); assert.strictEqual(1280, info.height); sharp(data) .rotate(90) .resize(533, 800) - .toBuffer(function (err, _data, info) { + .toBuffer((err, _data, info) => { if (err) throw err; assert.strictEqual(533, info.width); assert.strictEqual(800, info.height); @@ -179,11 +179,11 @@ describe('Resize dimensions', function () { }); }); - it('TIFF embed known to cause rounding errors', function (_t, done) { + it('TIFF embed known to cause rounding errors', (_t, done) => { sharp(fixtures.inputTiff) .resize(240, 320, { fit: sharp.fit.contain }) .jpeg() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -193,11 +193,11 @@ describe('Resize dimensions', function () { }); }); - it('TIFF known to cause rounding errors', function (_t, done) { + it('TIFF known to cause rounding errors', (_t, done) => { sharp(fixtures.inputTiff) .resize(240, 320) .jpeg() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -207,11 +207,11 @@ describe('Resize dimensions', function () { }); }); - it('fit=inside, portrait', function (_t, done) { + it('fit=inside, portrait', (_t, done) => { sharp(fixtures.inputTiff) .resize(320, 320, { fit: sharp.fit.inside }) .jpeg() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -221,11 +221,11 @@ describe('Resize dimensions', function () { }); }); - it('fit=outside, portrait', function (_t, done) { + it('fit=outside, portrait', (_t, done) => { sharp(fixtures.inputTiff) .resize(320, 320, { fit: sharp.fit.outside }) .jpeg() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -235,10 +235,10 @@ describe('Resize dimensions', function () { }); }); - it('fit=inside, landscape', function (_t, done) { + it('fit=inside, landscape', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 320, { fit: sharp.fit.inside }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -248,10 +248,10 @@ describe('Resize dimensions', function () { }); }); - it('fit=outside, landscape', function (_t, done) { + it('fit=outside, landscape', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 320, { fit: sharp.fit.outside }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -261,13 +261,13 @@ describe('Resize dimensions', function () { }); }); - it('fit=inside, provide only one dimension', function (_t, done) { + it('fit=inside, provide only one dimension', (_t, done) => { sharp(fixtures.inputJpg) .resize({ width: 320, fit: sharp.fit.inside }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -277,13 +277,13 @@ describe('Resize dimensions', function () { }); }); - it('fit=outside, provide only one dimension', function (_t, done) { + it('fit=outside, provide only one dimension', (_t, done) => { sharp(fixtures.inputJpg) .resize({ width: 320, fit: sharp.fit.outside }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -293,13 +293,13 @@ describe('Resize dimensions', function () { }); }); - it('Do not enlarge when input width is already less than output width', function (_t, done) { + it('Do not enlarge when input width is already less than output width', (_t, done) => { sharp(fixtures.inputJpg) .resize({ width: 2800, withoutEnlargement: true }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -309,13 +309,13 @@ describe('Resize dimensions', function () { }); }); - it('Do not enlarge when input height is already less than output height', function (_t, done) { + it('Do not enlarge when input height is already less than output height', (_t, done) => { sharp(fixtures.inputJpg) .resize({ height: 2300, withoutEnlargement: true }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -325,14 +325,14 @@ describe('Resize dimensions', function () { }); }); - it('Do crop when fit = cover and withoutEnlargement = true and width >= outputWidth, and height < outputHeight', function (_t, done) { + it('Do crop when fit = cover and withoutEnlargement = true and width >= outputWidth, and height < outputHeight', (_t, done) => { sharp(fixtures.inputJpg) .resize({ width: 3000, height: 1000, withoutEnlargement: true }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -342,14 +342,14 @@ describe('Resize dimensions', function () { }); }); - it('Do crop when fit = cover and withoutEnlargement = true and width < outputWidth, and height >= outputHeight', function (_t, done) { + it('Do crop when fit = cover and withoutEnlargement = true and width < outputWidth, and height >= outputHeight', (_t, done) => { sharp(fixtures.inputJpg) .resize({ width: 1500, height: 2226, withoutEnlargement: true }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -359,13 +359,13 @@ describe('Resize dimensions', function () { }); }); - it('Do enlarge when input width is less than output width', function (_t, done) { + it('Do enlarge when input width is less than output width', (_t, done) => { sharp(fixtures.inputJpg) .resize({ width: 2800, withoutEnlargement: false }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -375,13 +375,13 @@ describe('Resize dimensions', function () { }); }); - it('Do enlarge when input width is less than output width', function (_t, done) { + it('Do enlarge when input width is less than output width', (_t, done) => { sharp(fixtures.inputJpg) .resize({ width: 2800, withoutReduction: true }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -391,13 +391,13 @@ describe('Resize dimensions', function () { }); }); - it('Do enlarge when input height is less than output height', function (_t, done) { + it('Do enlarge when input height is less than output height', (_t, done) => { sharp(fixtures.inputJpg) .resize({ height: 2300, withoutReduction: true }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -407,13 +407,13 @@ describe('Resize dimensions', function () { }); }); - it('Do enlarge when input width is less than output width', function (_t, done) { + it('Do enlarge when input width is less than output width', (_t, done) => { sharp(fixtures.inputJpg) .resize({ width: 2800, withoutReduction: false }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -423,10 +423,10 @@ describe('Resize dimensions', function () { }); }); - it('Do not resize when both withoutEnlargement and withoutReduction are true', function (_t, done) { + it('Do not resize when both withoutEnlargement and withoutReduction are true', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 320, { fit: 'fill', withoutEnlargement: true, withoutReduction: true }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -436,10 +436,10 @@ describe('Resize dimensions', function () { }); }); - it('Do not reduce size when fit = outside and withoutReduction are true and height > outputHeight and width > outputWidth', function (_t, done) { + it('Do not reduce size when fit = outside and withoutReduction are true and height > outputHeight and width > outputWidth', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 320, { fit: 'outside', withoutReduction: true }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -449,10 +449,10 @@ describe('Resize dimensions', function () { }); }); - it('Do resize when fit = outside and withoutReduction are true and input height > height and input width > width ', function (_t, done) { + it('Do resize when fit = outside and withoutReduction are true and input height > height and input width > width ', (_t, done) => { sharp(fixtures.inputJpg) .resize(3000, 3000, { fit: 'outside', withoutReduction: true }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -462,10 +462,10 @@ describe('Resize dimensions', function () { }); }); - it('fit=fill, downscale width and height', function (_t, done) { + it('fit=fill, downscale width and height', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 320, { fit: 'fill' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -475,13 +475,13 @@ describe('Resize dimensions', function () { }); }); - it('fit=fill, downscale width', function (_t, done) { + it('fit=fill, downscale width', (_t, done) => { sharp(fixtures.inputJpg) .resize({ width: 320, fit: 'fill' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -491,13 +491,13 @@ describe('Resize dimensions', function () { }); }); - it('fit=fill, downscale height', function (_t, done) { + it('fit=fill, downscale height', (_t, done) => { sharp(fixtures.inputJpg) .resize({ height: 320, fit: 'fill' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -507,10 +507,10 @@ describe('Resize dimensions', function () { }); }); - it('fit=fill, upscale width and height', function (_t, done) { + it('fit=fill, upscale width and height', (_t, done) => { sharp(fixtures.inputJpg) .resize(3000, 3000, { fit: 'fill' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -520,10 +520,10 @@ describe('Resize dimensions', function () { }); }); - it('fit=fill, upscale width', function (_t, done) { + it('fit=fill, upscale width', (_t, done) => { sharp(fixtures.inputJpg) .resize(3000, null, { fit: 'fill' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -533,10 +533,10 @@ describe('Resize dimensions', function () { }); }); - it('fit=fill, upscale height', function (_t, done) { + it('fit=fill, upscale height', (_t, done) => { sharp(fixtures.inputJpg) .resize(null, 3000, { fit: 'fill' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -546,10 +546,10 @@ describe('Resize dimensions', function () { }); }); - it('fit=fill, downscale width, upscale height', function (_t, done) { + it('fit=fill, downscale width, upscale height', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 3000, { fit: 'fill' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -559,10 +559,10 @@ describe('Resize dimensions', function () { }); }); - it('fit=fill, upscale width, downscale height', function (_t, done) { + it('fit=fill, upscale width, downscale height', (_t, done) => { sharp(fixtures.inputJpg) .resize(3000, 320, { fit: 'fill' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -572,10 +572,10 @@ describe('Resize dimensions', function () { }); }); - it('fit=fill, identity transform', function (_t, done) { + it('fit=fill, identity transform', (_t, done) => { sharp(fixtures.inputJpg) .resize(null, null, { fit: 'fill' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -585,16 +585,16 @@ describe('Resize dimensions', function () { }); }); - it('Dimensions that result in differing even shrinks on each axis', function (_t, done) { + it('Dimensions that result in differing even shrinks on each axis', (_t, done) => { sharp(fixtures.inputJpg) .resize(645, 399) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(645, info.width); assert.strictEqual(399, info.height); sharp(data) .resize(150, 100) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(150, info.width); assert.strictEqual(100, info.height); @@ -603,33 +603,31 @@ describe('Resize dimensions', function () { }); }); - it('Dimensions that result in differing odd shrinks on each axis', function (_t, done) { - return sharp(fixtures.inputJpg) + it('Dimensions that result in differing odd shrinks on each axis', (_t, done) => sharp(fixtures.inputJpg) .resize(600, 399) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(600, info.width); assert.strictEqual(399, info.height); sharp(data) .resize(200) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(200, info.width); assert.strictEqual(133, info.height); fixtures.assertSimilar(fixtures.expected('resize-diff-shrink-odd.jpg'), data, done); }); - }); - }); + })); [ true, false - ].forEach(function (value) { - it(`fastShrinkOnLoad: ${value} does not causes image shifts`, function (_t, done) { + ].forEach((value) => { + it(`fastShrinkOnLoad: ${value} does not causes image shifts`, (_t, done) => { sharp(fixtures.inputJpgCenteredImage) .resize(9, 8, { fastShrinkOnLoad: value }) .png() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(9, info.width); assert.strictEqual(8, info.height); @@ -644,11 +642,11 @@ describe('Resize dimensions', function () { sharp.kernel.mitchell, sharp.kernel.lanczos2, sharp.kernel.lanczos3 - ].forEach(function (kernel) { - it(`kernel ${kernel}`, function (_t, done) { + ].forEach((kernel) => { + it(`kernel ${kernel}`, (_t, done) => { sharp(fixtures.inputJpg) .resize(320, null, { kernel }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -657,11 +655,11 @@ describe('Resize dimensions', function () { }); }); - it('nearest upsampling with integral factor', function (_t, done) { + it('nearest upsampling with integral factor', (_t, done) => { sharp(fixtures.inputTiff8BitDepth) .resize(210, 210, { kernel: 'nearest' }) .png() - .toBuffer(function (err, _data, info) { + .toBuffer((err, _data, info) => { if (err) throw err; assert.strictEqual(210, info.width); assert.strictEqual(210, info.height); @@ -669,8 +667,7 @@ describe('Resize dimensions', function () { }); }); - it('Ensure shortest edge (height) is at least 1 pixel', function () { - return sharp({ + it('Ensure shortest edge (height) is at least 1 pixel', () => sharp({ create: { width: 10, height: 2, @@ -680,14 +677,12 @@ describe('Resize dimensions', function () { }) .resize(2) .toBuffer({ resolveWithObject: true }) - .then(function (output) { + .then((output) => { assert.strictEqual(2, output.info.width); assert.strictEqual(1, output.info.height); - }); - }); + })); - it('Ensure shortest edge (width) is at least 1 pixel', function () { - return sharp({ + it('Ensure shortest edge (width) is at least 1 pixel', () => sharp({ create: { width: 2, height: 10, @@ -697,14 +692,12 @@ describe('Resize dimensions', function () { }) .resize(null, 2) .toBuffer({ resolveWithObject: true }) - .then(function (output) { + .then((output) => { assert.strictEqual(1, output.info.width); assert.strictEqual(2, output.info.height); - }); - }); + })); - it('Ensure embedded shortest edge (height) is at least 1 pixel', function () { - return sharp({ + it('Ensure embedded shortest edge (height) is at least 1 pixel', () => sharp({ create: { width: 200, height: 1, @@ -714,14 +707,12 @@ describe('Resize dimensions', function () { }) .resize({ width: 50, height: 50, fit: sharp.fit.contain }) .toBuffer({ resolveWithObject: true }) - .then(function (output) { + .then((output) => { assert.strictEqual(50, output.info.width); assert.strictEqual(50, output.info.height); - }); - }); + })); - it('Ensure embedded shortest edge (width) is at least 1 pixel', function () { - return sharp({ + it('Ensure embedded shortest edge (width) is at least 1 pixel', () => sharp({ create: { width: 1, height: 200, @@ -731,11 +722,10 @@ describe('Resize dimensions', function () { }) .resize({ width: 50, height: 50, fit: sharp.fit.contain }) .toBuffer({ resolveWithObject: true }) - .then(function (output) { + .then((output) => { assert.strictEqual(50, output.info.width); assert.strictEqual(50, output.info.height); - }); - }); + })); it('Skip shrink-on-load where one dimension <4px', async () => { const jpeg = await sharp({ @@ -778,20 +768,20 @@ describe('Resize dimensions', function () { assert.strictEqual(height, 334); }); - it('unknown kernel throws', function () { - assert.throws(function () { + it('unknown kernel throws', () => { + assert.throws(() => { sharp().resize(null, null, { kernel: 'unknown' }); }); }); - it('unknown fit throws', function () { - assert.throws(function () { + it('unknown fit throws', () => { + assert.throws(() => { sharp().resize(null, null, { fit: 'unknown' }); }); }); - it('unknown position throws', function () { - assert.throws(function () { + it('unknown position throws', () => { + assert.throws(() => { sharp().resize(null, null, { position: 'unknown' }); }); }); @@ -799,7 +789,7 @@ describe('Resize dimensions', function () { it('Multiple resize emits warning', () => { let warningMessage = ''; const s = sharp(); - s.on('warning', function (msg) { warningMessage = msg; }); + s.on('warning', (msg) => { warningMessage = msg; }); s.resize(1); assert.strictEqual(warningMessage, ''); s.resize(2); diff --git a/test/unit/rotate.js b/test/unit/rotate.js index ce8fe92f3..ae8b755c0 100644 --- a/test/unit/rotate.js +++ b/test/unit/rotate.js @@ -9,22 +9,22 @@ const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); -describe('Rotation', function () { - ['autoOrient', 'constructor'].forEach(function (rotateMethod) { +describe('Rotation', () => { + ['autoOrient', 'constructor'].forEach((rotateMethod) => { describe(`Auto orientation via ${rotateMethod}:`, () => { const options = rotateMethod === 'constructor' ? { autoOrient: true } : {}; - ['Landscape', 'Portrait'].forEach(function (orientation) { - [1, 2, 3, 4, 5, 6, 7, 8].forEach(function (exifTag) { + ['Landscape', 'Portrait'].forEach((orientation) => { + [1, 2, 3, 4, 5, 6, 7, 8].forEach((exifTag) => { const input = fixtures[`inputJpgWith${orientation}Exif${exifTag}`]; const expectedOutput = fixtures.expected(`${orientation}_${exifTag}-out.jpg`); - it(`${orientation} image with EXIF Orientation ${exifTag}: Auto-rotate`, function (_t, done) { + it(`${orientation} image with EXIF Orientation ${exifTag}: Auto-rotate`, (_t, done) => { const [expectedWidth, expectedHeight] = orientation === 'Landscape' ? [600, 450] : [450, 600]; const img = sharp(input, options); rotateMethod === 'autoOrient' && img.autoOrient(); - img.toBuffer(function (err, data, info) { + img.toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(info.width, expectedWidth); assert.strictEqual(info.height, expectedHeight); @@ -32,14 +32,14 @@ describe('Rotation', function () { }); }); - it(`${orientation} image with EXIF Orientation ${exifTag}: Auto-rotate then resize`, function (_t, done) { + it(`${orientation} image with EXIF Orientation ${exifTag}: Auto-rotate then resize`, (_t, done) => { const [expectedWidth, expectedHeight] = orientation === 'Landscape' ? [320, 240] : [320, 427]; const img = sharp(input, options); rotateMethod === 'autoOrient' && img.autoOrient(); img.resize({ width: 320 }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(info.width, expectedWidth); assert.strictEqual(info.height, expectedHeight); @@ -48,7 +48,7 @@ describe('Rotation', function () { }); if (rotateMethod !== 'constructor') { - it(`${orientation} image with EXIF Orientation ${exifTag}: Resize then auto-rotate`, function (_t, done) { + it(`${orientation} image with EXIF Orientation ${exifTag}: Resize then auto-rotate`, (_t, done) => { const [expectedWidth, expectedHeight] = orientation === 'Landscape' ? (exifTag < 5) ? [320, 240] : [320, 240] : [320, 427]; @@ -57,7 +57,7 @@ describe('Rotation', function () { .resize({ width: 320 }); rotateMethod === 'autoOrient' && img.autoOrient(); - img.toBuffer(function (err, data, info) { + img.toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(info.width, expectedWidth); assert.strictEqual(info.height, expectedHeight); @@ -67,10 +67,10 @@ describe('Rotation', function () { } [true, false].forEach((doResize) => { - [90, 180, 270, 45].forEach(function (angle) { + [90, 180, 270, 45].forEach((angle) => { const [inputWidth, inputHeight] = orientation === 'Landscape' ? [600, 450] : [450, 600]; const expectedOutput = fixtures.expected(`${orientation}_${exifTag}_rotate${angle}-out.jpg`); - it(`${orientation} image with EXIF Orientation ${exifTag}: Auto-rotate then rotate ${angle} ${doResize ? 'and resize' : ''}`, function (_t, done) { + it(`${orientation} image with EXIF Orientation ${exifTag}: Auto-rotate then rotate ${angle} ${doResize ? 'and resize' : ''}`, (_t, done) => { const [width, height] = (angle === 45 ? [742, 742] : [inputWidth, inputHeight]).map((x) => doResize ? Math.floor(x / 1.875) : x); const [expectedWidth, expectedHeight] = angle % 180 === 0 ? [width, height] : [height, width]; @@ -80,7 +80,7 @@ describe('Rotation', function () { img.rotate(angle); doResize && img.resize(expectedWidth); - img.toBuffer(function (err, data, info) { + img.toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(info.width, expectedWidth); assert.strictEqual(info.height, expectedHeight); @@ -89,11 +89,11 @@ describe('Rotation', function () { }); }); - [[true, true], [true, false], [false, true]].forEach(function ([flip, flop]) { + [[true, true], [true, false], [false, true]].forEach(([flip, flop]) => { const [inputWidth, inputHeight] = orientation === 'Landscape' ? [600, 450] : [450, 600]; const flipFlopFileName = [flip && 'flip', flop && 'flop'].filter(Boolean).join('_'); const flipFlopTestName = [flip && 'flip', flop && 'flop'].filter(Boolean).join(' & '); - it(`${orientation} image with EXIF Orientation ${exifTag}: Auto-rotate then ${flipFlopTestName} ${doResize ? 'and resize' : ''}`, function (_t, done) { + it(`${orientation} image with EXIF Orientation ${exifTag}: Auto-rotate then ${flipFlopTestName} ${doResize ? 'and resize' : ''}`, (_t, done) => { const expectedOutput = fixtures.expected(`${orientation}_${exifTag}_${flipFlopFileName}-out.jpg`); const img = sharp(input, options); @@ -104,7 +104,7 @@ describe('Rotation', function () { flop && img.flop(); doResize && img.resize(orientation === 'Landscape' ? 320 : 240); - img.toBuffer(function (err, data, info) { + img.toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(info.width, inputWidth / (doResize ? 1.875 : 1)); assert.strictEqual(info.height, inputHeight / (doResize ? 1.875 : 1)); @@ -118,12 +118,12 @@ describe('Rotation', function () { }); }); - it('Rotate by 30 degrees with semi-transparent background', function (_t, done) { + it('Rotate by 30 degrees with semi-transparent background', (_t, done) => { sharp(fixtures.inputJpg) .resize(320) .rotate(30, { background: { r: 255, g: 0, b: 0, alpha: 0.5 } }) .png() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(408, info.width); @@ -132,11 +132,11 @@ describe('Rotation', function () { }); }); - it('Rotate by 30 degrees with solid background', function (_t, done) { + it('Rotate by 30 degrees with solid background', (_t, done) => { sharp(fixtures.inputJpg) .resize(320) .rotate(30, { background: { r: 255, g: 0, b: 0 } }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(408, info.width); @@ -145,11 +145,11 @@ describe('Rotation', function () { }); }); - it('Rotate by 90 degrees, respecting output input size', function (_t, done) { + it('Rotate by 90 degrees, respecting output input size', (_t, done) => { sharp(fixtures.inputJpg) .rotate(90) .resize(320, 240) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -159,11 +159,11 @@ describe('Rotation', function () { }); }); - it('Resize then rotate by 30 degrees, respecting output input size', function (_t, done) { + it('Resize then rotate by 30 degrees, respecting output input size', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .rotate(30) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -173,9 +173,9 @@ describe('Rotation', function () { }); }); - [-3690, -450, -90, 90, 450, 3690].forEach(function (angle) { - it(`Rotate by any 90-multiple angle (${angle}deg)`, function (_t, done) { - sharp(fixtures.inputJpg320x240).rotate(angle).toBuffer(function (err, _data, info) { + [-3690, -450, -90, 90, 450, 3690].forEach((angle) => { + it(`Rotate by any 90-multiple angle (${angle}deg)`, (_t, done) => { + sharp(fixtures.inputJpg320x240).rotate(angle).toBuffer((err, _data, info) => { if (err) throw err; assert.strictEqual(240, info.width); assert.strictEqual(320, info.height); @@ -184,9 +184,9 @@ describe('Rotation', function () { }); }); - [-3750, -510, -150, 30, 390, 3630].forEach(function (angle) { - it(`Rotate by any 30-multiple angle (${angle}deg)`, function (_t, done) { - sharp(fixtures.inputJpg320x240).rotate(angle).toBuffer(function (err, _data, info) { + [-3750, -510, -150, 30, 390, 3630].forEach((angle) => { + it(`Rotate by any 30-multiple angle (${angle}deg)`, (_t, done) => { + sharp(fixtures.inputJpg320x240).rotate(angle).toBuffer((err, _data, info) => { if (err) throw err; assert.strictEqual(397, info.width); assert.strictEqual(368, info.height); @@ -195,9 +195,9 @@ describe('Rotation', function () { }); }); - [-3780, -540, 0, 180, 540, 3780].forEach(function (angle) { - it(`Rotate by any 180-multiple angle (${angle}deg)`, function (_t, done) { - sharp(fixtures.inputJpg320x240).rotate(angle).toBuffer(function (err, _data, info) { + [-3780, -540, 0, 180, 540, 3780].forEach((angle) => { + it(`Rotate by any 180-multiple angle (${angle}deg)`, (_t, done) => { + sharp(fixtures.inputJpg320x240).rotate(angle).toBuffer((err, _data, info) => { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); @@ -206,15 +206,15 @@ describe('Rotation', function () { }); }); - it('Rotate by 270 degrees, square output ignoring aspect ratio', function (_t, done) { + it('Rotate by 270 degrees, square output ignoring aspect ratio', (_t, done) => { sharp(fixtures.inputJpg) .resize(240, 240, { fit: sharp.fit.fill }) .rotate(270) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(240, info.width); assert.strictEqual(240, info.height); - sharp(data).metadata(function (err, metadata) { + sharp(data).metadata((err, metadata) => { if (err) throw err; assert.strictEqual(240, metadata.width); assert.strictEqual(240, metadata.height); @@ -223,15 +223,15 @@ describe('Rotation', function () { }); }); - it('Rotate by 315 degrees, square output ignoring aspect ratio', function (_t, done) { + it('Rotate by 315 degrees, square output ignoring aspect ratio', (_t, done) => { sharp(fixtures.inputJpg) .resize(240, 240, { fit: sharp.fit.fill }) .rotate(315) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(339, info.width); assert.strictEqual(339, info.height); - sharp(data).metadata(function (err, metadata) { + sharp(data).metadata((err, metadata) => { if (err) throw err; assert.strictEqual(339, metadata.width); assert.strictEqual(339, metadata.height); @@ -240,15 +240,15 @@ describe('Rotation', function () { }); }); - it('Rotate by 270 degrees, rectangular output ignoring aspect ratio', function (_t, done) { + it('Rotate by 270 degrees, rectangular output ignoring aspect ratio', (_t, done) => { sharp(fixtures.inputJpg) .rotate(270) .resize(320, 240, { fit: sharp.fit.fill }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); - sharp(data).metadata(function (err, metadata) { + sharp(data).metadata((err, metadata) => { if (err) throw err; assert.strictEqual(320, metadata.width); assert.strictEqual(240, metadata.height); @@ -257,15 +257,15 @@ describe('Rotation', function () { }); }); - it('Auto-rotate by 270 degrees, rectangular output ignoring aspect ratio', function (_t, done) { + it('Auto-rotate by 270 degrees, rectangular output ignoring aspect ratio', (_t, done) => { sharp(fixtures.inputJpgWithLandscapeExif8) .resize(320, 240, { fit: sharp.fit.fill }) .rotate() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); - sharp(data).metadata(function (err, metadata) { + sharp(data).metadata((err, metadata) => { if (err) throw err; assert.strictEqual(320, metadata.width); assert.strictEqual(240, metadata.height); @@ -274,15 +274,15 @@ describe('Rotation', function () { }); }); - it('Rotate by 30 degrees, rectangular output ignoring aspect ratio', function (_t, done) { + it('Rotate by 30 degrees, rectangular output ignoring aspect ratio', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240, { fit: sharp.fit.fill }) .rotate(30) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(397, info.width); assert.strictEqual(368, info.height); - sharp(data).metadata(function (err, metadata) { + sharp(data).metadata((err, metadata) => { if (err) throw err; assert.strictEqual(397, metadata.width); assert.strictEqual(368, metadata.height); @@ -291,17 +291,17 @@ describe('Rotation', function () { }); }); - it('Input image has Orientation EXIF tag but do not rotate output', function (_t, done) { + it('Input image has Orientation EXIF tag but do not rotate output', (_t, done) => { sharp(fixtures.inputJpgWithExif) .resize(320) .withMetadata() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); assert.strictEqual(427, info.height); - sharp(data).metadata(function (err, metadata) { + sharp(data).metadata((err, metadata) => { if (err) throw err; assert.strictEqual(8, metadata.orientation); done(); @@ -309,11 +309,11 @@ describe('Rotation', function () { }); }); - it('Input image has Orientation EXIF tag value of 8 (270 degrees), auto-rotate', function (_t, done) { + it('Input image has Orientation EXIF tag value of 8 (270 degrees), auto-rotate', (_t, done) => { sharp(fixtures.inputJpgWithExif) .rotate() .resize(320) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -322,17 +322,17 @@ describe('Rotation', function () { }); }); - it('Override EXIF Orientation tag metadata after auto-rotate', function (_t, done) { + it('Override EXIF Orientation tag metadata after auto-rotate', (_t, done) => { sharp(fixtures.inputJpgWithExif) .rotate() .resize(320) .withMetadata({ orientation: 3 }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); - sharp(data).metadata(function (err, metadata) { + sharp(data).metadata((err, metadata) => { if (err) throw err; assert.strictEqual(3, metadata.orientation); fixtures.assertSimilar(fixtures.expected('exif-8.jpg'), data, done); @@ -340,17 +340,17 @@ describe('Rotation', function () { }); }); - it('Input image has Orientation EXIF tag value of 5 (270 degrees + flip), auto-rotate', function (_t, done) { + it('Input image has Orientation EXIF tag value of 5 (270 degrees + flip), auto-rotate', (_t, done) => { sharp(fixtures.inputJpgWithExifMirroring) .rotate() .resize(320) .withMetadata() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); - sharp(data).metadata(function (err, metadata) { + sharp(data).metadata((err, metadata) => { if (err) throw err; assert.strictEqual(1, metadata.orientation); fixtures.assertSimilar(fixtures.expected('exif-5.jpg'), data, done); @@ -358,8 +358,8 @@ describe('Rotation', function () { }); }); - it('Attempt to auto-rotate using image that has no EXIF', function (_t, done) { - sharp(fixtures.inputJpg).rotate().resize(320).toBuffer(function (err, data, info) { + it('Attempt to auto-rotate using image that has no EXIF', (_t, done) => { + sharp(fixtures.inputJpg).rotate().resize(320).toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -369,12 +369,12 @@ describe('Rotation', function () { }); }); - it('Attempt to auto-rotate image format without EXIF support', function (_t, done) { + it('Attempt to auto-rotate image format without EXIF support', (_t, done) => { sharp(fixtures.inputPng) .rotate() .resize(320) .jpeg() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('jpeg', info.format); @@ -384,8 +384,8 @@ describe('Rotation', function () { }); }); - it('Rotate with a string argument, should fail', function () { - assert.throws(function () { + it('Rotate with a string argument, should fail', () => { + assert.throws(() => { sharp(fixtures.inputJpg).rotate('not-a-number'); }); }); @@ -436,18 +436,18 @@ describe('Rotation', function () { it('Multiple rotate emits warning', () => { let warningMessage = ''; const s = sharp(); - s.on('warning', function (msg) { warningMessage = msg; }); + s.on('warning', (msg) => { warningMessage = msg; }); s.rotate(90); assert.strictEqual(warningMessage, ''); s.rotate(180); assert.strictEqual(warningMessage, 'ignoring previous rotate options'); }); - it('Multiple rotate: last one wins (cardinal)', function (_t, done) { + it('Multiple rotate: last one wins (cardinal)', (_t, done) => { sharp(fixtures.inputJpg) .rotate(45) .rotate(90) - .toBuffer(function (err, _data, info) { + .toBuffer((err, _data, info) => { if (err) throw err; assert.strictEqual(2225, info.width); assert.strictEqual(2725, info.height); @@ -455,11 +455,11 @@ describe('Rotation', function () { }); }); - it('Multiple rotate: last one wins (non cardinal)', function (_t, done) { + it('Multiple rotate: last one wins (non cardinal)', (_t, done) => { sharp(fixtures.inputJpg) .rotate(90) .rotate(45) - .toBuffer(function (err, _data, info) { + .toBuffer((err, _data, info) => { if (err) throw err; assert.strictEqual(3500, info.width); assert.strictEqual(3500, info.height); @@ -467,17 +467,17 @@ describe('Rotation', function () { }); }); - it('Flip - vertical', function (_t, done) { + it('Flip - vertical', (_t, done) => { sharp(fixtures.inputJpg) .resize(320) .flip() .withMetadata() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); assert.strictEqual(261, info.height); - sharp(data).metadata(function (err, metadata) { + sharp(data).metadata((err, metadata) => { if (err) throw err; assert.strictEqual(1, metadata.orientation); fixtures.assertSimilar(fixtures.expected('flip.jpg'), data, done); @@ -485,17 +485,17 @@ describe('Rotation', function () { }); }); - it('Flop - horizontal', function (_t, done) { + it('Flop - horizontal', (_t, done) => { sharp(fixtures.inputJpg) .resize(320) .flop() .withMetadata() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); assert.strictEqual(261, info.height); - sharp(data).metadata(function (err, metadata) { + sharp(data).metadata((err, metadata) => { if (err) throw err; assert.strictEqual(1, metadata.orientation); fixtures.assertSimilar(fixtures.expected('flop.jpg'), data, done); @@ -503,12 +503,12 @@ describe('Rotation', function () { }); }); - it('Flip and flop', function (_t, done) { + it('Flip and flop', (_t, done) => { sharp(fixtures.inputJpg) .resize(320) .flip() .flop() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -517,12 +517,12 @@ describe('Rotation', function () { }); }); - it('Neither flip nor flop', function (_t, done) { + it('Neither flip nor flop', (_t, done) => { sharp(fixtures.inputJpg) .resize(320) .flip(false) .flop(false) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -531,12 +531,12 @@ describe('Rotation', function () { }); }); - it('Auto-rotate and flip', function (_t, done) { + it('Auto-rotate and flip', (_t, done) => { sharp(fixtures.inputJpgWithExif) .rotate() .flip() .resize(320) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -545,12 +545,12 @@ describe('Rotation', function () { }); }); - it('Auto-rotate and flop', function (_t, done) { + it('Auto-rotate and flop', (_t, done) => { sharp(fixtures.inputJpgWithExif) .rotate() .flop() .resize(320) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); diff --git a/test/unit/sharpen.js b/test/unit/sharpen.js index 66eae7049..9ea354a71 100644 --- a/test/unit/sharpen.js +++ b/test/unit/sharpen.js @@ -9,12 +9,12 @@ const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); -describe('Sharpen', function () { - it('specific radius 10 (sigma 6)', function (_t, done) { +describe('Sharpen', () => { + it('specific radius 10 (sigma 6)', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .sharpen(6) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -23,11 +23,11 @@ describe('Sharpen', function () { }); }); - it('specific radius 3 (sigma 1.5) and levels 0.5, 2.5', function (_t, done) { + it('specific radius 3 (sigma 1.5) and levels 0.5, 2.5', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .sharpen(1.5, 0.5, 2.5) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -36,11 +36,11 @@ describe('Sharpen', function () { }); }); - it('specific radius 5 (sigma 3.5) and levels 2, 4', function (_t, done) { + it('specific radius 5 (sigma 3.5) and levels 2, 4', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .sharpen(3.5, 2, 4) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -66,11 +66,11 @@ describe('Sharpen', function () { }); if (!process.env.SHARP_TEST_WITHOUT_CACHE) { - it('specific radius/levels with alpha channel', function (_t, done) { + it('specific radius/levels with alpha channel', (_t, done) => { sharp(fixtures.inputPngWithTransparency) .resize(320, 240) .sharpen(5, 4, 8) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(4, info.channels); @@ -81,11 +81,11 @@ describe('Sharpen', function () { }); } - it('mild sharpen', function (_t, done) { + it('mild sharpen', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .sharpen() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -94,20 +94,20 @@ describe('Sharpen', function () { }); }); - it('invalid sigma', function () { - assert.throws(function () { + it('invalid sigma', () => { + assert.throws(() => { sharp(fixtures.inputJpg).sharpen(-1.5); }); }); - it('invalid flat', function () { - assert.throws(function () { + it('invalid flat', () => { + assert.throws(() => { sharp(fixtures.inputJpg).sharpen(1, -1); }); }); - it('invalid jagged', function () { - assert.throws(function () { + it('invalid jagged', () => { + assert.throws(() => { sharp(fixtures.inputJpg).sharpen(1, 1, -1); }); }); @@ -142,11 +142,11 @@ describe('Sharpen', function () { /Expected number between 0 and 1000000 for options\.y3 but received -1 of type number/ )); - it('sharpened image is larger than non-sharpened', function (_t, done) { + it('sharpened image is larger than non-sharpened', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .sharpen(false) - .toBuffer(function (err, notSharpened, info) { + .toBuffer((err, notSharpened, info) => { if (err) throw err; assert.strictEqual(true, notSharpened.length > 0); assert.strictEqual('jpeg', info.format); @@ -155,7 +155,7 @@ describe('Sharpen', function () { sharp(fixtures.inputJpg) .resize(320, 240) .sharpen(true) - .toBuffer(function (err, sharpened, info) { + .toBuffer((err, sharpened, info) => { if (err) throw err; assert.strictEqual(true, sharpened.length > 0); assert.strictEqual(true, sharpened.length > notSharpened.length); diff --git a/test/unit/stats.js b/test/unit/stats.js index be42793d4..9164787e3 100644 --- a/test/unit/stats.js +++ b/test/unit/stats.js @@ -22,9 +22,9 @@ function isInteger (val) { return Number.isInteger(val); } -describe('Image Stats', function () { - it('JPEG', function (_t, done) { - sharp(fixtures.inputJpg).stats(function (err, stats) { +describe('Image Stats', () => { + it('JPEG', (_t, done) => { + sharp(fixtures.inputJpg).stats((err, stats) => { if (err) throw err; assert.strictEqual(true, stats.isOpaque); @@ -88,8 +88,8 @@ describe('Image Stats', function () { }); }); - it('PNG without transparency', function (_t, done) { - sharp(fixtures.inputPng).stats(function (err, stats) { + it('PNG without transparency', (_t, done) => { + sharp(fixtures.inputPng).stats((err, stats) => { if (err) throw err; assert.strictEqual(true, stats.isOpaque); @@ -120,8 +120,8 @@ describe('Image Stats', function () { }); }); - it('PNG with transparency', function (_t, done) { - sharp(fixtures.inputPngWithTransparency).stats(function (err, stats) { + it('PNG with transparency', (_t, done) => { + sharp(fixtures.inputPngWithTransparency).stats((err, stats) => { if (err) throw err; assert.strictEqual(false, stats.isOpaque); @@ -201,8 +201,8 @@ describe('Image Stats', function () { }); }); - it('PNG fully transparent', function (_t, done) { - sharp(fixtures.inputPngCompleteTransparency).stats(function (err, stats) { + it('PNG fully transparent', (_t, done) => { + sharp(fixtures.inputPngCompleteTransparency).stats((err, stats) => { if (err) throw err; assert.strictEqual(false, stats.isOpaque); @@ -234,8 +234,8 @@ describe('Image Stats', function () { }); }); - it('Tiff', function (_t, done) { - sharp(fixtures.inputTiff).stats(function (err, stats) { + it('Tiff', (_t, done) => { + sharp(fixtures.inputTiff).stats((err, stats) => { if (err) throw err; assert.strictEqual(true, stats.isOpaque); @@ -267,8 +267,8 @@ describe('Image Stats', function () { }); }); - it('WebP', function (_t, done) { - sharp(fixtures.inputWebP).stats(function (err, stats) { + it('WebP', (_t, done) => { + sharp(fixtures.inputWebP).stats((err, stats) => { if (err) throw err; assert.strictEqual(true, stats.isOpaque); @@ -332,8 +332,8 @@ describe('Image Stats', function () { }); }); - it('GIF', function (_t, done) { - sharp(fixtures.inputGif).stats(function (err, stats) { + it('GIF', (_t, done) => { + sharp(fixtures.inputGif).stats((err, stats) => { if (err) throw err; assert.strictEqual(true, stats.isOpaque); @@ -397,8 +397,8 @@ describe('Image Stats', function () { }); }); - it('Grayscale GIF with alpha', function (_t, done) { - sharp(fixtures.inputGifGreyPlusAlpha).stats(function (err, stats) { + it('Grayscale GIF with alpha', (_t, done) => { + sharp(fixtures.inputGifGreyPlusAlpha).stats((err, stats) => { if (err) throw err; assert.strictEqual(false, stats.isOpaque); @@ -479,9 +479,9 @@ describe('Image Stats', function () { assert.strictEqual(sharpness, 0); }); - it('Stream in, Callback out', function (_t, done) { + it('Stream in, Callback out', (_t, done) => { const readable = fs.createReadStream(fixtures.inputJpg); - const pipeline = sharp().stats(function (err, stats) { + const pipeline = sharp().stats((err, stats) => { if (err) throw err; assert.strictEqual(true, stats.isOpaque); @@ -546,12 +546,12 @@ describe('Image Stats', function () { readable.pipe(pipeline); }); - it('Stream in, Promise out', function () { + it('Stream in, Promise out', () => { const pipeline = sharp(); fs.createReadStream(fixtures.inputJpg).pipe(pipeline); - return pipeline.stats().then(function (stats) { + return pipeline.stats().then((stats) => { assert.strictEqual(true, stats.isOpaque); assert.strictEqual(true, isInAcceptableRange(stats.entropy, 7.332915340666659)); assert.strictEqual(true, isInAcceptableRange(stats.sharpness, 0.788301114707569)); @@ -608,13 +608,12 @@ describe('Image Stats', function () { assert.strictEqual(true, isInRange(stats.channels[0].maxX, 0, 2725)); assert.strictEqual(true, isInteger(stats.channels[0].maxY)); assert.strictEqual(true, isInRange(stats.channels[0].maxY, 0, 2725)); - }).catch(function (err) { + }).catch((err) => { throw err; }); }); - it('File in, Promise out', function () { - return sharp(fixtures.inputJpg).stats().then(function (stats) { + it('File in, Promise out', () => sharp(fixtures.inputJpg).stats().then((stats) => { assert.strictEqual(true, stats.isOpaque); assert.strictEqual(true, isInAcceptableRange(stats.entropy, 7.332915340666659)); assert.strictEqual(true, isInAcceptableRange(stats.sharpness, 0.788301114707569)); @@ -671,10 +670,9 @@ describe('Image Stats', function () { assert.strictEqual(true, isInRange(stats.channels[0].maxX, 0, 2725)); assert.strictEqual(true, isInteger(stats.channels[0].maxY)); assert.strictEqual(true, isInRange(stats.channels[0].maxY, 0, 2725)); - }).catch(function (err) { + }).catch((err) => { throw err; - }); - }); + })); it('Blurred image has lower sharpness than original', () => { const original = sharp(fixtures.inputJpg).stats(); @@ -688,9 +686,9 @@ describe('Image Stats', function () { }); }); - it('File input with corrupt header fails gracefully', function (_t, done) { + it('File input with corrupt header fails gracefully', (_t, done) => { sharp(fixtures.inputJpgWithCorruptHeader) - .stats(function (err) { + .stats((err) => { assert(err.message.includes('Input file has corrupt header')); assert(err.stack.includes('at Sharp.stats')); assert(err.stack.includes(__filename)); @@ -698,10 +696,10 @@ describe('Image Stats', function () { }); }); - it('Stream input with corrupt header fails gracefully', function (_t, done) { + it('Stream input with corrupt header fails gracefully', (_t, done) => { fs.createReadStream(fixtures.inputJpgWithCorruptHeader).pipe( sharp() - .stats(function (err) { + .stats((err) => { assert(err.message.includes('Input buffer has corrupt header')); assert(err.stack.includes('at Sharp.stats')); assert(err.stack.includes(__filename)); @@ -710,40 +708,38 @@ describe('Image Stats', function () { ); }); - it('File input with corrupt header fails gracefully, Promise out', function () { - return sharp(fixtures.inputJpgWithCorruptHeader) - .stats().then(function () { + it('File input with corrupt header fails gracefully, Promise out', () => sharp(fixtures.inputJpgWithCorruptHeader) + .stats().then(() => { throw new Error('Corrupt Header file'); - }).catch(function (err) { + }).catch((err) => { assert.ok(!!err); - }); - }); + })); - it('File input with corrupt header fails gracefully, Stream In, Promise Out', function () { + it('File input with corrupt header fails gracefully, Stream In, Promise Out', () => { const pipeline = sharp(); fs.createReadStream(fixtures.inputJpgWithCorruptHeader).pipe(pipeline); return pipeline - .stats().then(function () { + .stats().then(() => { throw new Error('Corrupt Header file'); - }).catch(function (err) { + }).catch((err) => { assert.ok(!!err); }); }); - it('Buffer input with corrupt header fails gracefully', function (_t, done) { + it('Buffer input with corrupt header fails gracefully', (_t, done) => { sharp(fs.readFileSync(fixtures.inputJpgWithCorruptHeader)) - .stats(function (err) { + .stats((err) => { assert.strictEqual(true, !!err); done(); }); }); - it('Non-existent file in, Promise out', function (_t, done) { - sharp('fail').stats().then(function () { + it('Non-existent file in, Promise out', (_t, done) => { + sharp('fail').stats().then(() => { throw new Error('Non-existent file'); - }, function (err) { + }, (err) => { assert.ok(!!err); done(); }); diff --git a/test/unit/svg.js b/test/unit/svg.js index a772bb378..d11b61895 100644 --- a/test/unit/svg.js +++ b/test/unit/svg.js @@ -10,20 +10,20 @@ const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); -describe('SVG input', function () { - it('Convert SVG to PNG at default 72DPI', function (_t, done) { +describe('SVG input', () => { + it('Convert SVG to PNG at default 72DPI', (_t, done) => { sharp(fixtures.inputSvg) .resize(1024) .extract({ left: 290, top: 760, width: 40, height: 40 }) .toFormat('png') - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(40, info.width); assert.strictEqual(40, info.height); - fixtures.assertSimilar(fixtures.expected('svg72.png'), data, function (err) { + fixtures.assertSimilar(fixtures.expected('svg72.png'), data, (err) => { if (err) throw err; - sharp(data).metadata(function (err, info) { + sharp(data).metadata((err, info) => { if (err) throw err; assert.strictEqual(72, info.density); done(); @@ -32,19 +32,19 @@ describe('SVG input', function () { }); }); - it('Convert SVG to PNG at 1200DPI', function (_t, done) { + it('Convert SVG to PNG at 1200DPI', (_t, done) => { sharp(fixtures.inputSvg, { density: 1200 }) .resize(1024) .extract({ left: 290, top: 760, width: 40, height: 40 }) .toFormat('png') - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(40, info.width); assert.strictEqual(40, info.height); - fixtures.assertSimilar(fixtures.expected('svg1200.png'), data, function (err) { + fixtures.assertSimilar(fixtures.expected('svg1200.png'), data, (err) => { if (err) throw err; - sharp(data).metadata(function (err, info) { + sharp(data).metadata((err, info) => { if (err) throw err; assert.strictEqual(1200, info.density); done(); @@ -53,22 +53,22 @@ describe('SVG input', function () { }); }); - it('Convert SVG to PNG at DPI larger than 2400', function (_t, done) { + it('Convert SVG to PNG at DPI larger than 2400', (_t, done) => { const size = 1024; - sharp(fixtures.inputSvgSmallViewBox).metadata(function (err, metadata) { + sharp(fixtures.inputSvgSmallViewBox).metadata((err, metadata) => { if (err) throw err; const density = (size / Math.max(metadata.width, metadata.height)) * metadata.density; sharp(fixtures.inputSvgSmallViewBox, { density }) .resize(size) .toFormat('png') - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(size, info.width); assert.strictEqual(size, info.height); - fixtures.assertSimilar(fixtures.expected('circle.png'), data, function (err) { + fixtures.assertSimilar(fixtures.expected('circle.png'), data, (err) => { if (err) throw err; - sharp(data).metadata(function (err, info) { + sharp(data).metadata((err, info) => { if (err) throw err; assert.strictEqual(9216, info.density); done(); @@ -78,19 +78,19 @@ describe('SVG input', function () { }); }); - it('Convert SVG to PNG utilizing scale-on-load', function (_t, done) { + it('Convert SVG to PNG utilizing scale-on-load', (_t, done) => { const size = 1024; sharp(fixtures.inputSvgSmallViewBox) .resize(size) .toFormat('png') - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(size, info.width); assert.strictEqual(size, info.height); - fixtures.assertSimilar(fixtures.expected('circle.png'), data, function (err) { + fixtures.assertSimilar(fixtures.expected('circle.png'), data, (err) => { if (err) throw err; - sharp(data).metadata(function (err, info) { + sharp(data).metadata((err, info) => { if (err) throw err; assert.strictEqual(72, info.density); done(); @@ -99,24 +99,24 @@ describe('SVG input', function () { }); }); - it('Convert SVG to PNG at 14.4DPI', function (_t, done) { + it('Convert SVG to PNG at 14.4DPI', (_t, done) => { sharp(fixtures.inputSvg, { density: 14.4 }) .toFormat('png') - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(20, info.width); assert.strictEqual(20, info.height); - fixtures.assertSimilar(fixtures.expected('svg14.4.png'), data, function (err) { + fixtures.assertSimilar(fixtures.expected('svg14.4.png'), data, (err) => { if (err) throw err; done(); }); }); }); - it('Convert SVG with embedded images to PNG, respecting dimensions, autoconvert to PNG', function (_t, done) { + it('Convert SVG with embedded images to PNG, respecting dimensions, autoconvert to PNG', (_t, done) => { sharp(fixtures.inputSvgWithEmbeddedImages) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(480, info.width); diff --git a/test/unit/text.js b/test/unit/text.js index 77a8177fd..029b45f1f 100644 --- a/test/unit/text.js +++ b/test/unit/text.js @@ -10,8 +10,8 @@ const sharp = require('../../'); const fixtures = require('../fixtures'); const { inRange } = require('../../lib/is'); -describe('Text to image', function () { - it('text with default values', async function (t) { +describe('Text to image', () => { + it('text with default values', async (t) => { const output = fixtures.path('output.text-default.png'); const text = sharp({ text: { @@ -41,7 +41,7 @@ describe('Text to image', function () { assert.ok(info.textAutofitDpi > 0); }); - it('text with width and height', async function (t) { + it('text with width and height', async (t) => { const output = fixtures.path('output.text-width-height.png'); const text = sharp({ text: { @@ -61,7 +61,7 @@ describe('Text to image', function () { assert.ok(inRange(info.textAutofitDpi, 900, 1300), `Actual textAutofitDpi ${info.textAutofitDpi}`); }); - it('text with dpi', async function (t) { + it('text with dpi', async (t) => { const output = fixtures.path('output.text-dpi.png'); const dpi = 300; const text = sharp({ @@ -79,7 +79,7 @@ describe('Text to image', function () { assert.strictEqual(dpi, metadata.density); }); - it('text with color and pango markup', async function (t) { + it('text with color and pango markup', async (t) => { const output = fixtures.path('output.text-color-pango.png'); const dpi = 300; const text = sharp({ @@ -101,7 +101,7 @@ describe('Text to image', function () { assert.strictEqual(true, metadata.hasAlpha); }); - it('text with font', async function (t) { + it('text with font', async (t) => { const output = fixtures.path('output.text-with-font.png'); const text = sharp({ text: { @@ -119,7 +119,7 @@ describe('Text to image', function () { assert.ok(info.height > 10); }); - it('text with justify and composite', async function (t) { + it('text with justify and composite', async (t) => { const output = fixtures.path('output.text-composite.png'); const width = 500; const dpi = 300; @@ -164,8 +164,8 @@ describe('Text to image', function () { assert.strictEqual(true, metadata.hasAlpha); }); - it('bad text input', function () { - assert.throws(function () { + it('bad text input', () => { + assert.throws(() => { sharp({ text: { } @@ -173,8 +173,8 @@ describe('Text to image', function () { }); }); - it('fontfile input', function () { - assert.doesNotThrow(function () { + it('fontfile input', () => { + assert.doesNotThrow(() => { sharp({ text: { text: 'text', @@ -184,8 +184,8 @@ describe('Text to image', function () { }); }); - it('bad font input', function () { - assert.throws(function () { + it('bad font input', () => { + assert.throws(() => { sharp({ text: { text: 'text', @@ -195,8 +195,8 @@ describe('Text to image', function () { }); }); - it('bad fontfile input', function () { - assert.throws(function () { + it('bad fontfile input', () => { + assert.throws(() => { sharp({ text: { text: 'text', @@ -236,8 +236,8 @@ describe('Text to image', function () { ); }); - it('bad align input', function () { - assert.throws(function () { + it('bad align input', () => { + assert.throws(() => { sharp({ text: { text: 'text', @@ -247,8 +247,8 @@ describe('Text to image', function () { }); }); - it('bad justify input', function () { - assert.throws(function () { + it('bad justify input', () => { + assert.throws(() => { sharp({ text: { text: 'text', @@ -273,8 +273,8 @@ describe('Text to image', function () { ); }); - it('bad rgba input', function () { - assert.throws(function () { + it('bad rgba input', () => { + assert.throws(() => { sharp({ text: { text: 'text', @@ -299,8 +299,8 @@ describe('Text to image', function () { ); }); - it('only height or dpi not both', function () { - assert.throws(function () { + it('only height or dpi not both', () => { + assert.throws(() => { sharp({ text: { text: 'text', diff --git a/test/unit/threshold.js b/test/unit/threshold.js index 1b0956f5b..1ffb0f9cc 100644 --- a/test/unit/threshold.js +++ b/test/unit/threshold.js @@ -9,12 +9,12 @@ const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); -describe('Threshold', function () { - it('threshold 1 jpeg', function (_t, done) { +describe('Threshold', () => { + it('threshold 1 jpeg', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .threshold(1) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -23,11 +23,11 @@ describe('Threshold', function () { }); }); - it('threshold 40 jpeg', function (_t, done) { + it('threshold 40 jpeg', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .threshold(40) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -36,11 +36,11 @@ describe('Threshold', function () { }); }); - it('threshold 128', function (_t, done) { + it('threshold 128', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .threshold(128) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -49,11 +49,11 @@ describe('Threshold', function () { }); }); - it('threshold true (=128)', function (_t, done) { + it('threshold true (=128)', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .threshold(true) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -62,20 +62,20 @@ describe('Threshold', function () { }); }); - it('threshold false (=0)', function (_t, done) { + it('threshold false (=0)', (_t, done) => { sharp(fixtures.inputJpg) .threshold(false) - .toBuffer(function (err, data) { + .toBuffer((err, data) => { if (err) throw err; fixtures.assertSimilar(fixtures.inputJpg, data, done); }); }); - it('threshold grayscale: true (=128)', function (_t, done) { + it('threshold grayscale: true (=128)', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .threshold(128, { grayscale: true }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -84,11 +84,11 @@ describe('Threshold', function () { }); }); - it('threshold default jpeg', function (_t, done) { + it('threshold default jpeg', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .threshold() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -97,11 +97,11 @@ describe('Threshold', function () { }); }); - it('threshold default png transparency', function (_t, done) { + it('threshold default png transparency', (_t, done) => { sharp(fixtures.inputPngWithTransparency) .resize(320, 240) .threshold() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(320, info.width); @@ -110,11 +110,11 @@ describe('Threshold', function () { }); }); - it('threshold default png alpha', function (_t, done) { + it('threshold default png alpha', (_t, done) => { sharp(fixtures.inputPngWithGreyAlpha) .resize(320, 240) .threshold() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('png', info.format); assert.strictEqual(320, info.width); @@ -123,21 +123,21 @@ describe('Threshold', function () { }); }); - it('threshold default webp transparency', function (_t, done) { + it('threshold default webp transparency', (_t, done) => { sharp(fixtures.inputWebPWithTransparency) .threshold() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('webp', info.format); fixtures.assertSimilar(fixtures.expected('threshold-128-transparency.webp'), data, done); }); }); - it('color threshold', function (_t, done) { + it('color threshold', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .threshold(128, { grayscale: false }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(320, info.width); @@ -146,14 +146,14 @@ describe('Threshold', function () { }); }); - it('invalid threshold -1', function () { - assert.throws(function () { + it('invalid threshold -1', () => { + assert.throws(() => { sharp().threshold(-1); }); }); - it('invalid threshold 256', function () { - assert.throws(function () { + it('invalid threshold 256', () => { + assert.throws(() => { sharp().threshold(256); }); }); diff --git a/test/unit/tiff.js b/test/unit/tiff.js index 6fc87b040..be5e5535f 100644 --- a/test/unit/tiff.js +++ b/test/unit/tiff.js @@ -12,13 +12,13 @@ const fixtures = require('../fixtures'); const outputTiff = fixtures.path('output.tiff'); -describe('TIFF', function () { - it('Load TIFF from Buffer', function (_t, done) { +describe('TIFF', () => { + it('Load TIFF from Buffer', (_t, done) => { const inputTiffBuffer = fs.readFileSync(fixtures.inputTiff); sharp(inputTiffBuffer) .resize(320, 240) .jpeg() - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual(data.length, info.size); @@ -29,10 +29,10 @@ describe('TIFF', function () { }); }); - it('Load multi-page TIFF from file', function (_t, done) { + it('Load multi-page TIFF from file', (_t, done) => { sharp(fixtures.inputTiffMultipage) // defaults to page 0 .jpeg() - .toBuffer(function (err, defaultData, defaultInfo) { + .toBuffer((err, defaultData, defaultInfo) => { if (err) throw err; assert.strictEqual(true, defaultData.length > 0); assert.strictEqual(defaultData.length, defaultInfo.size); @@ -40,7 +40,7 @@ describe('TIFF', function () { sharp(fixtures.inputTiffMultipage, { page: 1 }) // 50%-scale copy of page 0 .jpeg() - .toBuffer(function (err, scaledData, scaledInfo) { + .toBuffer((err, scaledData, scaledInfo) => { if (err) throw err; assert.strictEqual(true, scaledData.length > 0); assert.strictEqual(scaledData.length, scaledInfo.size); @@ -52,11 +52,11 @@ describe('TIFF', function () { }); }); - it('Load multi-page TIFF from Buffer', function (_t, done) { + it('Load multi-page TIFF from Buffer', (_t, done) => { const inputTiffBuffer = fs.readFileSync(fixtures.inputTiffMultipage); sharp(inputTiffBuffer) // defaults to page 0 .jpeg() - .toBuffer(function (err, defaultData, defaultInfo) { + .toBuffer((err, defaultData, defaultInfo) => { if (err) throw err; assert.strictEqual(true, defaultData.length > 0); assert.strictEqual(defaultData.length, defaultInfo.size); @@ -64,7 +64,7 @@ describe('TIFF', function () { sharp(inputTiffBuffer, { page: 1 }) // 50%-scale copy of page 0 .jpeg() - .toBuffer(function (err, scaledData, scaledInfo) { + .toBuffer((err, scaledData, scaledInfo) => { if (err) throw err; assert.strictEqual(true, scaledData.length > 0); assert.strictEqual(scaledData.length, scaledInfo.size); @@ -76,10 +76,10 @@ describe('TIFF', function () { }); }); - it('Save TIFF to Buffer', function (_t, done) { + it('Save TIFF to Buffer', (_t, done) => { sharp(fixtures.inputTiff) .resize(320, 240) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual(data.length, info.size); @@ -105,19 +105,19 @@ describe('TIFF', function () { ) ); - it('Invalid TIFF quality throws error', function () { - assert.throws(function () { + it('Invalid TIFF quality throws error', () => { + assert.throws(() => { sharp().tiff({ quality: 101 }); }); }); - it('Missing TIFF quality does not throw error', function () { - assert.doesNotThrow(function () { + it('Missing TIFF quality does not throw error', () => { + assert.doesNotThrow(() => { sharp().tiff(); }); }); - it('Not squashing TIFF to a bit depth of 1 should not change the file size', function (_t, done) { + it('Not squashing TIFF to a bit depth of 1 should not change the file size', (_t, done) => { const startSize = fs.statSync(fixtures.inputTiff8BitDepth).size; sharp(fixtures.inputTiff8BitDepth) .toColourspace('b-w') // can only squash 1 band uchar images @@ -134,7 +134,7 @@ describe('TIFF', function () { }); }); - it('Squashing TIFF to a bit depth of 1 should significantly reduce file size', function (_t, done) { + it('Squashing TIFF to a bit depth of 1 should significantly reduce file size', (_t, done) => { const startSize = fs.statSync(fixtures.inputTiff8BitDepth).size; sharp(fixtures.inputTiff8BitDepth) .toColourspace('b-w') // can only squash 1 band uchar images @@ -151,8 +151,8 @@ describe('TIFF', function () { }); }); - it('Invalid TIFF bitdepth value throws error', function () { - assert.throws(function () { + it('Invalid TIFF bitdepth value throws error', () => { + assert.throws(() => { sharp().tiff({ bitdepth: 3 }); }, /Error: Expected 1, 2, 4 or 8 for bitdepth but received 3 of type number/); }); @@ -210,19 +210,19 @@ describe('TIFF', function () { assert.strictEqual(25400, density); }); - it('TIFF invalid xres value should throw an error', function () { - assert.throws(function () { + it('TIFF invalid xres value should throw an error', () => { + assert.throws(() => { sharp().tiff({ xres: '1000.0' }); }); }); - it('TIFF invalid yres value should throw an error', function () { - assert.throws(function () { + it('TIFF invalid yres value should throw an error', () => { + assert.throws(() => { sharp().tiff({ yres: '1000.0' }); }); }); - it('TIFF lzw compression with horizontal predictor shrinks test file', function (_t, done) { + it('TIFF lzw compression with horizontal predictor shrinks test file', (_t, done) => { const startSize = fs.statSync(fixtures.inputTiffUncompressed).size; sharp(fixtures.inputTiffUncompressed) .tiff({ @@ -274,7 +274,7 @@ describe('TIFF', function () { }) ); - it('TIFF ccittfax4 compression shrinks b-w test file', function (_t, done) { + it('TIFF ccittfax4 compression shrinks b-w test file', (_t, done) => { const startSize = fs.statSync(fixtures.inputTiff).size; sharp(fixtures.inputTiff) .toColourspace('b-w') @@ -314,7 +314,7 @@ describe('TIFF', function () { assert.strictEqual(resolutionUnit, 'cm'); }); - it('TIFF deflate compression with horizontal predictor shrinks test file', function (_t, done) { + it('TIFF deflate compression with horizontal predictor shrinks test file', (_t, done) => { const startSize = fs.statSync(fixtures.inputTiffUncompressed).size; sharp(fixtures.inputTiffUncompressed) .tiff({ @@ -329,7 +329,7 @@ describe('TIFF', function () { }); }); - it('TIFF deflate compression with float predictor shrinks test file', function (_t, done) { + it('TIFF deflate compression with float predictor shrinks test file', (_t, done) => { const startSize = fs.statSync(fixtures.inputTiffUncompressed).size; sharp(fixtures.inputTiffUncompressed) .tiff({ @@ -344,7 +344,7 @@ describe('TIFF', function () { }); }); - it('TIFF deflate compression without predictor shrinks test file', function (_t, done) { + it('TIFF deflate compression without predictor shrinks test file', (_t, done) => { const startSize = fs.statSync(fixtures.inputTiffUncompressed).size; sharp(fixtures.inputTiffUncompressed) .tiff({ @@ -359,7 +359,7 @@ describe('TIFF', function () { }); }); - it('TIFF jpeg compression shrinks test file', function (_t, done) { + it('TIFF jpeg compression shrinks test file', (_t, done) => { const startSize = fs.statSync(fixtures.inputTiffUncompressed).size; sharp(fixtures.inputTiffUncompressed) .tiff({ @@ -373,79 +373,79 @@ describe('TIFF', function () { }); }); - it('TIFF none compression does not throw error', function () { - assert.doesNotThrow(function () { + it('TIFF none compression does not throw error', () => { + assert.doesNotThrow(() => { sharp().tiff({ compression: 'none' }); }); }); - it('TIFF lzw compression does not throw error', function () { - assert.doesNotThrow(function () { + it('TIFF lzw compression does not throw error', () => { + assert.doesNotThrow(() => { sharp().tiff({ compression: 'lzw' }); }); }); - it('TIFF deflate compression does not throw error', function () { - assert.doesNotThrow(function () { + it('TIFF deflate compression does not throw error', () => { + assert.doesNotThrow(() => { sharp().tiff({ compression: 'deflate' }); }); }); - it('TIFF invalid compression option throws', function () { - assert.throws(function () { + it('TIFF invalid compression option throws', () => { + assert.throws(() => { sharp().tiff({ compression: 0 }); }); }); - it('TIFF invalid compression option throws', function () { - assert.throws(function () { + it('TIFF invalid compression option throws', () => { + assert.throws(() => { sharp().tiff({ compression: 'a' }); }); }); - it('TIFF bigtiff true value does not throw error', function () { - assert.doesNotThrow(function () { + it('TIFF bigtiff true value does not throw error', () => { + assert.doesNotThrow(() => { sharp().tiff({ bigtiff: true }); }); }); - it('Invalid TIFF bigtiff value throws error', function () { - assert.throws(function () { + it('Invalid TIFF bigtiff value throws error', () => { + assert.throws(() => { sharp().tiff({ bigtiff: 'true' }); }); }); - it('TIFF invalid predictor option throws', function () { - assert.throws(function () { + it('TIFF invalid predictor option throws', () => { + assert.throws(() => { sharp().tiff({ predictor: 'a' }); }); }); - it('TIFF invalid resolutionUnit option throws', function () { - assert.throws(function () { + it('TIFF invalid resolutionUnit option throws', () => { + assert.throws(() => { sharp().tiff({ resolutionUnit: 'none' }); }); }); - it('TIFF horizontal predictor does not throw error', function () { - assert.doesNotThrow(function () { + it('TIFF horizontal predictor does not throw error', () => { + assert.doesNotThrow(() => { sharp().tiff({ predictor: 'horizontal' }); }); }); - it('TIFF float predictor does not throw error', function () { - assert.doesNotThrow(function () { + it('TIFF float predictor does not throw error', () => { + assert.doesNotThrow(() => { sharp().tiff({ predictor: 'float' }); }); }); - it('TIFF none predictor does not throw error', function () { - assert.doesNotThrow(function () { + it('TIFF none predictor does not throw error', () => { + assert.doesNotThrow(() => { sharp().tiff({ predictor: 'none' }); }); }); - it('TIFF tiled pyramid image without compression enlarges test file', function (_t, done) { + it('TIFF tiled pyramid image without compression enlarges test file', (_t, done) => { const startSize = fs.statSync(fixtures.inputTiffUncompressed).size; sharp(fixtures.inputTiffUncompressed) .tiff({ @@ -463,89 +463,89 @@ describe('TIFF', function () { }); }); - it('TIFF pyramid true value does not throw error', function () { - assert.doesNotThrow(function () { + it('TIFF pyramid true value does not throw error', () => { + assert.doesNotThrow(() => { sharp().tiff({ pyramid: true }); }); }); - it('Invalid TIFF pyramid value throws error', function () { - assert.throws(function () { + it('Invalid TIFF pyramid value throws error', () => { + assert.throws(() => { sharp().tiff({ pyramid: 'true' }); }); }); - it('TIFF miniswhite true value does not throw error', function () { - assert.doesNotThrow(function () { + it('TIFF miniswhite true value does not throw error', () => { + assert.doesNotThrow(() => { sharp().tiff({ miniswhite: true }); }); }); - it('Invalid TIFF miniswhite value throws error', function () { - assert.throws(function () { + it('Invalid TIFF miniswhite value throws error', () => { + assert.throws(() => { sharp().tiff({ miniswhite: 'true' }); }); }); - it('Invalid TIFF tile value throws error', function () { - assert.throws(function () { + it('Invalid TIFF tile value throws error', () => { + assert.throws(() => { sharp().tiff({ tile: 'true' }); }); }); - it('TIFF tile true value does not throw error', function () { - assert.doesNotThrow(function () { + it('TIFF tile true value does not throw error', () => { + assert.doesNotThrow(() => { sharp().tiff({ tile: true }); }); }); - it('Valid TIFF tileHeight value does not throw error', function () { - assert.doesNotThrow(function () { + it('Valid TIFF tileHeight value does not throw error', () => { + assert.doesNotThrow(() => { sharp().tiff({ tileHeight: 512 }); }); }); - it('Valid TIFF tileWidth value does not throw error', function () { - assert.doesNotThrow(function () { + it('Valid TIFF tileWidth value does not throw error', () => { + assert.doesNotThrow(() => { sharp().tiff({ tileWidth: 512 }); }); }); - it('Invalid TIFF tileHeight value throws error', function () { - assert.throws(function () { + it('Invalid TIFF tileHeight value throws error', () => { + assert.throws(() => { sharp().tiff({ tileHeight: '256' }); }); }); - it('Invalid TIFF tileWidth value throws error', function () { - assert.throws(function () { + it('Invalid TIFF tileWidth value throws error', () => { + assert.throws(() => { sharp().tiff({ tileWidth: '256' }); }); }); - it('Invalid TIFF tileHeight value throws error', function () { - assert.throws(function () { + it('Invalid TIFF tileHeight value throws error', () => { + assert.throws(() => { sharp().tiff({ tileHeight: 0 }); }); }); - it('Invalid TIFF tileWidth value throws error', function () { - assert.throws(function () { + it('Invalid TIFF tileWidth value throws error', () => { + assert.throws(() => { sharp().tiff({ tileWidth: 0 }); }); }); - it('TIFF file input with invalid page fails gracefully', function (_t, done) { + it('TIFF file input with invalid page fails gracefully', (_t, done) => { sharp(fixtures.inputTiffMultipage, { page: 2 }) - .toBuffer(function (err) { + .toBuffer((err) => { assert.strictEqual(true, !!err); done(); }); }); - it('TIFF buffer input with invalid page fails gracefully', function (_t, done) { + it('TIFF buffer input with invalid page fails gracefully', (_t, done) => { sharp(fs.readFileSync(fixtures.inputTiffMultipage), { page: 2 }) - .toBuffer(function (err) { + .toBuffer((err) => { assert.strictEqual(true, !!err); done(); }); diff --git a/test/unit/tile.js b/test/unit/tile.js index 77521bce3..8d477ebfa 100644 --- a/test/unit/tile.js +++ b/test/unit/tile.js @@ -14,27 +14,26 @@ const sharp = require('../../'); const fixtures = require('../fixtures'); // Verifies all tiles in a given dz output directory are <= size -const assertDeepZoomTiles = function (directory, expectedSize, expectedLevels, done) { +const assertDeepZoomTiles = (directory, expectedSize, expectedLevels, done) => { // Get levels const dirents = fs.readdirSync(directory, { withFileTypes: true }); const levels = dirents.filter(dirent => dirent.isDirectory()).map(dirent => dirent.name); assert.strictEqual(expectedLevels, levels.length); // Get tiles const tiles = []; - levels.forEach(function (level) { + levels.forEach((level) => { // Verify level directory name assert.strictEqual(true, /^[0-9]+$/.test(level)); - fs.readdirSync(path.join(directory, level)).forEach(function (tile) { + fs.readdirSync(path.join(directory, level)).forEach((tile) => { // Verify tile file name assert.strictEqual(true, /^[0-9]+_[0-9]+\.jpeg$/.test(tile)); tiles.push(path.join(directory, level, tile)); }); }); // Verify each tile is <= expectedSize - Promise.all(tiles.map(function (tile) { - return sharp(tile) + Promise.all(tiles.map((tile) => sharp(tile) .metadata() - .then(function (metadata) { + .then((metadata) => { assert.strictEqual('jpeg', metadata.format); assert.strictEqual('srgb', metadata.space); assert.strictEqual(3, metadata.channels); @@ -42,20 +41,19 @@ const assertDeepZoomTiles = function (directory, expectedSize, expectedLevels, d assert.strictEqual(false, metadata.hasAlpha); assert.strictEqual(true, metadata.width <= expectedSize); assert.strictEqual(true, metadata.height <= expectedSize); - }); - })) + }))) .then(() => done()) .catch(done); }; -const assertZoomifyTiles = function (directory, expectedLevels, done) { - fs.stat(path.join(directory, 'ImageProperties.xml'), function (err, stat) { +const assertZoomifyTiles = (directory, expectedLevels, done) => { + fs.stat(path.join(directory, 'ImageProperties.xml'), (err, stat) => { if (err) throw err; assert.ok(stat.isFile()); assert.ok(stat.size > 0); let maxTileLevel = -1; - fs.readdirSync(path.join(directory, 'TileGroup0')).forEach(function (tile) { + fs.readdirSync(path.join(directory, 'TileGroup0')).forEach((tile) => { // Verify tile file name assert.ok(/^[0-9]+-[0-9]+-[0-9]+\.jpg$/.test(tile)); const level = Number(tile.split('-')[0]); @@ -68,24 +66,24 @@ const assertZoomifyTiles = function (directory, expectedLevels, done) { }); }; -const assertGoogleTiles = function (directory, expectedLevels, done) { +const assertGoogleTiles = (directory, expectedLevels, done) => { // Get levels 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'), (err, stat) => { if (err) throw err; assert.ok(stat.isFile()); assert.ok(stat.size > 0); // Basic check to confirm lowest and highest level tiles exist - fs.stat(path.join(directory, '0', '0', '0.jpg'), function (err, stat) { + fs.stat(path.join(directory, '0', '0', '0.jpg'), (err, stat) => { if (err) throw err; assert.strictEqual(true, stat.isFile()); assert.strictEqual(true, stat.size > 0); - fs.stat(path.join(directory, (expectedLevels - 1).toString(), '0', '0.jpg'), function (err, stat) { + fs.stat(path.join(directory, (expectedLevels - 1).toString(), '0', '0.jpg'), (err, stat) => { if (err) throw err; assert.strictEqual(true, stat.isFile()); assert.strictEqual(true, stat.size > 0); @@ -96,7 +94,7 @@ const assertGoogleTiles = function (directory, expectedLevels, done) { }; // Verifies tiles at specified level in a given output directory are > size+overlap -const assertTileOverlap = function (directory, tileSize, done) { +const assertTileOverlap = (directory, tileSize, done) => { // Get sorted levels const dirents = fs.readdirSync(directory, { withFileTypes: true }); const levels = dirents.filter(dirent => dirent.isDirectory()).map(dirent => dirent.name).sort((a, b) => a - b); @@ -107,7 +105,7 @@ const assertTileOverlap = function (directory, tileSize, done) { // Select a tile from the approximate center of the image const squareTile = path.join(directory, highestLevel, tiles[Math.floor(tiles.length / 2)]); - sharp(squareTile).metadata(function (err, metadata) { + sharp(squareTile).metadata((err, metadata) => { if (err) { throw err; } else { @@ -119,10 +117,10 @@ const assertTileOverlap = function (directory, tileSize, done) { }); }; -describe('Tile', function () { - it('Valid size values pass', function () { - [1, 8192].forEach(function (size) { - assert.doesNotThrow(function () { +describe('Tile', () => { + it('Valid size values pass', () => { + [1, 8192].forEach((size) => { + assert.doesNotThrow(() => { sharp().tile({ size }); @@ -130,9 +128,9 @@ describe('Tile', function () { }); }); - it('Invalid size values fail', function () { - ['zoinks', 1.1, -1, 0, 8193].forEach(function (size) { - assert.throws(function () { + it('Invalid size values fail', () => { + ['zoinks', 1.1, -1, 0, 8193].forEach((size) => { + assert.throws(() => { sharp().tile({ size }); @@ -140,9 +138,9 @@ describe('Tile', function () { }); }); - it('Valid overlap values pass', function () { - [0, 8192].forEach(function (overlap) { - assert.doesNotThrow(function () { + it('Valid overlap values pass', () => { + [0, 8192].forEach((overlap) => { + assert.doesNotThrow(() => { sharp().tile({ size: 8192, overlap @@ -151,9 +149,9 @@ describe('Tile', function () { }); }); - it('Invalid overlap values fail', function () { - ['zoinks', 1.1, -1, 8193].forEach(function (overlap) { - assert.throws(function () { + it('Invalid overlap values fail', () => { + ['zoinks', 1.1, -1, 8193].forEach((overlap) => { + assert.throws(() => { sharp().tile({ overlap }); @@ -161,9 +159,9 @@ describe('Tile', function () { }); }); - it('Valid container values pass', function () { - ['fs', 'zip'].forEach(function (container) { - assert.doesNotThrow(function () { + it('Valid container values pass', () => { + ['fs', 'zip'].forEach((container) => { + assert.doesNotThrow(() => { sharp().tile({ container }); @@ -171,9 +169,9 @@ describe('Tile', function () { }); }); - it('Invalid container values fail', function () { - ['zoinks', 1].forEach(function (container) { - assert.throws(function () { + it('Invalid container values fail', () => { + ['zoinks', 1].forEach((container) => { + assert.throws(() => { sharp().tile({ container }); @@ -181,9 +179,9 @@ describe('Tile', function () { }); }); - it('Valid layout values pass', function () { - ['dz', 'google', 'zoomify'].forEach(function (layout) { - assert.doesNotThrow(function () { + it('Valid layout values pass', () => { + ['dz', 'google', 'zoomify'].forEach((layout) => { + assert.doesNotThrow(() => { sharp().tile({ layout }); @@ -191,9 +189,9 @@ describe('Tile', function () { }); }); - it('Invalid layout values fail', function () { - ['zoinks', 1].forEach(function (layout) { - assert.throws(function () { + it('Invalid layout values fail', () => { + ['zoinks', 1].forEach((layout) => { + assert.throws(() => { sharp().tile({ layout }); @@ -201,30 +199,30 @@ describe('Tile', function () { }); }); - it('Valid formats pass', function () { - ['jpeg', 'png', 'webp'].forEach(function (format) { - assert.doesNotThrow(function () { + it('Valid formats pass', () => { + ['jpeg', 'png', 'webp'].forEach((format) => { + assert.doesNotThrow(() => { sharp().toFormat(format).tile(); }); }); }); - it('Invalid formats fail', function () { - ['tiff', 'raw'].forEach(function (format) { - assert.throws(function () { + it('Invalid formats fail', () => { + ['tiff', 'raw'].forEach((format) => { + assert.throws(() => { sharp().toFormat(format).tile(); }); }); }); - it('Valid depths pass', function () { - ['onepixel', 'onetile', 'one'].forEach(function (depth) { + it('Valid depths pass', () => { + ['onepixel', 'onetile', 'one'].forEach((depth) => { assert.doesNotThrow(() => sharp().tile({ depth })); }); }); - it('Invalid depths fail', function () { - ['depth', 1].forEach(function (depth) { + it('Invalid depths fail', () => { + ['depth', 1].forEach((depth) => { assert.throws( () => sharp().tile({ depth }), /Expected one of: onepixel, onetile, one for depth but received/ @@ -232,16 +230,16 @@ describe('Tile', function () { }); }); - it('Prevent larger overlap than default size', function () { - assert.throws(function () { + it('Prevent larger overlap than default size', () => { + assert.throws(() => { sharp().tile({ overlap: 257 }); }); }); - it('Prevent larger overlap than provided size', function () { - assert.throws(function () { + it('Prevent larger overlap than provided size', () => { + assert.throws(() => { sharp().tile({ size: 512, overlap: 513 @@ -249,9 +247,9 @@ describe('Tile', function () { }); }); - it('Valid rotation angle values pass', function () { - [90, 270, -90].forEach(function (angle) { - assert.doesNotThrow(function () { + it('Valid rotation angle values pass', () => { + [90, 270, -90].forEach((angle) => { + assert.doesNotThrow(() => { sharp().tile({ angle }); @@ -259,9 +257,9 @@ describe('Tile', function () { }); }); - it('Invalid rotation angle values fail', function () { - ['zoinks', 1.1, -1, 27].forEach(function (angle) { - assert.throws(function () { + it('Invalid rotation angle values fail', () => { + ['zoinks', 1.1, -1, 27].forEach((angle) => { + assert.throws(() => { sharp().tile({ angle }); @@ -269,9 +267,9 @@ describe('Tile', function () { }); }); - it('Valid skipBlanks threshold values pass', function () { - [-1, 0, 255, 65535].forEach(function (skipBlanksThreshold) { - assert.doesNotThrow(function () { + it('Valid skipBlanks threshold values pass', () => { + [-1, 0, 255, 65535].forEach((skipBlanksThreshold) => { + assert.doesNotThrow(() => { sharp().tile({ skipBlanks: skipBlanksThreshold }); @@ -279,9 +277,9 @@ describe('Tile', function () { }); }); - it('InvalidskipBlanks threshold values fail', function () { - ['zoinks', -2, 65536].forEach(function (skipBlanksThreshold) { - assert.throws(function () { + it('InvalidskipBlanks threshold values fail', () => { + ['zoinks', -2, 65536].forEach((skipBlanksThreshold) => { + assert.throws(() => { sharp().tile({ skipBlanks: skipBlanksThreshold }); @@ -289,42 +287,42 @@ describe('Tile', function () { }); }); - it('Valid center parameter value passes', function () { + it('Valid center parameter value passes', () => { assert.doesNotThrow( () => sharp().tile({ center: true }) ); }); - it('Invalid centre parameter value fails', function () { + it('Invalid centre parameter value fails', () => { assert.throws( () => sharp().tile({ centre: 'true' }), /Expected boolean for tileCentre but received true of type string/ ); }); - it('Valid id parameter value passes', function () { - assert.doesNotThrow(function () { + it('Valid id parameter value passes', () => { + assert.doesNotThrow(() => { sharp().tile({ id: 'test' }); }); }); - it('Invalid id parameter value fails', function () { - assert.throws(function () { + it('Invalid id parameter value fails', () => { + assert.throws(() => { sharp().tile({ id: true }); }); }); - it('Valid basename parameter value passes', function () { + it('Valid basename parameter value passes', () => { assert.doesNotThrow( () => sharp().tile({ basename: 'pass' }) ); }); - it('Invalid basename parameter value fails', function () { + it('Invalid basename parameter value fails', () => { assert.throws( () => sharp().tile({ basename: true }), /Expected string for basename but received/ @@ -332,11 +330,11 @@ describe('Tile', function () { }); if (sharp.format.dz.output.file) { - it('Deep Zoom layout', function (_t, done) { + it('Deep Zoom layout', (_t, done) => { const directory = fixtures.path('output.dzi_files'); - fs.rm(directory, { recursive: true }, function () { + fs.rm(directory, { recursive: true }, () => { sharp(fixtures.inputJpg) - .toFile(fixtures.path('output.dzi'), function (err, info) { + .toFile(fixtures.path('output.dzi'), (err, info) => { if (err) throw err; assert.strictEqual('dz', info.format); assert.strictEqual(2725, info.width); @@ -348,37 +346,37 @@ describe('Tile', function () { }); }); - it('Deep Zoom layout with custom size+overlap', function (_t, done) { + it('Deep Zoom layout with custom size+overlap', (_t, done) => { const directory = fixtures.path('output.512.dzi_files'); - fs.rm(directory, { recursive: true }, function () { + fs.rm(directory, { recursive: true }, () => { sharp(fixtures.inputJpg) .tile({ size: 512, overlap: 16 }) - .toFile(fixtures.path('output.512.dzi'), function (err, info) { + .toFile(fixtures.path('output.512.dzi'), (err, info) => { if (err) throw err; assert.strictEqual('dz', info.format); assert.strictEqual(2725, info.width); assert.strictEqual(2225, info.height); assert.strictEqual(3, info.channels); assert.strictEqual('undefined', typeof info.size); - assertDeepZoomTiles(directory, 512 + (2 * 16), 13, function () { + assertDeepZoomTiles(directory, 512 + (2 * 16), 13, () => { assertTileOverlap(directory, 512, done); }); }); }); }); - it('Deep Zoom layout with custom size+angle', function (_t, done) { + it('Deep Zoom layout with custom size+angle', (_t, done) => { const directory = fixtures.path('output.512_90.dzi_files'); - fs.rm(directory, { recursive: true }, function () { + fs.rm(directory, { recursive: true }, () => { sharp(fixtures.inputJpg) .tile({ size: 512, angle: 90 }) - .toFile(fixtures.path('output.512_90.dzi'), function (err, info) { + .toFile(fixtures.path('output.512_90.dzi'), (err, info) => { if (err) throw err; assert.strictEqual('dz', info.format); assert.strictEqual(2725, info.width); @@ -392,7 +390,7 @@ describe('Tile', function () { // expected are w=512 and h=170 for the 0_1.jpeg. // if a 0 angle is supplied to the .tile function // the expected values are w=170 and h=512 for the 1_0.jpeg - sharp(tile).metadata(function (err, metadata) { + sharp(tile).metadata((err, metadata) => { if (err) { throw err; } else { @@ -404,15 +402,15 @@ describe('Tile', function () { }); }); - it('Deep Zoom layout with depth of one', function (_t, done) { + it('Deep Zoom layout with depth of one', (_t, done) => { const directory = fixtures.path('output.512_depth_one.dzi_files'); - fs.rm(directory, { recursive: true }, function () { + fs.rm(directory, { recursive: true }, () => { sharp(fixtures.inputJpg) .tile({ size: 512, depth: 'one' }) - .toFile(fixtures.path('output.512_depth_one.dzi'), function (err) { + .toFile(fixtures.path('output.512_depth_one.dzi'), (err) => { if (err) throw err; // Verify only one depth generated assertDeepZoomTiles(directory, 512, 1, done); @@ -420,15 +418,15 @@ describe('Tile', function () { }); }); - it('Deep Zoom layout with depth of onepixel', function (_t, done) { + it('Deep Zoom layout with depth of onepixel', (_t, done) => { const directory = fixtures.path('output.512_depth_onepixel.dzi_files'); - fs.rm(directory, { recursive: true }, function () { + fs.rm(directory, { recursive: true }, () => { sharp(fixtures.inputJpg) .tile({ size: 512, depth: 'onepixel' }) - .toFile(fixtures.path('output.512_depth_onepixel.dzi'), function (err) { + .toFile(fixtures.path('output.512_depth_onepixel.dzi'), (err) => { if (err) throw err; // Verify only one depth generated assertDeepZoomTiles(directory, 512, 13, done); @@ -436,15 +434,15 @@ describe('Tile', function () { }); }); - it('Deep Zoom layout with depth of onetile', function (_t, done) { + it('Deep Zoom layout with depth of onetile', (_t, done) => { const directory = fixtures.path('output.256_depth_onetile.dzi_files'); - fs.rm(directory, { recursive: true }, function () { + fs.rm(directory, { recursive: true }, () => { sharp(fixtures.inputJpg) .tile({ size: 256, depth: 'onetile' }) - .toFile(fixtures.path('output.256_depth_onetile.dzi'), function (err) { + .toFile(fixtures.path('output.256_depth_onetile.dzi'), (err) => { if (err) throw err; // Verify only one depth generated assertDeepZoomTiles(directory, 256, 5, done); @@ -452,15 +450,15 @@ describe('Tile', function () { }); }); - it('Deep Zoom layout with skipBlanks', function (_t, done) { + it('Deep Zoom layout with skipBlanks', (_t, done) => { const directory = fixtures.path('output.256_skip_blanks.dzi_files'); - fs.rm(directory, { recursive: true }, function () { + fs.rm(directory, { recursive: true }, () => { sharp(fixtures.inputJpgOverlayLayer2) .tile({ size: 256, skipBlanks: 0 }) - .toFile(fixtures.path('output.256_skip_blanks.dzi'), function (err) { + .toFile(fixtures.path('output.256_skip_blanks.dzi'), (err) => { if (err) throw err; // assert them 0_0.jpeg doesn't exist because it's a white tile const whiteTilePath = path.join(directory, '11', '0_0.jpeg'); @@ -471,21 +469,21 @@ describe('Tile', function () { }); }); - it('Zoomify layout', function (_t, done) { + it('Zoomify layout', (_t, done) => { const directory = fixtures.path('output.zoomify.dzi'); - fs.rm(directory, { recursive: true }, function () { + fs.rm(directory, { recursive: true }, () => { sharp(fixtures.inputJpg) .tile({ layout: 'zoomify' }) - .toFile(fixtures.path('output.zoomify.dzi'), function (err, info) { + .toFile(fixtures.path('output.zoomify.dzi'), (err, info) => { if (err) throw err; assert.strictEqual('dz', info.format); assert.strictEqual(2725, info.width); assert.strictEqual(2225, info.height); assert.strictEqual(3, info.channels); assert.strictEqual(undefined, info.size); - fs.stat(path.join(directory, 'ImageProperties.xml'), function (err, stat) { + fs.stat(path.join(directory, 'ImageProperties.xml'), (err, stat) => { if (err) throw err; assert.strictEqual(true, stat.isFile()); assert.strictEqual(true, stat.size > 0); @@ -495,16 +493,16 @@ describe('Tile', function () { }); }); - it('Zoomify layout with depth one', function (_t, done) { + it('Zoomify layout with depth one', (_t, done) => { const directory = fixtures.path('output.zoomify.depth_one.dzi'); - fs.rm(directory, { recursive: true }, function () { + fs.rm(directory, { recursive: true }, () => { sharp(fixtures.inputJpg) .tile({ size: 256, layout: 'zoomify', depth: 'one' }) - .toFile(directory, function (err, info) { + .toFile(directory, (err, info) => { if (err) throw err; assert.strictEqual('dz', info.format); assert.strictEqual(2725, info.width); @@ -516,16 +514,16 @@ describe('Tile', function () { }); }); - it('Zoomify layout with depth onetile', function (_t, done) { + it('Zoomify layout with depth onetile', (_t, done) => { const directory = fixtures.path('output.zoomify.depth_onetile.dzi'); - fs.rm(directory, { recursive: true }, function () { + fs.rm(directory, { recursive: true }, () => { sharp(fixtures.inputJpg) .tile({ size: 256, layout: 'zoomify', depth: 'onetile' }) - .toFile(directory, function (err, info) { + .toFile(directory, (err, info) => { if (err) throw err; assert.strictEqual('dz', info.format); assert.strictEqual(2725, info.width); @@ -537,16 +535,16 @@ describe('Tile', function () { }); }); - it('Zoomify layout with depth onepixel', function (_t, done) { + it('Zoomify layout with depth onepixel', (_t, done) => { const directory = fixtures.path('output.zoomify.depth_onepixel.dzi'); - fs.rm(directory, { recursive: true }, function () { + fs.rm(directory, { recursive: true }, () => { sharp(fixtures.inputJpg) .tile({ size: 256, layout: 'zoomify', depth: 'onepixel' }) - .toFile(directory, function (err, info) { + .toFile(directory, (err, info) => { if (err) throw err; assert.strictEqual('dz', info.format); assert.strictEqual(2725, info.width); @@ -558,16 +556,16 @@ describe('Tile', function () { }); }); - it('Zoomify layout with skip blanks', function (_t, done) { + it('Zoomify layout with skip blanks', (_t, done) => { const directory = fixtures.path('output.zoomify.skipBlanks.dzi'); - fs.rm(directory, { recursive: true }, function () { + fs.rm(directory, { recursive: true }, () => { sharp(fixtures.inputJpgOverlayLayer2) .tile({ size: 256, layout: 'zoomify', skipBlanks: 0 }) - .toFile(directory, function (err, info) { + .toFile(directory, (err, info) => { if (err) throw err; // assert them 0_0.jpeg doesn't exist because it's a white tile const whiteTilePath = path.join(directory, 'TileGroup0', '2-0-0.jpg'); @@ -582,21 +580,21 @@ describe('Tile', function () { }); }); - it('Google layout', function (_t, done) { + it('Google layout', (_t, done) => { const directory = fixtures.path('output.google.dzi'); - fs.rm(directory, { recursive: true }, function () { + fs.rm(directory, { recursive: true }, () => { sharp(fixtures.inputJpg) .tile({ layout: 'google' }) - .toFile(directory, function (err, info) { + .toFile(directory, (err, info) => { if (err) throw err; assert.strictEqual('dz', info.format); assert.strictEqual(2725, info.width); assert.strictEqual(2225, info.height); assert.strictEqual(3, info.channels); assert.strictEqual(undefined, info.size); - fs.stat(path.join(directory, '0', '0', '0.jpg'), function (err, stat) { + fs.stat(path.join(directory, '0', '0', '0.jpg'), (err, stat) => { if (err) throw err; assert.strictEqual(true, stat.isFile()); assert.strictEqual(true, stat.size > 0); @@ -606,9 +604,9 @@ describe('Tile', function () { }); }); - it('Google layout with jpeg format', function (_t, done) { + it('Google layout with jpeg format', (_t, done) => { const directory = fixtures.path('output.jpg.google.dzi'); - fs.rm(directory, { recursive: true }, function () { + fs.rm(directory, { recursive: true }, () => { sharp(fixtures.inputJpg) .jpeg({ quality: 1 @@ -616,7 +614,7 @@ describe('Tile', function () { .tile({ layout: 'google' }) - .toFile(directory, function (err, info) { + .toFile(directory, (err, info) => { if (err) throw err; assert.strictEqual('dz', info.format); assert.strictEqual(2725, info.width); @@ -624,7 +622,7 @@ describe('Tile', function () { assert.strictEqual(3, info.channels); assert.strictEqual(undefined, info.size); const sample = path.join(directory, '0', '0', '0.jpg'); - sharp(sample).metadata(function (err, metadata) { + sharp(sample).metadata((err, metadata) => { if (err) throw err; assert.strictEqual('jpeg', metadata.format); assert.strictEqual('srgb', metadata.space); @@ -633,7 +631,7 @@ describe('Tile', function () { assert.strictEqual(false, metadata.hasAlpha); assert.strictEqual(256, metadata.width); assert.strictEqual(256, metadata.height); - fs.stat(sample, function (err, stat) { + fs.stat(sample, (err, stat) => { if (err) throw err; assert.strictEqual(true, stat.size < 2000); done(); @@ -643,9 +641,9 @@ describe('Tile', function () { }); }); - it('Google layout with png format', function (_t, done) { + it('Google layout with png format', (_t, done) => { const directory = fixtures.path('output.png.google.dzi'); - fs.rm(directory, { recursive: true }, function () { + fs.rm(directory, { recursive: true }, () => { sharp(fixtures.inputJpg) .png({ compressionLevel: 0 @@ -653,7 +651,7 @@ describe('Tile', function () { .tile({ layout: 'google' }) - .toFile(directory, function (err, info) { + .toFile(directory, (err, info) => { if (err) throw err; assert.strictEqual('dz', info.format); assert.strictEqual(2725, info.width); @@ -661,7 +659,7 @@ describe('Tile', function () { assert.strictEqual(3, info.channels); assert.strictEqual(undefined, info.size); const sample = path.join(directory, '0', '0', '0.png'); - sharp(sample).metadata(function (err, metadata) { + sharp(sample).metadata((err, metadata) => { if (err) throw err; assert.strictEqual('png', metadata.format); assert.strictEqual('srgb', metadata.space); @@ -670,7 +668,7 @@ describe('Tile', function () { assert.strictEqual(false, metadata.hasAlpha); assert.strictEqual(256, metadata.width); assert.strictEqual(256, metadata.height); - fs.stat(sample, function (err, stat) { + fs.stat(sample, (err, stat) => { if (err) throw err; assert.strictEqual(true, stat.size > 44000); done(); @@ -680,9 +678,9 @@ describe('Tile', function () { }); }); - it('Google layout with webp format', function (_t, done) { + it('Google layout with webp format', (_t, done) => { const directory = fixtures.path('output.webp.google.dzi'); - fs.rm(directory, { recursive: true }, function () { + fs.rm(directory, { recursive: true }, () => { sharp(fixtures.inputJpg) .webp({ quality: 1, @@ -691,7 +689,7 @@ describe('Tile', function () { .tile({ layout: 'google' }) - .toFile(directory, function (err, info) { + .toFile(directory, (err, info) => { if (err) throw err; assert.strictEqual('dz', info.format); assert.strictEqual(2725, info.width); @@ -699,7 +697,7 @@ describe('Tile', function () { assert.strictEqual(3, info.channels); assert.strictEqual(undefined, info.size); const sample = path.join(directory, '0', '0', '0.webp'); - sharp(sample).metadata(function (err, metadata) { + sharp(sample).metadata((err, metadata) => { if (err) throw err; assert.strictEqual('webp', metadata.format); assert.strictEqual('srgb', metadata.space); @@ -708,7 +706,7 @@ describe('Tile', function () { assert.strictEqual(false, metadata.hasAlpha); assert.strictEqual(256, metadata.width); assert.strictEqual(256, metadata.height); - fs.stat(sample, function (err, stat) { + fs.stat(sample, (err, stat) => { if (err) throw err; assert.strictEqual(true, stat.size < 2000); done(); @@ -718,16 +716,16 @@ describe('Tile', function () { }); }); - it('Google layout with depth one', function (_t, done) { + it('Google layout with depth one', (_t, done) => { const directory = fixtures.path('output.google_depth_one.dzi'); - fs.rm(directory, { recursive: true }, function () { + fs.rm(directory, { recursive: true }, () => { sharp(fixtures.inputJpg) .tile({ layout: 'google', depth: 'one', size: 256 }) - .toFile(directory, function (err, info) { + .toFile(directory, (err, info) => { if (err) throw err; assert.strictEqual('dz', info.format); assert.strictEqual(2725, info.width); @@ -739,16 +737,16 @@ describe('Tile', function () { }); }); - it('Google layout with depth onetile', function (_t, done) { + it('Google layout with depth onetile', (_t, done) => { const directory = fixtures.path('output.google_depth_onetile.dzi'); - fs.rm(directory, { recursive: true }, function () { + fs.rm(directory, { recursive: true }, () => { sharp(fixtures.inputJpg) .tile({ layout: 'google', depth: 'onetile', size: 256 }) - .toFile(directory, function (err, info) { + .toFile(directory, (err, info) => { if (err) throw err; assert.strictEqual('dz', info.format); assert.strictEqual(2725, info.width); @@ -760,15 +758,15 @@ describe('Tile', function () { }); }); - it('Google layout with default skip Blanks', function (_t, done) { + it('Google layout with default skip Blanks', (_t, done) => { const directory = fixtures.path('output.google_depth_skipBlanks.dzi'); - fs.rm(directory, { recursive: true }, function () { + fs.rm(directory, { recursive: true }, () => { sharp(fixtures.inputPng) .tile({ layout: 'google', size: 256 }) - .toFile(directory, function (err, info) { + .toFile(directory, (err, info) => { if (err) throw err; const whiteTilePath = path.join(directory, '4', '8', '0.jpg'); @@ -784,15 +782,15 @@ describe('Tile', function () { }); }); - it('Google layout with center image in tile', function (_t, done) { + it('Google layout with center image in tile', (_t, done) => { const directory = fixtures.path('output.google_center.dzi'); - fs.rm(directory, { recursive: true }, function () { + fs.rm(directory, { recursive: true }, () => { sharp(fixtures.inputJpg) .tile({ center: true, layout: 'google' }) - .toFile(directory, function (err, info) { + .toFile(directory, (err, info) => { if (err) throw err; assert.strictEqual('dz', info.format); assert.strictEqual(2725, info.width); @@ -804,15 +802,15 @@ describe('Tile', function () { }); }); - it('Google layout with center image in tile centre', function (_t, done) { + it('Google layout with center image in tile centre', (_t, done) => { const directory = fixtures.path('output.google_center.dzi'); - fs.rm(directory, { recursive: true }, function () { + fs.rm(directory, { recursive: true }, () => { sharp(fixtures.inputJpg) .tile({ centre: true, layout: 'google' }) - .toFile(directory, function (err, info) { + .toFile(directory, (err, info) => { if (err) throw err; assert.strictEqual('dz', info.format); assert.strictEqual(2725, info.width); @@ -824,17 +822,17 @@ describe('Tile', function () { }); }); - it('IIIFv2 layout', function (_t, done) { + it('IIIFv2 layout', (_t, done) => { const name = 'output.iiif.info'; const directory = fixtures.path(name); - fs.rm(directory, { recursive: true }, function () { + fs.rm(directory, { recursive: true }, () => { const id = 'https://sharp.test.com/iiif'; sharp(fixtures.inputJpg) .tile({ layout: 'iiif', id }) - .toFile(directory, function (err, info) { + .toFile(directory, (err, info) => { if (err) throw err; assert.strictEqual('dz', info.format); assert.strictEqual(2725, info.width); @@ -844,7 +842,7 @@ describe('Tile', function () { const infoJson = require(path.join(directory, 'info.json')); assert.strictEqual('http://iiif.io/api/image/2/context.json', infoJson['@context']); assert.strictEqual(`${id}/${name}`, infoJson['@id']); - fs.stat(path.join(directory, '0,0,256,256', '256,', '0', 'default.jpg'), function (err, stat) { + fs.stat(path.join(directory, '0,0,256,256', '256,', '0', 'default.jpg'), (err, stat) => { if (err) throw err; assert.strictEqual(true, stat.isFile()); assert.strictEqual(true, stat.size > 0); @@ -854,17 +852,17 @@ describe('Tile', function () { }); }); - it('IIIFv3 layout', function (_t, done) { + it('IIIFv3 layout', (_t, done) => { const name = 'output.iiif3.info'; const directory = fixtures.path(name); - fs.rm(directory, { recursive: true }, function () { + fs.rm(directory, { recursive: true }, () => { const id = 'https://sharp.test.com/iiif3'; sharp(fixtures.inputJpg) .tile({ layout: 'iiif3', id }) - .toFile(directory, function (err, info) { + .toFile(directory, (err, info) => { if (err) throw err; assert.strictEqual('dz', info.format); assert.strictEqual(2725, info.width); @@ -875,7 +873,7 @@ describe('Tile', function () { assert.strictEqual('http://iiif.io/api/image/3/context.json', infoJson['@context']); assert.strictEqual('ImageService3', infoJson.type); assert.strictEqual(`${id}/${name}`, infoJson.id); - fs.stat(path.join(directory, '0,0,256,256', '256,256', '0', 'default.jpg'), function (err, stat) { + fs.stat(path.join(directory, '0,0,256,256', '256,256', '0', 'default.jpg'), (err, stat) => { if (err) throw err; assert.strictEqual(true, stat.isFile()); assert.strictEqual(true, stat.size > 0); @@ -885,20 +883,20 @@ describe('Tile', function () { }); }); - it('Write to ZIP container using file extension', function (_t, done) { + it('Write to ZIP container using file extension', (_t, done) => { const container = fixtures.path('output.dz.container.zip'); const extractTo = fixtures.path('output.dz.container'); const directory = path.join(extractTo, 'output.dz.container_files'); - fs.rm(directory, { recursive: true }, function () { + fs.rm(directory, { recursive: true }, () => { sharp(fixtures.inputJpg) - .toFile(container, function (err, info) { + .toFile(container, (err, info) => { if (err) throw err; assert.strictEqual('dz', info.format); assert.strictEqual(2725, info.width); assert.strictEqual(2225, info.height); assert.strictEqual(3, info.channels); assert.strictEqual('number', typeof info.size); - fs.stat(container, function (err, stat) { + fs.stat(container, (err, stat) => { if (err) throw err; assert.strictEqual(true, stat.isFile()); assert.strictEqual(true, stat.size > 0); @@ -912,16 +910,16 @@ describe('Tile', function () { }); }); - it('Write to ZIP container using container tile option', function (_t, done) { + it('Write to ZIP container using container tile option', (_t, done) => { const container = fixtures.path('output.dz.containeropt.zip'); const extractTo = fixtures.path('output.dz.containeropt'); const directory = path.join(extractTo, 'output.dz.containeropt_files'); - fs.rm(directory, { recursive: true }, function () { + fs.rm(directory, { recursive: true }, () => { sharp(fixtures.inputJpg) .tile({ container: 'zip' }) - .toFile(container, function (err, info) { + .toFile(container, (err, info) => { // Vips overrides .dzi extension to .zip used by container var below if (err) throw err; assert.strictEqual('dz', info.format); @@ -929,7 +927,7 @@ describe('Tile', function () { assert.strictEqual(2225, info.height); assert.strictEqual(3, info.channels); assert.strictEqual('number', typeof info.size); - fs.stat(container, function (err, stat) { + fs.stat(container, (err, stat) => { if (err) throw err; assert.strictEqual(true, stat.isFile()); assert.strictEqual(true, stat.size > 0); @@ -943,14 +941,14 @@ describe('Tile', function () { }); }); - it('Write ZIP container to Buffer', function (_t, done) { + it('Write ZIP container to Buffer', (_t, done) => { const container = fixtures.path('output.dz.tiles.zip'); const extractTo = fixtures.path('output.dz.tiles'); const directory = path.join(extractTo, 'output.dz.tiles_files'); - fs.rm(directory, { recursive: true }, function () { + fs.rm(directory, { recursive: true }, () => { sharp(fixtures.inputJpg) .tile({ basename: 'output.dz.tiles' }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('dz', info.format); assert.strictEqual(2725, info.width); @@ -958,7 +956,7 @@ describe('Tile', function () { assert.strictEqual(3, info.channels); assert.strictEqual('number', typeof info.size); fs.writeFileSync(container, data); - fs.stat(container, function (err, stat) { + fs.stat(container, (err, stat) => { if (err) throw err; assert.strictEqual(true, stat.isFile()); assert.strictEqual(true, stat.size > 0); diff --git a/test/unit/timeout.js b/test/unit/timeout.js index d44179aa2..77aad8fa6 100644 --- a/test/unit/timeout.js +++ b/test/unit/timeout.js @@ -9,7 +9,7 @@ const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); -describe('Timeout', function () { +describe('Timeout', () => { it('Will timeout after 1s when performing slow blur operation', () => assert.rejects( () => sharp(fixtures.inputJpg) .blur(200) diff --git a/test/unit/tint.js b/test/unit/tint.js index f7a168a78..db3f4984f 100644 --- a/test/unit/tint.js +++ b/test/unit/tint.js @@ -12,13 +12,13 @@ const fixtures = require('../fixtures'); // Allow for small rounding differences between platforms const maxDistance = 6; -describe('Tint', function () { - it('tints rgb image red', function (_t, done) { +describe('Tint', () => { + it('tints rgb image red', (_t, done) => { const output = fixtures.path('output.tint-red.jpg'); sharp(fixtures.inputJpg) .resize(320, 240) .tint('#FF0000') - .toFile(output, function (err, info) { + .toFile(output, (err, info) => { if (err) throw err; assert.strictEqual(true, info.size > 0); fixtures.assertMaxColourDistance(output, fixtures.expected('tint-red.jpg'), maxDistance); @@ -26,12 +26,12 @@ describe('Tint', function () { }); }); - it('tints rgb image green', function (_t, done) { + it('tints rgb image green', (_t, done) => { const output = fixtures.path('output.tint-green.jpg'); sharp(fixtures.inputJpg) .resize(320, 240) .tint('#00FF00') - .toFile(output, function (err, info) { + .toFile(output, (err, info) => { if (err) throw err; assert.strictEqual(true, info.size > 0); fixtures.assertMaxColourDistance(output, fixtures.expected('tint-green.jpg'), maxDistance); @@ -39,12 +39,12 @@ describe('Tint', function () { }); }); - it('tints rgb image blue', function (_t, done) { + it('tints rgb image blue', (_t, done) => { const output = fixtures.path('output.tint-blue.jpg'); sharp(fixtures.inputJpg) .resize(320, 240) .tint('#0000FF') - .toFile(output, function (err, info) { + .toFile(output, (err, info) => { if (err) throw err; assert.strictEqual(true, info.size > 0); fixtures.assertMaxColourDistance(output, fixtures.expected('tint-blue.jpg'), maxDistance); @@ -52,12 +52,12 @@ describe('Tint', function () { }); }); - it('tints rgb image with sepia tone', function (_t, done) { + it('tints rgb image with sepia tone', (_t, done) => { const output = fixtures.path('output.tint-sepia-hex.jpg'); sharp(fixtures.inputJpg) .resize(320, 240) .tint('#704214') - .toFile(output, function (err, info) { + .toFile(output, (err, info) => { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); @@ -66,12 +66,12 @@ describe('Tint', function () { }); }); - it('tints rgb image with sepia tone with rgb colour', function (_t, done) { + it('tints rgb image with sepia tone with rgb colour', (_t, done) => { const output = fixtures.path('output.tint-sepia-rgb.jpg'); sharp(fixtures.inputJpg) .resize(320, 240) .tint([112, 66, 20]) - .toFile(output, function (err, info) { + .toFile(output, (err, info) => { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); @@ -80,12 +80,12 @@ describe('Tint', function () { }); }); - it('tints rgb image with alpha channel', function (_t, done) { + it('tints rgb image with alpha channel', (_t, done) => { const output = fixtures.path('output.tint-alpha.png'); sharp(fixtures.inputPngRGBWithAlpha) .resize(320, 240) .tint('#704214') - .toFile(output, function (err, info) { + .toFile(output, (err, info) => { if (err) throw err; assert.strictEqual(320, info.width); assert.strictEqual(240, info.height); @@ -94,12 +94,12 @@ describe('Tint', function () { }); }); - it('tints cmyk image red', function (_t, done) { + it('tints cmyk image red', (_t, done) => { const output = fixtures.path('output.tint-cmyk.jpg'); sharp(fixtures.inputJpgWithCmykProfile) .resize(320, 240) .tint('#FF0000') - .toFile(output, function (err, info) { + .toFile(output, (err, info) => { if (err) throw err; assert.strictEqual(true, info.size > 0); fixtures.assertMaxColourDistance(output, fixtures.expected('tint-cmyk.jpg'), maxDistance); diff --git a/test/unit/trim.js b/test/unit/trim.js index 5df2aabcb..99b14a8d9 100644 --- a/test/unit/trim.js +++ b/test/unit/trim.js @@ -10,8 +10,8 @@ const sharp = require('../../'); const inRange = require('../../lib/is').inRange; const fixtures = require('../fixtures'); -describe('Trim borders', function () { - it('Skip shrink-on-load', function (_t, done) { +describe('Trim borders', () => { + it('Skip shrink-on-load', (_t, done) => { const expected = fixtures.expected('alpha-layer-2-trim-resize.jpg'); sharp(fixtures.inputJpgOverlayLayer2) .trim() @@ -19,7 +19,7 @@ describe('Trim borders', function () { width: 300, fastShrinkOnLoad: false }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual('jpeg', info.format); assert.strictEqual(300, info.width); @@ -44,13 +44,13 @@ describe('Trim borders', function () { }) ); - it('16-bit PNG with alpha channel', function (_t, done) { + it('16-bit PNG with alpha channel', (_t, done) => { sharp(fixtures.inputPngWithTransparency16bit) .resize(32, 32) .trim({ threshold: 20 }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('png', info.format); @@ -63,7 +63,7 @@ describe('Trim borders', function () { }); }); - it('Attempt to trim 2x2 pixel image fails', function (_t, done) { + it('Attempt to trim 2x2 pixel image fails', (_t, done) => { sharp({ create: { width: 2, @@ -211,7 +211,7 @@ describe('Trim borders', function () { assert.strictEqual(info.trimOffsetTop, -552); }); - describe('Invalid parameters', function () { + describe('Invalid parameters', () => { Object.entries({ 'Invalid string': 'fail', 'Invalid background option': { @@ -223,16 +223,16 @@ describe('Trim borders', function () { 'Invalid lineArt': { lineArt: 'fail' } - }).forEach(function ([description, parameter]) { - it(description, function () { - assert.throws(function () { + }).forEach(([description, parameter]) => { + it(description, () => { + assert.throws(() => { sharp().trim(parameter); }); }); }); }); - describe('Specific background colour', function () { + describe('Specific background colour', () => { it('Doesn\'t trim at all', async () => { const { info } = await sharp(fixtures.inputPngTrimSpecificColour) .trim({ diff --git a/test/unit/unflatten.js b/test/unit/unflatten.js index 7a4423517..1db60af33 100644 --- a/test/unit/unflatten.js +++ b/test/unit/unflatten.js @@ -7,24 +7,24 @@ const { describe, it } = require('node:test'); const sharp = require('../../'); const fixtures = require('../fixtures'); -describe('Unflatten', function () { - it('unflatten white background', function (_t, done) { +describe('Unflatten', () => { + it('unflatten white background', (_t, done) => { sharp(fixtures.inputPng).unflatten() - .toBuffer(function (err, data) { + .toBuffer((err, data) => { if (err) throw err; fixtures.assertSimilar(fixtures.expected('unflatten-white-transparent.png'), data, { threshold: 0 }, done); }); }); - it('unflatten transparent image', function (_t, done) { + it('unflatten transparent image', (_t, done) => { sharp(fixtures.inputPngTrimSpecificColourIncludeAlpha).unflatten() - .toBuffer(function (err, data) { + .toBuffer((err, data) => { if (err) throw err; fixtures.assertSimilar(fixtures.expected('unflatten-flag-white-transparent.png'), data, { threshold: 0 }, done); }); }); - it('unflatten using threshold', function (_t, done) { + it('unflatten using threshold', (_t, done) => { sharp(fixtures.inputPngPalette).unflatten().threshold(128, { grayscale: false }) - .toBuffer(function (err, data) { + .toBuffer((err, data) => { if (err) throw err; fixtures.assertSimilar(fixtures.expected('unflatten-swiss.png'), data, { threshold: 1 }, done); }); diff --git a/test/unit/util.js b/test/unit/util.js index 16c04a63c..e3676db6d 100644 --- a/test/unit/util.js +++ b/test/unit/util.js @@ -8,9 +8,9 @@ const assert = require('node:assert'); const semver = require('semver'); const sharp = require('../../'); -describe('Utilities', function () { - describe('Cache', function () { - it('Can be disabled', function (_t, done) { +describe('Utilities', () => { + describe('Cache', () => { + it('Can be disabled', (_t, done) => { const check = setInterval(() => { const cache = sharp.cache(false); const empty = @@ -26,13 +26,13 @@ describe('Utilities', function () { } }, 2000); }); - it('Can be enabled with defaults', function () { + it('Can be enabled with defaults', () => { const cache = sharp.cache(true); assert.strictEqual(cache.memory.max, 50); assert.strictEqual(cache.files.max, 20); assert.strictEqual(cache.items.max, 100); }); - it('Can be set to zero', function () { + it('Can be set to zero', () => { const cache = sharp.cache({ memory: 0, files: 0, @@ -42,7 +42,7 @@ describe('Utilities', function () { assert.strictEqual(cache.files.max, 0); assert.strictEqual(cache.items.max, 0); }); - it('Can be set to a maximum of 10MB, 100 files and 1000 items', function () { + it('Can be set to a maximum of 10MB, 100 files and 1000 items', () => { const cache = sharp.cache({ memory: 10, files: 100, @@ -52,7 +52,7 @@ describe('Utilities', function () { assert.strictEqual(cache.files.max, 100); assert.strictEqual(cache.items.max, 1000); }); - it('Ignores invalid values', function () { + it('Ignores invalid values', () => { sharp.cache(true); const cache = sharp.cache('spoons'); assert.strictEqual(cache.memory.max, 50); @@ -61,23 +61,23 @@ describe('Utilities', function () { }); }); - describe('Concurrency', function () { - it('Can be set to use 16 threads', function () { + describe('Concurrency', () => { + it('Can be set to use 16 threads', () => { sharp.concurrency(16); assert.strictEqual(16, sharp.concurrency()); }); - it('Can be reset to default', function () { + it('Can be reset to default', () => { sharp.concurrency(0); assert.strictEqual(true, sharp.concurrency() > 0); }); - it('Ignores invalid values', function () { + it('Ignores invalid values', () => { const defaultConcurrency = sharp.concurrency(); sharp.concurrency('spoons'); assert.strictEqual(defaultConcurrency, sharp.concurrency()); }); }); - describe('Counters', function () { + describe('Counters', () => { it('Have zero value at rest', (_t, done) => { queueMicrotask(() => { const counters = sharp.counters(); @@ -88,28 +88,28 @@ describe('Utilities', function () { }); }); - describe('SIMD', function () { - it('Can get current state', function () { + describe('SIMD', () => { + it('Can get current state', () => { const simd = sharp.simd(); assert.strictEqual(typeof simd, 'boolean'); }); - it('Can disable', function () { + it('Can disable', () => { const simd = sharp.simd(false); assert.strictEqual(simd, false); }); - it('Can attempt to enable', function () { + it('Can attempt to enable', () => { const simd = sharp.simd(true); assert.strictEqual(typeof simd, 'boolean'); }); }); - describe('Format', function () { - it('Contains expected attributes', function () { + describe('Format', () => { + it('Contains expected attributes', () => { assert.strictEqual('object', typeof sharp.format); - Object.keys(sharp.format).forEach(function (format) { + Object.keys(sharp.format).forEach((format) => { assert.strictEqual(true, 'id' in sharp.format[format]); assert.strictEqual(format, sharp.format[format].id); - ['input', 'output'].forEach(function (direction) { + ['input', 'output'].forEach((direction) => { assert.strictEqual(true, direction in sharp.format[format]); assert.strictEqual('object', typeof sharp.format[format][direction]); assert.strictEqual(true, [3, 4].includes(Object.keys(sharp.format[format][direction]).length)); @@ -122,30 +122,30 @@ describe('Utilities', function () { }); }); }); - it('Raw file=false, buffer=true, stream=true', function () { - ['input', 'output'].forEach(function (direction) { + it('Raw file=false, buffer=true, stream=true', () => { + ['input', 'output'].forEach((direction) => { assert.strictEqual(false, sharp.format.raw[direction].file); assert.strictEqual(true, sharp.format.raw[direction].buffer); assert.strictEqual(true, sharp.format.raw[direction].stream); }); }); - it('vips format supports filesystem only', function () { - ['input', 'output'].forEach(function (direction) { + it('vips format supports filesystem only', () => { + ['input', 'output'].forEach((direction) => { assert.strictEqual(true, sharp.format.vips[direction].file); assert.strictEqual(false, sharp.format.vips[direction].buffer); assert.strictEqual(false, sharp.format.vips[direction].stream); }); }); - it('input fileSuffix', function () { + it('input fileSuffix', () => { assert.deepStrictEqual(['.jpg', '.jpeg', '.jpe', '.jfif'], sharp.format.jpeg.input.fileSuffix); }); - it('output alias', function () { + it('output alias', () => { assert.deepStrictEqual(['jpe', 'jpg'], sharp.format.jpeg.output.alias); }); }); - describe('Versions', function () { - it('Contains expected attributes', function () { + describe('Versions', () => { + it('Contains expected attributes', () => { assert.strictEqual('object', typeof sharp.versions); assert(semver.valid(sharp.versions.vips)); assert(semver.valid(sharp.versions.sharp)); diff --git a/test/unit/webp.js b/test/unit/webp.js index b36c9a503..22d37a522 100644 --- a/test/unit/webp.js +++ b/test/unit/webp.js @@ -10,12 +10,12 @@ const assert = require('node:assert'); const sharp = require('../../'); const fixtures = require('../fixtures'); -describe('WebP', function () { - it('WebP output', function (_t, done) { +describe('WebP', () => { + it('WebP output', (_t, done) => { sharp(fixtures.inputJpg) .resize(320, 240) .toFormat(sharp.format.webp) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('webp', info.format); @@ -25,22 +25,22 @@ describe('WebP', function () { }); }); - it('Invalid WebP quality throws error', function () { - assert.throws(function () { + it('Invalid WebP quality throws error', () => { + assert.throws(() => { sharp().webp({ quality: 101 }); }); }); - it('Invalid WebP alpha quality throws error', function () { - assert.throws(function () { + it('Invalid WebP alpha quality throws error', () => { + assert.throws(() => { sharp().webp({ alphaQuality: 101 }); }); }); - it('should work for webp alpha quality', function (_t, done) { + it('should work for webp alpha quality', (_t, done) => { sharp(fixtures.inputPngAlphaPremultiplicationSmall) .webp({ alphaQuality: 80, effort: 0 }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('webp', info.format); @@ -48,10 +48,10 @@ describe('WebP', function () { }); }); - it('should work for webp lossless', function (_t, done) { + it('should work for webp lossless', (_t, done) => { sharp(fixtures.inputPngAlphaPremultiplicationSmall) .webp({ lossless: true, effort: 0 }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('webp', info.format); @@ -59,10 +59,10 @@ describe('WebP', function () { }); }); - it('should work for webp near-lossless', function (_t, done) { + it('should work for webp near-lossless', (_t, done) => { sharp(fixtures.inputPngAlphaPremultiplicationSmall) .webp({ nearLossless: true, quality: 50, effort: 0 }) - .toBuffer(function (err50, data50, info50) { + .toBuffer((err50, data50, info50) => { if (err50) throw err50; assert.strictEqual(true, data50.length > 0); assert.strictEqual('webp', info50.format); @@ -70,10 +70,10 @@ describe('WebP', function () { }); }); - it('should use near-lossless when both lossless and nearLossless are specified', function (_t, done) { + it('should use near-lossless when both lossless and nearLossless are specified', (_t, done) => { sharp(fixtures.inputPngAlphaPremultiplicationSmall) .webp({ nearLossless: true, quality: 50, lossless: true, effort: 0 }) - .toBuffer(function (err50, data50, info50) { + .toBuffer((err50, data50, info50) => { if (err50) throw err50; assert.strictEqual(true, data50.length > 0); assert.strictEqual('webp', info50.format); @@ -272,11 +272,11 @@ describe('WebP', function () { assert.deepStrictEqual(updated.delay, [120, 120, 90, 120, 120, 90, 120, 90, 30]); }); - it('should work with streams when only animated is set', function (_t, done) { + it('should work with streams when only animated is set', (_t, done) => { fs.createReadStream(fixtures.inputWebPAnimated) .pipe(sharp({ animated: true })) .webp({ lossless: true, effort: 0 }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('webp', info.format); @@ -284,11 +284,11 @@ describe('WebP', function () { }); }); - it('should work with streams when only pages is set', function (_t, done) { + it('should work with streams when only pages is set', (_t, done) => { fs.createReadStream(fixtures.inputWebPAnimated) .pipe(sharp({ pages: -1 })) .webp({ lossless: true, effort: 0 }) - .toBuffer(function (err, data, info) { + .toBuffer((err, data, info) => { if (err) throw err; assert.strictEqual(true, data.length > 0); assert.strictEqual('webp', info.format); From e1628d8ef5033dedde9ed1ddd4dd681e1fc30e1e Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Tue, 4 Nov 2025 15:06:49 +0000 Subject: [PATCH 105/115] Simplify ICC processing when retaining input profiles #4468 Takes advantage of libvips' improved ICC handling --- docs/src/content/docs/api-output.md | 10 +++++++++- docs/src/content/docs/changelog/v0.34.5.md | 3 +++ lib/output.js | 9 ++++++++- src/pipeline.cc | 14 +++----------- test/unit/metadata.js | 19 +++++++++++++++---- 5 files changed, 38 insertions(+), 17 deletions(-) diff --git a/docs/src/content/docs/api-output.md b/docs/src/content/docs/api-output.md index 8368e54dd..5acd2fadb 100644 --- a/docs/src/content/docs/api-output.md +++ b/docs/src/content/docs/api-output.md @@ -201,7 +201,7 @@ const dataWithMergedExif = await sharp(inputWithExif) Keep ICC profile from the input image in the output image. -For non-RGB output use [toColourspace](/api-colour/#tocolourspace). +When input and output colour spaces differ, use with [toColourspace](/api-colour/#tocolourspace) and optionally [pipelineColourspace](/api-colour/#pipelinecolourspace). **Since**: 0.33.0 @@ -211,6 +211,14 @@ const outputWithIccProfile = await sharp(inputWithIccProfile) .keepIccProfile() .toBuffer(); ``` +**Example** +```js +const cmykOutputWithIccProfile = await sharp(cmykInputWithIccProfile) + .pipelineColourspace('cmyk') + .toColourspace('cmyk') + .keepIccProfile() + .toBuffer(); +``` ## withIccProfile diff --git a/docs/src/content/docs/changelog/v0.34.5.md b/docs/src/content/docs/changelog/v0.34.5.md index 8cfca9c9b..df994024a 100644 --- a/docs/src/content/docs/changelog/v0.34.5.md +++ b/docs/src/content/docs/changelog/v0.34.5.md @@ -16,3 +16,6 @@ slug: changelog/v0.34.5 * Improve error messaging when only warnings issued. [#4465](https://github.com/lovell/sharp/issues/4465) + +* Simplify ICC processing when retaining input profiles. + [#4468](https://github.com/lovell/sharp/issues/4468) diff --git a/lib/output.js b/lib/output.js index dac7774ca..27a6ac470 100644 --- a/lib/output.js +++ b/lib/output.js @@ -256,7 +256,7 @@ function withExifMerge (exif) { /** * Keep ICC profile from the input image in the output image. * - * For non-RGB output use {@link /api-colour/#tocolourspace toColourspace}. + * When input and output colour spaces differ, use with {@link /api-colour/#tocolourspace toColourspace} and optionally {@link /api-colour/#pipelinecolourspace pipelineColourspace}. * * @since 0.33.0 * @@ -265,6 +265,13 @@ function withExifMerge (exif) { * .keepIccProfile() * .toBuffer(); * + * @example + * const cmykOutputWithIccProfile = await sharp(cmykInputWithIccProfile) + * .pipelineColourspace('cmyk') + * .toColourspace('cmyk') + * .keepIccProfile() + * .toBuffer(); + * * @returns {Sharp} */ function keepIccProfile () { diff --git a/src/pipeline.cc b/src/pipeline.cc index 5da169a15..23cad0787 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -797,20 +797,14 @@ class PipelineWorker : public Napi::AsyncWorker { image = sharp::EnsureAlpha(image, baton->ensureAlpha); } - // Convert image to sRGB, if not already + // Ensure output colour space if (sharp::Is16Bit(image.interpretation())) { image = image.cast(VIPS_FORMAT_USHORT); } if (image.interpretation() != baton->colourspace) { - // Convert colourspace, pass the current known interpretation so libvips doesn't have to guess image = image.colourspace(baton->colourspace, VImage::option()->set("source_space", image.interpretation())); - // Transform colours from embedded profile to output profile - if ((baton->keepMetadata & VIPS_FOREIGN_KEEP_ICC) && baton->colourspacePipeline != VIPS_INTERPRETATION_CMYK && - baton->withIccProfile.empty() && sharp::HasProfile(image)) { - image = image.icc_transform(processingProfile, VImage::option() - ->set("embedded", true) - ->set("depth", sharp::Is16Bit(image.interpretation()) ? 16 : 8) - ->set("intent", VIPS_INTENT_PERCEPTUAL)); + if (inputProfile.first && baton->withIccProfile.empty()) { + image = sharp::SetProfile(image, inputProfile); } } @@ -845,8 +839,6 @@ class PipelineWorker : public Napi::AsyncWorker { } catch(...) { sharp::VipsWarningCallback(nullptr, G_LOG_LEVEL_WARNING, "Invalid profile", nullptr); } - } else if (baton->keepMetadata & VIPS_FOREIGN_KEEP_ICC) { - image = sharp::SetProfile(image, inputProfile); } // Negate the colours in the image diff --git a/test/unit/metadata.js b/test/unit/metadata.js index 0e7b4747b..300380edd 100644 --- a/test/unit/metadata.js +++ b/test/unit/metadata.js @@ -651,16 +651,27 @@ describe('Image metadata', () => { assert.strictEqual(description, 'Generic RGB Profile'); }); - it('keep existing ICC profile, ignore colourspace conversion', async () => { - const data = await sharp(fixtures.inputJpgWithExif) + it('keep existing CMYK input profile for CMYK output', async () => { + const data = await sharp(fixtures.inputJpgWithCmykProfile) .keepIccProfile() .toColourspace('cmyk') .toBuffer(); const metadata = await sharp(data).metadata(); - assert.strictEqual(metadata.channels, 3); + assert.strictEqual(metadata.channels, 4); const { description } = icc.parse(metadata.icc); - assert.strictEqual(description, 'Generic RGB Profile'); + assert.strictEqual(description, 'U.S. Web Coated (SWOP) v2'); + }); + + it('transform with but discard existing RGB input profile for CMYK output', async () => { + const data = await sharp(fixtures.inputJpgWithExif) + .keepIccProfile() + .toColourspace('cmyk') + .toBuffer(); + + const metadata = await sharp(data).metadata(); + assert.strictEqual(metadata.channels, 4); + assert.strictEqual(metadata.icc, undefined); }); it('keep existing ICC profile, avoid colour transform', async () => { From 6c1e840098ea4a25d833518b30703d9b0af83d32 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Wed, 5 Nov 2025 15:30:52 +0000 Subject: [PATCH 106/115] Use structured binding for tuples where possible --- src/metadata.cc | 12 ++++++------ src/pipeline.cc | 27 +++++++++++---------------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/metadata.cc b/src/metadata.cc index 73e3f930b..2fde7bf6a 100644 --- a/src/metadata.cc +++ b/src/metadata.cc @@ -219,10 +219,10 @@ class MetadataWorker : public Napi::AsyncWorker { if (!baton->levels.empty()) { int i = 0; Napi::Array levels = Napi::Array::New(env, static_cast(baton->levels.size())); - for (std::pair const &l : baton->levels) { + for (const auto& [width, height] : baton->levels) { Napi::Object level = Napi::Object::New(env); - level.Set("width", l.first); - level.Set("height", l.second); + level.Set("width", width); + level.Set("height", height); levels.Set(i++, level); } info.Set("levels", levels); @@ -279,10 +279,10 @@ class MetadataWorker : public Napi::AsyncWorker { if (baton->comments.size() > 0) { int i = 0; Napi::Array comments = Napi::Array::New(env, baton->comments.size()); - for (auto &c : baton->comments) { + for (const auto& [keyword, text] : baton->comments) { Napi::Object comment = Napi::Object::New(env); - comment.Set("keyword", c.first); - comment.Set("text", c.second); + comment.Set("keyword", keyword); + comment.Set("text", text); comments.Set(i++, comment); } info.Set("comments", comments); diff --git a/src/pipeline.cc b/src/pipeline.cc index 23cad0787..5f0a3bb0e 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -455,12 +455,10 @@ class PipelineWorker : public Napi::AsyncWorker { std::tie(image, background) = sharp::ApplyAlpha(image, baton->resizeBackground, shouldPremultiplyAlpha); // Embed - int left; - int top; - std::tie(left, top) = sharp::CalculateEmbedPosition( + const auto& [left, top] = sharp::CalculateEmbedPosition( inputWidth, inputHeight, baton->width, baton->height, baton->position); - int width = std::max(inputWidth, baton->width); - int height = std::max(inputHeight, baton->height); + const int width = std::max(inputWidth, baton->width); + const int height = std::max(inputHeight, baton->height); image = nPages > 1 ? sharp::EmbedMultiPage(image, @@ -479,13 +477,10 @@ class PipelineWorker : public Napi::AsyncWorker { // Crop if (baton->position < 9) { // Gravity-based crop - int left; - int top; - - std::tie(left, top) = sharp::CalculateCrop( + const auto& [left, top] = sharp::CalculateCrop( inputWidth, inputHeight, baton->width, baton->height, baton->position); - int width = std::min(inputWidth, baton->width); - int height = std::min(inputHeight, baton->height); + const int width = std::min(inputWidth, baton->width); + const int height = std::min(inputHeight, baton->height); image = nPages > 1 ? sharp::CropMultiPage(image, @@ -803,7 +798,7 @@ class PipelineWorker : public Napi::AsyncWorker { } if (image.interpretation() != baton->colourspace) { image = image.colourspace(baton->colourspace, VImage::option()->set("source_space", image.interpretation())); - if (inputProfile.first && baton->withIccProfile.empty()) { + if (inputProfile.first != nullptr && baton->withIccProfile.empty()) { image = sharp::SetProfile(image, inputProfile); } } @@ -860,8 +855,8 @@ class PipelineWorker : public Napi::AsyncWorker { if (!baton->withExifMerge) { image = sharp::RemoveExif(image); } - for (const auto& s : baton->withExif) { - image.set(s.first.data(), s.second.data()); + for (const auto& [key, value] : baton->withExif) { + image.set(key.c_str(), value.c_str()); } } // XMP buffer @@ -1440,11 +1435,11 @@ class PipelineWorker : public Napi::AsyncWorker { std::string AssembleSuffixString(std::string extname, std::vector> options) { std::string argument; - for (auto const &option : options) { + for (const auto& [key, value] : options) { if (!argument.empty()) { argument += ","; } - argument += option.first + "=" + option.second; + argument += key + "=" + value; } return extname + "[" + argument + "]"; } From ef86a75560adb40605d3dfc85dc3656a0b88c413 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Wed, 5 Nov 2025 15:41:31 +0000 Subject: [PATCH 107/115] Prerelease v0.34.5-rc.0 --- biome.json | 2 +- npm/darwin-arm64/package.json | 2 +- npm/darwin-x64/package.json | 2 +- npm/linux-arm/package.json | 2 +- npm/linux-arm64/package.json | 2 +- npm/linux-ppc64/package.json | 2 +- npm/linux-riscv64/package.json | 2 +- npm/linux-s390x/package.json | 2 +- npm/linux-x64/package.json | 2 +- npm/linuxmusl-arm64/package.json | 2 +- npm/linuxmusl-x64/package.json | 2 +- npm/package.json | 2 +- npm/wasm32/package.json | 4 ++-- npm/win32-arm64/package.json | 2 +- npm/win32-ia32/package.json | 2 +- npm/win32-x64/package.json | 2 +- package.json | 36 ++++++++++++++++---------------- 17 files changed, 35 insertions(+), 35 deletions(-) diff --git a/biome.json b/biome.json index a89282fbb..7946049c8 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.3.3/schema.json", + "$schema": "https://biomejs.dev/schemas/2.3.4/schema.json", "vcs": { "enabled": true, "clientKind": "git", diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index f056b3bdd..476ec943f 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-arm64", - "version": "0.34.4", + "version": "0.34.5-rc.0", "description": "Prebuilt sharp for use with macOS 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index cdf02fe06..e07eff86b 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-x64", - "version": "0.34.4", + "version": "0.34.5-rc.0", "description": "Prebuilt sharp for use with macOS x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm/package.json b/npm/linux-arm/package.json index d32dc06bd..331102fe9 100644 --- a/npm/linux-arm/package.json +++ b/npm/linux-arm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm", - "version": "0.34.4", + "version": "0.34.5-rc.0", "description": "Prebuilt sharp for use with Linux (glibc) ARM (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm64/package.json b/npm/linux-arm64/package.json index bd2c4587e..38f5893ad 100644 --- a/npm/linux-arm64/package.json +++ b/npm/linux-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm64", - "version": "0.34.4", + "version": "0.34.5-rc.0", "description": "Prebuilt sharp for use with Linux (glibc) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-ppc64/package.json b/npm/linux-ppc64/package.json index 8a2e183c2..0a47d9684 100644 --- a/npm/linux-ppc64/package.json +++ b/npm/linux-ppc64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-ppc64", - "version": "0.34.4", + "version": "0.34.5-rc.0", "description": "Prebuilt sharp for use with Linux (glibc) ppc64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-riscv64/package.json b/npm/linux-riscv64/package.json index 076d2cdf5..17317482d 100644 --- a/npm/linux-riscv64/package.json +++ b/npm/linux-riscv64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-riscv64", - "version": "0.34.4", + "version": "0.34.5-rc.0", "description": "Prebuilt sharp for use with Linux (glibc) RISC-V 64-bit", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-s390x/package.json b/npm/linux-s390x/package.json index 6ba8a4555..30da146d6 100644 --- a/npm/linux-s390x/package.json +++ b/npm/linux-s390x/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-s390x", - "version": "0.34.4", + "version": "0.34.5-rc.0", "description": "Prebuilt sharp for use with Linux (glibc) s390x", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-x64/package.json b/npm/linux-x64/package.json index e613ddfad..36f0405b6 100644 --- a/npm/linux-x64/package.json +++ b/npm/linux-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-x64", - "version": "0.34.4", + "version": "0.34.5-rc.0", "description": "Prebuilt sharp for use with Linux (glibc) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-arm64/package.json b/npm/linuxmusl-arm64/package.json index 3ab8537e3..8958d0986 100644 --- a/npm/linuxmusl-arm64/package.json +++ b/npm/linuxmusl-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-arm64", - "version": "0.34.4", + "version": "0.34.5-rc.0", "description": "Prebuilt sharp for use with Linux (musl) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-x64/package.json b/npm/linuxmusl-x64/package.json index 83f7027d1..ce8632c4f 100644 --- a/npm/linuxmusl-x64/package.json +++ b/npm/linuxmusl-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-x64", - "version": "0.34.4", + "version": "0.34.5-rc.0", "description": "Prebuilt sharp for use with Linux (musl) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/package.json b/npm/package.json index 6fe69b646..8948314c0 100644 --- a/npm/package.json +++ b/npm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp", - "version": "0.34.4", + "version": "0.34.5-rc.0", "private": "true", "workspaces": [ "darwin-arm64", diff --git a/npm/wasm32/package.json b/npm/wasm32/package.json index f4fc25fd4..e7d408778 100644 --- a/npm/wasm32/package.json +++ b/npm/wasm32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-wasm32", - "version": "0.34.4", + "version": "0.34.5-rc.0", "description": "Prebuilt sharp for use with wasm32", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", @@ -31,7 +31,7 @@ "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "dependencies": { - "@emnapi/runtime": "^1.6.0" + "@emnapi/runtime": "^1.7.0" }, "cpu": [ "wasm32" diff --git a/npm/win32-arm64/package.json b/npm/win32-arm64/package.json index 741cca7ef..55bd7a034 100644 --- a/npm/win32-arm64/package.json +++ b/npm/win32-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-arm64", - "version": "0.34.4", + "version": "0.34.5-rc.0", "description": "Prebuilt sharp for use with Windows 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-ia32/package.json b/npm/win32-ia32/package.json index e92a3bc92..afab5ab82 100644 --- a/npm/win32-ia32/package.json +++ b/npm/win32-ia32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-ia32", - "version": "0.34.4", + "version": "0.34.5-rc.0", "description": "Prebuilt sharp for use with Windows x86 (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-x64/package.json b/npm/win32-x64/package.json index ea1c7cdda..1ef2ff204 100644 --- a/npm/win32-x64/package.json +++ b/npm/win32-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-x64", - "version": "0.34.4", + "version": "0.34.5-rc.0", "description": "Prebuilt sharp for use with Windows x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/package.json b/package.json index f992e7100..d202ca1f6 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "sharp", "description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images", - "version": "0.34.4", + "version": "0.34.5-rc.0", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", "contributors": [ @@ -144,8 +144,8 @@ "semver": "^7.7.3" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.4", - "@img/sharp-darwin-x64": "0.34.4", + "@img/sharp-darwin-arm64": "0.34.5-rc.0", + "@img/sharp-darwin-x64": "0.34.5-rc.0", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", @@ -156,30 +156,30 @@ "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", - "@img/sharp-linux-arm": "0.34.4", - "@img/sharp-linux-arm64": "0.34.4", - "@img/sharp-linux-ppc64": "0.34.4", - "@img/sharp-linux-riscv64": "0.34.4", - "@img/sharp-linux-s390x": "0.34.4", - "@img/sharp-linux-x64": "0.34.4", - "@img/sharp-linuxmusl-arm64": "0.34.4", - "@img/sharp-linuxmusl-x64": "0.34.4", - "@img/sharp-wasm32": "0.34.4", - "@img/sharp-win32-arm64": "0.34.4", - "@img/sharp-win32-ia32": "0.34.4", - "@img/sharp-win32-x64": "0.34.4" + "@img/sharp-linux-arm": "0.34.5-rc.0", + "@img/sharp-linux-arm64": "0.34.5-rc.0", + "@img/sharp-linux-ppc64": "0.34.5-rc.0", + "@img/sharp-linux-riscv64": "0.34.5-rc.0", + "@img/sharp-linux-s390x": "0.34.5-rc.0", + "@img/sharp-linux-x64": "0.34.5-rc.0", + "@img/sharp-linuxmusl-arm64": "0.34.5-rc.0", + "@img/sharp-linuxmusl-x64": "0.34.5-rc.0", + "@img/sharp-wasm32": "0.34.5-rc.0", + "@img/sharp-win32-arm64": "0.34.5-rc.0", + "@img/sharp-win32-ia32": "0.34.5-rc.0", + "@img/sharp-win32-x64": "0.34.5-rc.0" }, "devDependencies": { - "@biomejs/biome": "^2.3.3", + "@biomejs/biome": "^2.3.4", "@cpplint/cli": "^0.1.0", - "@emnapi/runtime": "^1.6.0", + "@emnapi/runtime": "^1.7.0", "@img/sharp-libvips-dev": "1.2.4", "@img/sharp-libvips-dev-wasm32": "1.2.4", "@img/sharp-libvips-win32-arm64": "1.2.4", "@img/sharp-libvips-win32-ia32": "1.2.4", "@img/sharp-libvips-win32-x64": "1.2.4", "@types/node": "*", - "emnapi": "^1.6.0", + "emnapi": "^1.7.0", "exif-reader": "^2.0.2", "extract-zip": "^2.0.1", "icc": "^3.0.0", From f7c95d1bf0f24049ee6ee77b21b1c1bb8d181aa2 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Thu, 6 Nov 2025 11:15:28 +0000 Subject: [PATCH 108/115] TypeScript: consolidate a few enum-like properties --- lib/index.d.ts | 15 ++++++++++----- test/types/sharp.test-d.ts | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/index.d.ts b/lib/index.d.ts index ed99ecf8c..89ff39e77 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -860,6 +860,7 @@ declare namespace sharp { | JxlOptions | GifOptions | Jp2Options + | RawOptions | TiffOptions, ): Sharp; @@ -1181,6 +1182,10 @@ declare namespace sharp { 'IFD3'?: ExifDir; } + type HeifCompression = 'av1' | 'hevc'; + + type Unit = 'inch' | 'cm'; + interface WriteableMetadata { /** Number of pixels per inch (DPI) */ density?: number | undefined; @@ -1259,7 +1264,7 @@ declare namespace sharp { /** Buffer containing raw TIFFTAG_PHOTOSHOP data, if present */ tifftagPhotoshop?: Buffer | undefined; /** The encoder used to compress an HEIF file, `av1` (AVIF) or `hevc` (HEIC) */ - compression?: 'av1' | 'hevc'; + compression?: HeifCompression | undefined; /** Default background colour, if present, for PNG (bKGD) and GIF images */ background?: { r: number; g: number; b: number } | { gray: number }; /** Details of each level in a multi-level image provided as an array of objects, requires libvips compiled with support for OpenSlide */ @@ -1267,7 +1272,7 @@ declare namespace sharp { /** Number of Sub Image File Directories in an OME-TIFF image */ subifds?: number | undefined; /** The unit of resolution (density) */ - resolutionUnit?: 'inch' | 'cm' | undefined; + resolutionUnit?: Unit | undefined; /** String containing format for images loaded via *magick */ formatMagick?: string | undefined; /** Array of keyword/text pairs representing PNG text blocks, if present. */ @@ -1423,7 +1428,7 @@ declare namespace sharp { /** quality, integer 1-100 (optional, default 50) */ quality?: number | undefined; /** compression format: av1, hevc (optional, default 'av1') */ - compression?: 'av1' | 'hevc' | undefined; + compression?: HeifCompression | undefined; /** use lossless compression (optional, default false) */ lossless?: boolean | undefined; /** Level of CPU effort to reduce file size, between 0 (fastest) and 9 (slowest) (optional, default 4) */ @@ -1481,7 +1486,7 @@ declare namespace sharp { /** Write 1-bit images as miniswhite (optional, default false) */ miniswhite?: boolean | undefined; /** Resolution unit options: inch, cm (optional, default 'inch') */ - resolutionUnit?: 'inch' | 'cm' | undefined; + resolutionUnit?: Unit | undefined; } interface PngOptions extends OutputOptions { @@ -1606,7 +1611,7 @@ declare namespace sharp { } interface RawOptions { - depth?: 'char' | 'uchar' | 'short' | 'ushort' | 'int' | 'uint' | 'float' | 'complex' | 'double' | 'dpcomplex'; + depth?: keyof DepthEnum; } /** 1 for grayscale, 2 for grayscale + alpha, 3 for sRGB, 4 for CMYK or RGBA */ diff --git a/test/types/sharp.test-d.ts b/test/types/sharp.test-d.ts index 9c6e78506..9364c08c8 100644 --- a/test/types/sharp.test-d.ts +++ b/test/types/sharp.test-d.ts @@ -321,7 +321,7 @@ sharp('input.gif') // From https://sharp.pixelplumbing.com/api-output#examples-9 // Extract raw RGB pixel data from JPEG input sharp('input.jpg') - .raw() + .raw({ depth: 'ushort' }) .toBuffer({ resolveWithObject: true }) .then(({ data, info }) => { console.log(data); From 6450c704a686d4205a2c21ddb1d10d5fc28c6c23 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Thu, 6 Nov 2025 11:34:00 +0000 Subject: [PATCH 109/115] Prerelease v0.34.5-rc.1 --- npm/darwin-arm64/package.json | 2 +- npm/darwin-x64/package.json | 2 +- npm/linux-arm/package.json | 2 +- npm/linux-arm64/package.json | 2 +- npm/linux-ppc64/package.json | 2 +- npm/linux-riscv64/package.json | 2 +- npm/linux-s390x/package.json | 2 +- npm/linux-x64/package.json | 2 +- npm/linuxmusl-arm64/package.json | 2 +- npm/linuxmusl-x64/package.json | 2 +- npm/package.json | 3 ++- npm/wasm32/package.json | 2 +- npm/win32-arm64/package.json | 2 +- npm/win32-ia32/package.json | 2 +- npm/win32-x64/package.json | 2 +- package.json | 30 +++++++++++++++--------------- 16 files changed, 31 insertions(+), 30 deletions(-) diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index 476ec943f..4ed4b81ce 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-arm64", - "version": "0.34.5-rc.0", + "version": "0.34.5-rc.1", "description": "Prebuilt sharp for use with macOS 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index e07eff86b..ec5c941e6 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-x64", - "version": "0.34.5-rc.0", + "version": "0.34.5-rc.1", "description": "Prebuilt sharp for use with macOS x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm/package.json b/npm/linux-arm/package.json index 331102fe9..7e07c7da4 100644 --- a/npm/linux-arm/package.json +++ b/npm/linux-arm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm", - "version": "0.34.5-rc.0", + "version": "0.34.5-rc.1", "description": "Prebuilt sharp for use with Linux (glibc) ARM (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm64/package.json b/npm/linux-arm64/package.json index 38f5893ad..a979a6819 100644 --- a/npm/linux-arm64/package.json +++ b/npm/linux-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm64", - "version": "0.34.5-rc.0", + "version": "0.34.5-rc.1", "description": "Prebuilt sharp for use with Linux (glibc) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-ppc64/package.json b/npm/linux-ppc64/package.json index 0a47d9684..4a23b66e8 100644 --- a/npm/linux-ppc64/package.json +++ b/npm/linux-ppc64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-ppc64", - "version": "0.34.5-rc.0", + "version": "0.34.5-rc.1", "description": "Prebuilt sharp for use with Linux (glibc) ppc64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-riscv64/package.json b/npm/linux-riscv64/package.json index 17317482d..085e29582 100644 --- a/npm/linux-riscv64/package.json +++ b/npm/linux-riscv64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-riscv64", - "version": "0.34.5-rc.0", + "version": "0.34.5-rc.1", "description": "Prebuilt sharp for use with Linux (glibc) RISC-V 64-bit", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-s390x/package.json b/npm/linux-s390x/package.json index 30da146d6..33b345692 100644 --- a/npm/linux-s390x/package.json +++ b/npm/linux-s390x/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-s390x", - "version": "0.34.5-rc.0", + "version": "0.34.5-rc.1", "description": "Prebuilt sharp for use with Linux (glibc) s390x", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-x64/package.json b/npm/linux-x64/package.json index 36f0405b6..d3f4ea13d 100644 --- a/npm/linux-x64/package.json +++ b/npm/linux-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-x64", - "version": "0.34.5-rc.0", + "version": "0.34.5-rc.1", "description": "Prebuilt sharp for use with Linux (glibc) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-arm64/package.json b/npm/linuxmusl-arm64/package.json index 8958d0986..c3ac43250 100644 --- a/npm/linuxmusl-arm64/package.json +++ b/npm/linuxmusl-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-arm64", - "version": "0.34.5-rc.0", + "version": "0.34.5-rc.1", "description": "Prebuilt sharp for use with Linux (musl) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-x64/package.json b/npm/linuxmusl-x64/package.json index ce8632c4f..c450d043d 100644 --- a/npm/linuxmusl-x64/package.json +++ b/npm/linuxmusl-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-x64", - "version": "0.34.5-rc.0", + "version": "0.34.5-rc.1", "description": "Prebuilt sharp for use with Linux (musl) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/package.json b/npm/package.json index 8948314c0..32586c4f9 100644 --- a/npm/package.json +++ b/npm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp", - "version": "0.34.5-rc.0", + "version": "0.34.5-rc.1", "private": "true", "workspaces": [ "darwin-arm64", @@ -8,6 +8,7 @@ "linux-arm", "linux-arm64", "linux-ppc64", + "linux-riscv64", "linux-s390x", "linux-x64", "linuxmusl-arm64", diff --git a/npm/wasm32/package.json b/npm/wasm32/package.json index e7d408778..508ba86f8 100644 --- a/npm/wasm32/package.json +++ b/npm/wasm32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-wasm32", - "version": "0.34.5-rc.0", + "version": "0.34.5-rc.1", "description": "Prebuilt sharp for use with wasm32", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-arm64/package.json b/npm/win32-arm64/package.json index 55bd7a034..b14a6b26f 100644 --- a/npm/win32-arm64/package.json +++ b/npm/win32-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-arm64", - "version": "0.34.5-rc.0", + "version": "0.34.5-rc.1", "description": "Prebuilt sharp for use with Windows 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-ia32/package.json b/npm/win32-ia32/package.json index afab5ab82..4b319a616 100644 --- a/npm/win32-ia32/package.json +++ b/npm/win32-ia32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-ia32", - "version": "0.34.5-rc.0", + "version": "0.34.5-rc.1", "description": "Prebuilt sharp for use with Windows x86 (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-x64/package.json b/npm/win32-x64/package.json index 1ef2ff204..d9b181d29 100644 --- a/npm/win32-x64/package.json +++ b/npm/win32-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-x64", - "version": "0.34.5-rc.0", + "version": "0.34.5-rc.1", "description": "Prebuilt sharp for use with Windows x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/package.json b/package.json index d202ca1f6..b48724e4a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "sharp", "description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images", - "version": "0.34.5-rc.0", + "version": "0.34.5-rc.1", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", "contributors": [ @@ -144,8 +144,8 @@ "semver": "^7.7.3" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.5-rc.0", - "@img/sharp-darwin-x64": "0.34.5-rc.0", + "@img/sharp-darwin-arm64": "0.34.5-rc.1", + "@img/sharp-darwin-x64": "0.34.5-rc.1", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", @@ -156,18 +156,18 @@ "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", - "@img/sharp-linux-arm": "0.34.5-rc.0", - "@img/sharp-linux-arm64": "0.34.5-rc.0", - "@img/sharp-linux-ppc64": "0.34.5-rc.0", - "@img/sharp-linux-riscv64": "0.34.5-rc.0", - "@img/sharp-linux-s390x": "0.34.5-rc.0", - "@img/sharp-linux-x64": "0.34.5-rc.0", - "@img/sharp-linuxmusl-arm64": "0.34.5-rc.0", - "@img/sharp-linuxmusl-x64": "0.34.5-rc.0", - "@img/sharp-wasm32": "0.34.5-rc.0", - "@img/sharp-win32-arm64": "0.34.5-rc.0", - "@img/sharp-win32-ia32": "0.34.5-rc.0", - "@img/sharp-win32-x64": "0.34.5-rc.0" + "@img/sharp-linux-arm": "0.34.5-rc.1", + "@img/sharp-linux-arm64": "0.34.5-rc.1", + "@img/sharp-linux-ppc64": "0.34.5-rc.1", + "@img/sharp-linux-riscv64": "0.34.5-rc.1", + "@img/sharp-linux-s390x": "0.34.5-rc.1", + "@img/sharp-linux-x64": "0.34.5-rc.1", + "@img/sharp-linuxmusl-arm64": "0.34.5-rc.1", + "@img/sharp-linuxmusl-x64": "0.34.5-rc.1", + "@img/sharp-wasm32": "0.34.5-rc.1", + "@img/sharp-win32-arm64": "0.34.5-rc.1", + "@img/sharp-win32-ia32": "0.34.5-rc.1", + "@img/sharp-win32-x64": "0.34.5-rc.1" }, "devDependencies": { "@biomejs/biome": "^2.3.4", From e0624568686516209c434de2d3c0ef6688f0811d Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Thu, 6 Nov 2025 14:06:31 +0000 Subject: [PATCH 110/115] Release v0.34.5 --- docs/src/content/docs/changelog/v0.34.5.md | 2 +- npm/darwin-arm64/package.json | 2 +- npm/darwin-x64/package.json | 2 +- npm/linux-arm/package.json | 2 +- npm/linux-arm64/package.json | 2 +- npm/linux-ppc64/package.json | 2 +- npm/linux-riscv64/package.json | 2 +- npm/linux-s390x/package.json | 2 +- npm/linux-x64/package.json | 2 +- npm/linuxmusl-arm64/package.json | 2 +- npm/linuxmusl-x64/package.json | 2 +- npm/package.json | 2 +- npm/wasm32/package.json | 2 +- npm/win32-arm64/package.json | 2 +- npm/win32-ia32/package.json | 2 +- npm/win32-x64/package.json | 2 +- package.json | 36 +++++++++------------- 17 files changed, 31 insertions(+), 37 deletions(-) diff --git a/docs/src/content/docs/changelog/v0.34.5.md b/docs/src/content/docs/changelog/v0.34.5.md index df994024a..d8321baa4 100644 --- a/docs/src/content/docs/changelog/v0.34.5.md +++ b/docs/src/content/docs/changelog/v0.34.5.md @@ -1,5 +1,5 @@ --- -title: v0.34.5 - TBD +title: v0.34.5 - 6th November 2025 slug: changelog/v0.34.5 --- diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index 4ed4b81ce..df6b34a92 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-arm64", - "version": "0.34.5-rc.1", + "version": "0.34.5", "description": "Prebuilt sharp for use with macOS 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index ec5c941e6..147d109dd 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-darwin-x64", - "version": "0.34.5-rc.1", + "version": "0.34.5", "description": "Prebuilt sharp for use with macOS x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm/package.json b/npm/linux-arm/package.json index 7e07c7da4..cd4d5a2b6 100644 --- a/npm/linux-arm/package.json +++ b/npm/linux-arm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm", - "version": "0.34.5-rc.1", + "version": "0.34.5", "description": "Prebuilt sharp for use with Linux (glibc) ARM (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-arm64/package.json b/npm/linux-arm64/package.json index a979a6819..b373bb920 100644 --- a/npm/linux-arm64/package.json +++ b/npm/linux-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-arm64", - "version": "0.34.5-rc.1", + "version": "0.34.5", "description": "Prebuilt sharp for use with Linux (glibc) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-ppc64/package.json b/npm/linux-ppc64/package.json index 4a23b66e8..db2b62c01 100644 --- a/npm/linux-ppc64/package.json +++ b/npm/linux-ppc64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-ppc64", - "version": "0.34.5-rc.1", + "version": "0.34.5", "description": "Prebuilt sharp for use with Linux (glibc) ppc64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-riscv64/package.json b/npm/linux-riscv64/package.json index 085e29582..9f0e95204 100644 --- a/npm/linux-riscv64/package.json +++ b/npm/linux-riscv64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-riscv64", - "version": "0.34.5-rc.1", + "version": "0.34.5", "description": "Prebuilt sharp for use with Linux (glibc) RISC-V 64-bit", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-s390x/package.json b/npm/linux-s390x/package.json index 33b345692..423692edd 100644 --- a/npm/linux-s390x/package.json +++ b/npm/linux-s390x/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-s390x", - "version": "0.34.5-rc.1", + "version": "0.34.5", "description": "Prebuilt sharp for use with Linux (glibc) s390x", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linux-x64/package.json b/npm/linux-x64/package.json index d3f4ea13d..95a8a035f 100644 --- a/npm/linux-x64/package.json +++ b/npm/linux-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linux-x64", - "version": "0.34.5-rc.1", + "version": "0.34.5", "description": "Prebuilt sharp for use with Linux (glibc) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-arm64/package.json b/npm/linuxmusl-arm64/package.json index c3ac43250..5e214bf18 100644 --- a/npm/linuxmusl-arm64/package.json +++ b/npm/linuxmusl-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-arm64", - "version": "0.34.5-rc.1", + "version": "0.34.5", "description": "Prebuilt sharp for use with Linux (musl) 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/linuxmusl-x64/package.json b/npm/linuxmusl-x64/package.json index c450d043d..8be92db0d 100644 --- a/npm/linuxmusl-x64/package.json +++ b/npm/linuxmusl-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-linuxmusl-x64", - "version": "0.34.5-rc.1", + "version": "0.34.5", "description": "Prebuilt sharp for use with Linux (musl) x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/package.json b/npm/package.json index 32586c4f9..773daa94a 100644 --- a/npm/package.json +++ b/npm/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp", - "version": "0.34.5-rc.1", + "version": "0.34.5", "private": "true", "workspaces": [ "darwin-arm64", diff --git a/npm/wasm32/package.json b/npm/wasm32/package.json index 508ba86f8..d5775bec3 100644 --- a/npm/wasm32/package.json +++ b/npm/wasm32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-wasm32", - "version": "0.34.5-rc.1", + "version": "0.34.5", "description": "Prebuilt sharp for use with wasm32", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-arm64/package.json b/npm/win32-arm64/package.json index b14a6b26f..651f420ea 100644 --- a/npm/win32-arm64/package.json +++ b/npm/win32-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-arm64", - "version": "0.34.5-rc.1", + "version": "0.34.5", "description": "Prebuilt sharp for use with Windows 64-bit ARM", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-ia32/package.json b/npm/win32-ia32/package.json index 4b319a616..21c6dbba2 100644 --- a/npm/win32-ia32/package.json +++ b/npm/win32-ia32/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-ia32", - "version": "0.34.5-rc.1", + "version": "0.34.5", "description": "Prebuilt sharp for use with Windows x86 (32-bit)", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/npm/win32-x64/package.json b/npm/win32-x64/package.json index d9b181d29..8b867b5e2 100644 --- a/npm/win32-x64/package.json +++ b/npm/win32-x64/package.json @@ -1,6 +1,6 @@ { "name": "@img/sharp-win32-x64", - "version": "0.34.5-rc.1", + "version": "0.34.5", "description": "Prebuilt sharp for use with Windows x64", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", diff --git a/package.json b/package.json index b48724e4a..0c0d00988 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "sharp", "description": "High performance Node.js image processing, the fastest module to resize JPEG, PNG, WebP, GIF, AVIF and TIFF images", - "version": "0.34.5-rc.1", + "version": "0.34.5", "author": "Lovell Fuller ", "homepage": "https://sharp.pixelplumbing.com", "contributors": [ @@ -144,8 +144,8 @@ "semver": "^7.7.3" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.5-rc.1", - "@img/sharp-darwin-x64": "0.34.5-rc.1", + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", @@ -156,18 +156,18 @@ "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", - "@img/sharp-linux-arm": "0.34.5-rc.1", - "@img/sharp-linux-arm64": "0.34.5-rc.1", - "@img/sharp-linux-ppc64": "0.34.5-rc.1", - "@img/sharp-linux-riscv64": "0.34.5-rc.1", - "@img/sharp-linux-s390x": "0.34.5-rc.1", - "@img/sharp-linux-x64": "0.34.5-rc.1", - "@img/sharp-linuxmusl-arm64": "0.34.5-rc.1", - "@img/sharp-linuxmusl-x64": "0.34.5-rc.1", - "@img/sharp-wasm32": "0.34.5-rc.1", - "@img/sharp-win32-arm64": "0.34.5-rc.1", - "@img/sharp-win32-ia32": "0.34.5-rc.1", - "@img/sharp-win32-x64": "0.34.5-rc.1" + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" }, "devDependencies": { "@biomejs/biome": "^2.3.4", @@ -198,11 +198,5 @@ }, "funding": { "url": "https://opencollective.com/libvips" - }, - "cc": { - "linelength": "120", - "filter": [ - "build/include" - ] } } From f2a49d19c9866ad59cd2a2c17fd937fd5a2fb0e0 Mon Sep 17 00:00:00 2001 From: Sylvester Keil Date: Fri, 7 Nov 2025 12:39:39 +0100 Subject: [PATCH 111/115] Fix invalid escape sequence (#4471) --- src/binding.gyp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/binding.gyp b/src/binding.gyp index c4ec70cc0..2040cde5b 100644 --- a/src/binding.gyp +++ b/src/binding.gyp @@ -120,7 +120,7 @@ 'conditions': [ ['use_global_libvips == "true"', { # Use pkg-config for include and lib - 'include_dirs': [' Date: Mon, 10 Nov 2025 16:41:22 +0000 Subject: [PATCH 112/115] TypeScript: tag deprecated constructor properties (#4474) --- lib/index.d.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/index.d.ts b/lib/index.d.ts index 89ff39e77..13714c947 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1028,11 +1028,11 @@ declare namespace sharp { openSlide?: OpenSlideInputOptions | undefined; /** JPEG 2000 specific input options */ jp2?: Jp2InputOptions | undefined; - /** Deprecated: use tiff.subifd instead */ + /** @deprecated Use {@link SharpOptions.tiff} instead */ subifd?: number | undefined; - /** Deprecated: use pdf.background instead */ + /** @deprecated Use {@link SharpOptions.pdf} instead */ pdfBackground?: Colour | Color | undefined; - /** Deprecated: use openSlide.level instead */ + /** @deprecated Use {@link SharpOptions.openSlide} instead */ level?: number | undefined; /** Set to `true` to read all frames/pages of an animated image (equivalent of setting `pages` to `-1`). (optional, default false) */ animated?: boolean | undefined; From 3609c61a226760a4e9ce8524c1b42e136831b89e Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Sat, 15 Nov 2025 11:55:58 +0100 Subject: [PATCH 113/115] Tests: fix JP2 suite with global libvips (#4477) --- test/unit/jp2.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/unit/jp2.js b/test/unit/jp2.js index 1f9dcb1ba..536e0a040 100644 --- a/test/unit/jp2.js +++ b/test/unit/jp2.js @@ -45,11 +45,11 @@ describe('JP2 output', () => { assert.strictEqual('png', info.format); assert.strictEqual(8, info.width); assert.strictEqual(15, info.height); - assert.strictEqual(4, info.channels); + assert.strictEqual(3, info.channels); }); }); - it('JP2 quality', (done) => { + it('JP2 quality', (_t, done) => { sharp(fixtures.inputJp2) .resize(320, 240) .jp2({ quality: 70 }) @@ -65,7 +65,7 @@ describe('JP2 output', () => { }); }); - it('Without chroma subsampling generates larger file', (done) => { + it('Without chroma subsampling generates larger file', (_t, done) => { // First generate with chroma subsampling (default) sharp(fixtures.inputJp2) .resize(320, 240) @@ -111,7 +111,7 @@ describe('JP2 output', () => { it('Invalid JP2 chromaSubsampling value throws error', () => { assert.throws( () => sharp().jp2({ chromaSubsampling: '4:2:2' }), - /Expected one of 4:2:0, 4:4:4 but received 4:2:2 of type string/ + /Expected one of: 4:2:0, 4:4:4 for chromaSubsampling but received 4:2:2 of type string/ ); }); } From 084a30f8bf05b3260adb26875c2b6c45ecb36038 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Wed, 10 Dec 2025 15:38:14 +0000 Subject: [PATCH 114/115] Docs: clarify metadata 'format' property #4483 --- docs/src/content/docs/api-input.md | 2 +- lib/input.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/content/docs/api-input.md b/docs/src/content/docs/api-input.md index a5a9e3739..8477f1ff5 100644 --- a/docs/src/content/docs/api-input.md +++ b/docs/src/content/docs/api-input.md @@ -17,7 +17,7 @@ Dimensions in the response will respect the `page` and `pages` properties of the A `Promise` is returned when `callback` is not provided. -- `format`: Name of decoder used to decompress image data e.g. `jpeg`, `png`, `webp`, `gif`, `svg` +- `format`: Name of decoder used to parse image e.g. `jpeg`, `png`, `webp`, `gif`, `svg`, `heif`, `tiff` - `size`: Total size of image in bytes, for Stream and Buffer input only - `width`: Number of pixels wide (EXIF orientation is not taken into consideration, see example below) - `height`: Number of pixels high (EXIF orientation is not taken into consideration, see example below) diff --git a/lib/input.js b/lib/input.js index 728b7188e..48388a1d2 100644 --- a/lib/input.js +++ b/lib/input.js @@ -574,7 +574,7 @@ function _isStreamInput () { * * A `Promise` is returned when `callback` is not provided. * - * - `format`: Name of decoder used to decompress image data e.g. `jpeg`, `png`, `webp`, `gif`, `svg` + * - `format`: Name of decoder used to parse image e.g. `jpeg`, `png`, `webp`, `gif`, `svg`, `heif`, `tiff` * - `size`: Total size of image in bytes, for Stream and Buffer input only * - `width`: Number of pixels wide (EXIF orientation is not taken into consideration, see example below) * - `height`: Number of pixels high (EXIF orientation is not taken into consideration, see example below) From 7b4c4762432b14c62676e860c8034b5cd326f464 Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Tue, 16 Dec 2025 19:59:31 +0000 Subject: [PATCH 115/115] CI: Update to latest FreeBSD 16 --- .cirrus.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cirrus.yml b/.cirrus.yml index 45f9c3df7..5a6fb8c59 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,5 +1,5 @@ freebsd_instance: - image_family: freebsd-15-0 + image_family: freebsd-16-0-snap task: name: FreeBSD