diff --git a/.optimiztrc.cjs b/.optimiztrc.cjs index b08918c..173bd19 100644 --- a/.optimiztrc.cjs +++ b/.optimiztrc.cjs @@ -15,7 +15,7 @@ module.exports = { }, // https://github.com/google/guetzli lossless: { - quality: 90, // visual quality to aim for, expressed as a JPEG quality value + quality: 90, // visual quality to aim for, expressed as a JPEG quality value; should be >= 84, otherwise the output will have noticeable artifacts memlimit: 6000, // memory limit in MB; guetzli will fail if unable to stay under the limit nomemlimit: false, // do not limit memory usage }, @@ -39,7 +39,7 @@ module.exports = { adaptiveFiltering: true, palette: false, quality: 100, - effort: 7, + effort: 10, colors: 256, dither: 1.0, }, @@ -88,15 +88,15 @@ module.exports = { // https://sharp.pixelplumbing.com/api-output#avif avif: { lossy: { - quality: 50, // quality, integer 1-100 + quality: 64, // quality, integer 1-100 lossless: false, // use lossless compression effort: 4, // CPU effort, between 0 (fastest) and 9 (slowest) chromaSubsampling: '4:4:4', // set to '4:2:0' to use chroma subsampling }, lossless: { - quality: 50, + quality: 100, lossless: true, - effort: 4, + effort: 9, chromaSubsampling: '4:4:4', }, }, @@ -104,51 +104,27 @@ module.exports = { // https://sharp.pixelplumbing.com/api-output#webp webp: { lossy: { - quality: 85, // quality, integer 1-100 - alphaQuality: 100, // quality of alpha layer, integer 0-100 + quality: 82, // quality, integer 1-100 + alphaQuality: 82, // quality of alpha layer, integer 0-100 lossless: false, // use lossless compression mode nearLossless: false, // use near_lossless compression mode smartSubsample: false, // use high quality chroma subsampling preset: 'default', // named preset for preprocessing/filtering, one of: default, photo, picture, drawing, icon, text effort: 4, // CPU effort, between 0 (fastest) and 6 (slowest) - minSize: false, // prevent use of animation key frames to minimise file size (slow) + minSize: true, // prevent use of animation key frames to minimise file size (slow) mixed: false, // allow mixture of lossy and lossless animation frames (slow) }, lossless: { - quality: 85, + quality: 100, alphaQuality: 100, lossless: true, nearLossless: false, smartSubsample: false, - effort: 4, + preset: 'default', + effort: 6, minSize: false, mixed: false, }, }, - - // https://developers.google.com/speed/webp/docs/gif2webp - webpGif: { - lossy: { - lossy: true, // encode image using lossy compression - mixed: false, // for each frame in the image, pick lossy or lossless compression heuristically - q: 75, // in case of lossy compression, a small factor produces a smaller file with lower quality; best quality is achieved by using a value of 100 - m: 6, // compression method (0=fast, 6=slowest) - min_size: true, // minimize output size; can be combined with -q, -m, -lossy or -mixed options - f: 0, // filter strength (0=off..100); for lossy encoding only - metadata: 'xmp', // comma separated list of metadata to copy from the input to the output if present; valid values: all, none, icc, xmp - loop_compatibility: false, // use compatibility mode for Chrome version prior to M62 (inclusive) - mt: true, // use multi-threading if available - }, - lossless: { - lossy: false, - mixed: false, - q: 100, - m: false, - min_size: false, - metadata: 'xmp', - loop_compatibility: false, - mt: true, - }, - }, }, }; diff --git a/CHANGELOG.md b/CHANGELOG.md index f6008fb..87d9f88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## 10.0.0 (2024-10-28) + +Breaking Changes: + +- Supported Node.js version updated to 18.18 or higher. +- Replaced “gif2webp” with “sharp” for GIF-to-WebP conversions. +- Removed the “webpGif” section from [.optimiztrc.cjs](.optimiztrc.cjs). +- Fine-tuned params in [.optimiztrc.cjs](.optimiztrc.cjs). + + ## 9.1.1 (2024-10-22) - Replaced [imagemin/guetzli-bin](https://github.com/imagemin/guetzli-bin) with [343dev/guetzli](https://github.com/343dev/guetzli). diff --git a/Dockerfile b/Dockerfile index 0ad3c45..dfe26e6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:18.17.0-bullseye-slim +FROM node:18.18.0-bullseye-slim LABEL maintainer="Andrey Warkentin (https://github.com/343dev)" WORKDIR /app @@ -8,13 +8,13 @@ COPY . . ENV NODE_ENV="production" RUN apt update \ - && apt install --yes --no-install-recommends build-essential libpng16-16 libjpeg62-turbo libjpeg62-turbo-dev libpng-dev pkg-config dh-autoreconf \ - && npm ci \ - && npm link \ - && npm cache clean --force \ - && apt purge --yes build-essential pkg-config libpng-dev libjpeg62-turbo-dev dh-autoreconf \ - && apt autoremove --yes --purge \ - && rm -rf /var/lib/apt/lists/* /usr/share/doc /usr/share/man + && apt install --yes --no-install-recommends build-essential libpng16-16 libjpeg62-turbo libjpeg62-turbo-dev libpng-dev pkg-config dh-autoreconf \ + && npm ci \ + && npm link \ + && npm cache clean --force \ + && apt purge --yes build-essential pkg-config libpng-dev libjpeg62-turbo-dev dh-autoreconf \ + && apt autoremove --yes --purge \ + && rm -rf /var/lib/apt/lists/* /usr/share/doc /usr/share/man WORKDIR /src diff --git a/MIGRATION.md b/MIGRATION.md index e753e5d..37117f1 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -1,5 +1,14 @@ # Migration +## 9.1.1 → 10.0.0 + +Node.js version must be 18.18 or higher. + +The “sharp” module now replaces “gif2webp” for converting GIFs to WebP. Consequently, the “webpGif” section in [.optimiztrc.cjs](.optimiztrc.cjs) has been replaced with a “webp” section. If you use a custom configuration file, please remove any “webpGif” section. + +Default settings in Optimizt’s configuration have been updated. Note that in lossless mode, image processing times may increase slightly, but resulting file sizes are expected to be smaller compared to previous versions. + + ## 8.0.1 → 9.0.0 The main change in the new version is how Optimizt handles file processing. Before, the result was stored in memory until all files were processed. This could cause the app to crash if it ran out of memory, leading to a loss of optimization results. Now, each file is processed one by one, and the result is saved to disk immediately. Logging events also happen in real-time, instead of waiting until all files are done. diff --git a/README.md b/README.md index 3f75683..ee8b84d 100644 --- a/README.md +++ b/README.md @@ -72,9 +72,9 @@ For SVG files, the settings in Lossy and Lossless modes are identical. ## Configuration -Image processing is done using [sharp](https://github.com/lovell/sharp) for [JPEG](https://sharp.pixelplumbing.com/api-output#jpeg), [PNG](https://sharp.pixelplumbing.com/api-output#png), [WebP](https://sharp.pixelplumbing.com/api-output#webp), and [AVIF](https://sharp.pixelplumbing.com/api-output#avif), while SVG is processed by [svgo](https://github.com/svg/svgo). +Image processing is done using [sharp](https://github.com/lovell/sharp) for [JPEG](https://sharp.pixelplumbing.com/api-output#jpeg), [PNG](https://sharp.pixelplumbing.com/api-output#png), [WebP](https://sharp.pixelplumbing.com/api-output#webp), and [AVIF](https://sharp.pixelplumbing.com/api-output#avif). -For GIF, [gifsicle](https://github.com/kohler/gifsicle) is used, and for converting GIF to WebP — [gif2webp](https://developers.google.com/speed/webp/docs/gif2webp). +SVG is processed by [svgo](https://github.com/svg/svgo), while for GIF, [gifsicle](https://github.com/kohler/gifsicle) is used. > [!NOTE] > In Lossless mode for JPEG, we use [Guetzli](https://github.com/google/guetzli), which offers high level of compression with good visual quality. However, repeated optimization may degrade visual quality. diff --git a/README.ru.md b/README.ru.md index 86522cb..bfb8ae2 100644 --- a/README.ru.md +++ b/README.ru.md @@ -72,9 +72,9 @@ find . -iname \*.jpg -exec optimizt {} + ## Конфигурация -Операции с [JPEG](https://sharp.pixelplumbing.com/api-output#jpeg), [PNG](https://sharp.pixelplumbing.com/api-output#png), [WebP](https://sharp.pixelplumbing.com/api-output#webp) и [AVIF](https://sharp.pixelplumbing.com/api-output#avif) производятся с помощью библиотеки [sharp](https://github.com/lovell/sharp), а SVG обрабатывается с помощью утилиты [svgo](https://github.com/svg/svgo). +Операции с [JPEG](https://sharp.pixelplumbing.com/api-output#jpeg), [PNG](https://sharp.pixelplumbing.com/api-output#png), [WebP](https://sharp.pixelplumbing.com/api-output#webp) и [AVIF](https://sharp.pixelplumbing.com/api-output#avif) производятся с помощью библиотеки [sharp](https://github.com/lovell/sharp). -Для оптимизации GIF используется [gifsicle](https://github.com/kohler/gifsicle), а для конвертации GIF в WebP — [gif2webp](https://developers.google.com/speed/webp/docs/gif2webp). +SVG обрабатывается с помощью утилиты [svgo](https://github.com/svg/svgo), а для оптимизации GIF используется [gifsicle](https://github.com/kohler/gifsicle). > [!NOTE] > В режиме Lossless для оптимизации JPEG используется энкодер [Guetzli](https://github.com/google/guetzli), который позволяет получить высокий уровень компрессии и при этом сохранить хорошее визуальное качество изображения. Но, нужно иметь в виду, что при повторной оптимизации файла размер может уменьшаться за счёт деградации визуального качества изображения. diff --git a/convert.js b/convert.js index bd0795e..d1ecc0c 100644 --- a/convert.js +++ b/convert.js @@ -2,8 +2,6 @@ import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; -import execBuffer from 'exec-buffer'; -import gif2webp from 'gif2webp-bin'; import pLimit from 'p-limit'; import sharp from 'sharp'; @@ -20,7 +18,6 @@ import { logProgress, logProgressVerbose, } from './lib/log.js'; -import { optionsToArguments } from './lib/options-to-arguments.js'; import { parseImageMetadata } from './lib/parse-image-metadata.js'; import { programOptions } from './lib/program-options.js'; import { showTotal } from './lib/show-total.js'; @@ -53,7 +50,6 @@ export async function convert({ filePaths, config }) { const avifConfig = getConfig('avif'); const webpConfig = getConfig('webp'); - const webpGifConfig = getConfig('webpGif'); const cpuCount = os.cpus().length; const tasksSimultaneousLimit = pLimit(cpuCount); @@ -78,13 +74,11 @@ export async function convert({ filePaths, config }) { } if (shouldConvertToWebp) { - const isGif = path.extname(filePath.input).toLowerCase() === '.gif'; - accumulator.push( tasksSimultaneousLimit( () => processFile({ filePath, - config: (isGif ? webpGifConfig : webpConfig) || {}, + config: webpConfig || {}, progressBarContainer, progressBar, totalSize, @@ -187,23 +181,9 @@ async function processWebp({ fileBuffer, config }) { const imageMetadata = await parseImageMetadata(fileBuffer); checkImageFormat(imageMetadata.format); - if (imageMetadata.format === 'gif') { - return execBuffer({ - bin: gif2webp, - args: [ - ...optionsToArguments({ - options: config, - prefix: '-', - }), - execBuffer.input, - '-o', - execBuffer.output, - ], - input: fileBuffer, - }); - } + const isAnimated = imageMetadata.pages > 1; - return sharp(fileBuffer) + return sharp(fileBuffer, { animated: isAnimated }) .rotate() // Rotate image using information from EXIF Orientation tag .webp(config) .toBuffer(); diff --git a/package-lock.json b/package-lock.json index 8acac49..4837dec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@343dev/optimizt", - "version": "9.1.1", + "version": "10.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@343dev/optimizt", - "version": "9.1.1", + "version": "10.0.0", "license": "MIT", "dependencies": { "@343dev/guetzli": "^1.0.1", @@ -14,10 +14,9 @@ "commander": "^12.1.0", "exec-buffer": "^3.2.0", "fdir": "^6.4.0", - "gif2webp-bin": "^5.0.0", - "gifsicle": "^7.0.0", + "gifsicle": "^7.0.1", "p-limit": "^6.1.0", - "sharp": "^0.33.4", + "sharp": "^0.33.5", "svgo": "^3.3.2" }, "bin": { @@ -799,9 +798,9 @@ } }, "node_modules/@img/sharp-darwin-arm64": { - "version": "0.33.4", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.4.tgz", - "integrity": "sha512-p0suNqXufJs9t3RqLBO6vvrgr5OhgbWp76s5gTRvdmxmuv9E1rcaqGUsl3l4mKVmXPkTkTErXediAui4x+8PSA==", + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", + "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", "cpu": [ "arm64" ], @@ -811,23 +810,19 @@ "darwin" ], "engines": { - "glibc": ">=2.26", - "node": "^18.17.0 || ^20.3.0 || >=21.0.0", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.0.2" + "@img/sharp-libvips-darwin-arm64": "1.0.4" } }, "node_modules/@img/sharp-darwin-x64": { - "version": "0.33.4", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.4.tgz", - "integrity": "sha512-0l7yRObwtTi82Z6ebVI2PnHT8EB2NxBgpK2MiKJZJ7cz32R4lxd001ecMhzzsZig3Yv9oclvqqdV93jo9hy+Dw==", + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", + "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", "cpu": [ "x64" ], @@ -837,23 +832,19 @@ "darwin" ], "engines": { - "glibc": ">=2.26", - "node": "^18.17.0 || ^20.3.0 || >=21.0.0", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.0.2" + "@img/sharp-libvips-darwin-x64": "1.0.4" } }, "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.2.tgz", - "integrity": "sha512-tcK/41Rq8IKlSaKRCCAuuY3lDJjQnYIW1UXU1kxcEKrfL8WR7N6+rzNoOxoQRJWTAECuKwgAHnPvqXGN8XfkHA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", + "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", "cpu": [ "arm64" ], @@ -862,20 +853,14 @@ "os": [ "darwin" ], - "engines": { - "macos": ">=11", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" - }, "funding": { "url": "https://opencollective.com/libvips" } }, "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.2.tgz", - "integrity": "sha512-Ofw+7oaWa0HiiMiKWqqaZbaYV3/UGL2wAPeLuJTx+9cXpCRdvQhCLG0IH8YGwM0yGWGLpsF4Su9vM1o6aer+Fw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", + "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", "cpu": [ "x64" ], @@ -884,20 +869,14 @@ "os": [ "darwin" ], - "engines": { - "macos": ">=10.13", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" - }, "funding": { "url": "https://opencollective.com/libvips" } }, "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.2.tgz", - "integrity": "sha512-iLWCvrKgeFoglQxdEwzu1eQV04o8YeYGFXtfWU26Zr2wWT3q3MTzC+QTCO3ZQfWd3doKHT4Pm2kRmLbupT+sZw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", + "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", "cpu": [ "arm" ], @@ -906,20 +885,14 @@ "os": [ "linux" ], - "engines": { - "glibc": ">=2.28", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" - }, "funding": { "url": "https://opencollective.com/libvips" } }, "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.2.tgz", - "integrity": "sha512-x7kCt3N00ofFmmkkdshwj3vGPCnmiDh7Gwnd4nUwZln2YjqPxV1NlTyZOvoDWdKQVDL911487HOueBvrpflagw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", + "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", "cpu": [ "arm64" ], @@ -928,20 +901,14 @@ "os": [ "linux" ], - "engines": { - "glibc": ">=2.26", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" - }, "funding": { "url": "https://opencollective.com/libvips" } }, "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.2.tgz", - "integrity": "sha512-cmhQ1J4qVhfmS6szYW7RT+gLJq9dH2i4maq+qyXayUSn9/3iY2ZeWpbAgSpSVbV2E1JUL2Gg7pwnYQ1h8rQIog==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", + "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", "cpu": [ "s390x" ], @@ -950,20 +917,14 @@ "os": [ "linux" ], - "engines": { - "glibc": ">=2.28", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" - }, "funding": { "url": "https://opencollective.com/libvips" } }, "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.2.tgz", - "integrity": "sha512-E441q4Qdb+7yuyiADVi5J+44x8ctlrqn8XgkDTwr4qPJzWkaHwD489iZ4nGDgcuya4iMN3ULV6NwbhRZJ9Z7SQ==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", + "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", "cpu": [ "x64" ], @@ -972,20 +933,14 @@ "os": [ "linux" ], - "engines": { - "glibc": ">=2.26", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" - }, "funding": { "url": "https://opencollective.com/libvips" } }, "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.2.tgz", - "integrity": "sha512-3CAkndNpYUrlDqkCM5qhksfE+qSIREVpyoeHIU6jd48SJZViAmznoQQLAv4hVXF7xyUB9zf+G++e2v1ABjCbEQ==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", + "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", "cpu": [ "arm64" ], @@ -994,20 +949,14 @@ "os": [ "linux" ], - "engines": { - "musl": ">=1.2.2", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" - }, "funding": { "url": "https://opencollective.com/libvips" } }, "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.2.tgz", - "integrity": "sha512-VI94Q6khIHqHWNOh6LLdm9s2Ry4zdjWJwH56WoiJU7NTeDwyApdZZ8c+SADC8OH98KWNQXnE01UdJ9CSfZvwZw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", + "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", "cpu": [ "x64" ], @@ -1016,20 +965,14 @@ "os": [ "linux" ], - "engines": { - "musl": ">=1.2.2", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" - }, "funding": { "url": "https://opencollective.com/libvips" } }, "node_modules/@img/sharp-linux-arm": { - "version": "0.33.4", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.4.tgz", - "integrity": "sha512-RUgBD1c0+gCYZGCCe6mMdTiOFS0Zc/XrN0fYd6hISIKcDUbAW5NtSQW9g/powkrXYm6Vzwd6y+fqmExDuCdHNQ==", + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", + "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", "cpu": [ "arm" ], @@ -1039,23 +982,19 @@ "linux" ], "engines": { - "glibc": ">=2.28", - "node": "^18.17.0 || ^20.3.0 || >=21.0.0", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.0.2" + "@img/sharp-libvips-linux-arm": "1.0.5" } }, "node_modules/@img/sharp-linux-arm64": { - "version": "0.33.4", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.4.tgz", - "integrity": "sha512-2800clwVg1ZQtxwSoTlHvtm9ObgAax7V6MTAB/hDT945Tfyy3hVkmiHpeLPCKYqYR1Gcmv1uDZ3a4OFwkdBL7Q==", + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", + "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", "cpu": [ "arm64" ], @@ -1065,23 +1004,19 @@ "linux" ], "engines": { - "glibc": ">=2.26", - "node": "^18.17.0 || ^20.3.0 || >=21.0.0", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.0.2" + "@img/sharp-libvips-linux-arm64": "1.0.4" } }, "node_modules/@img/sharp-linux-s390x": { - "version": "0.33.4", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.4.tgz", - "integrity": "sha512-h3RAL3siQoyzSoH36tUeS0PDmb5wINKGYzcLB5C6DIiAn2F3udeFAum+gj8IbA/82+8RGCTn7XW8WTFnqag4tQ==", + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", + "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", "cpu": [ "s390x" ], @@ -1091,23 +1026,19 @@ "linux" ], "engines": { - "glibc": ">=2.31", - "node": "^18.17.0 || ^20.3.0 || >=21.0.0", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.0.2" + "@img/sharp-libvips-linux-s390x": "1.0.4" } }, "node_modules/@img/sharp-linux-x64": { - "version": "0.33.4", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.4.tgz", - "integrity": "sha512-GoR++s0XW9DGVi8SUGQ/U4AeIzLdNjHka6jidVwapQ/JebGVQIpi52OdyxCNVRE++n1FCLzjDovJNozif7w/Aw==", + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", + "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", "cpu": [ "x64" ], @@ -1117,23 +1048,19 @@ "linux" ], "engines": { - "glibc": ">=2.26", - "node": "^18.17.0 || ^20.3.0 || >=21.0.0", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.0.2" + "@img/sharp-libvips-linux-x64": "1.0.4" } }, "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.33.4", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.4.tgz", - "integrity": "sha512-nhr1yC3BlVrKDTl6cO12gTpXMl4ITBUZieehFvMntlCXFzH2bvKG76tBL2Y/OqhupZt81pR7R+Q5YhJxW0rGgQ==", + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", + "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", "cpu": [ "arm64" ], @@ -1143,23 +1070,19 @@ "linux" ], "engines": { - "musl": ">=1.2.2", - "node": "^18.17.0 || ^20.3.0 || >=21.0.0", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.0.2" + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" } }, "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.33.4", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.4.tgz", - "integrity": "sha512-uCPTku0zwqDmZEOi4ILyGdmW76tH7dm8kKlOIV1XC5cLyJ71ENAAqarOHQh0RLfpIpbV5KOpXzdU6XkJtS0daw==", + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", + "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", "cpu": [ "x64" ], @@ -1169,45 +1092,38 @@ "linux" ], "engines": { - "musl": ">=1.2.2", - "node": "^18.17.0 || ^20.3.0 || >=21.0.0", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.0.2" + "@img/sharp-libvips-linuxmusl-x64": "1.0.4" } }, "node_modules/@img/sharp-wasm32": { - "version": "0.33.4", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.4.tgz", - "integrity": "sha512-Bmmauh4sXUsUqkleQahpdNXKvo+wa1V9KhT2pDA4VJGKwnKMJXiSTGphn0gnJrlooda0QxCtXc6RX1XAU6hMnQ==", + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", + "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", "cpu": [ "wasm32" ], "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", "optional": true, "dependencies": { - "@emnapi/runtime": "^1.1.1" + "@emnapi/runtime": "^1.2.0" }, "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { "url": "https://opencollective.com/libvips" } }, "node_modules/@img/sharp-win32-ia32": { - "version": "0.33.4", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.4.tgz", - "integrity": "sha512-99SJ91XzUhYHbx7uhK3+9Lf7+LjwMGQZMDlO/E/YVJ7Nc3lyDFZPGhjwiYdctoH2BOzW9+TnfqcaMKt0jHLdqw==", + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", + "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", "cpu": [ "ia32" ], @@ -1217,19 +1133,16 @@ "win32" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { "url": "https://opencollective.com/libvips" } }, "node_modules/@img/sharp-win32-x64": { - "version": "0.33.4", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.4.tgz", - "integrity": "sha512-3QLocdTRVIrFNye5YocZl+KKpYKP+fksi1QhmOArgx7GyhIbQp/WrJRu176jm8IxromS7RIkzMiMINVdBtC8Aw==", + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", + "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", "cpu": [ "x64" ], @@ -1239,10 +1152,7 @@ "win32" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0", - "npm": ">=9.6.5", - "pnpm": ">=7.1.0", - "yarn": ">=3.2.0" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { "url": "https://opencollective.com/libvips" @@ -5155,23 +5065,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/gif2webp-bin": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/gif2webp-bin/-/gif2webp-bin-5.0.0.tgz", - "integrity": "sha512-jZNnxuird124c3OIVRTra7htJowYyxKx4oUeNxfEkzgeOqseWCyw61TvzbTVyklwxmyZwDojwkaPeKItmZvppw==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "bin-build": "^3.0.0", - "bin-wrapper": "^4.0.0" - }, - "bin": { - "gif2webp": "cli.js" - }, - "engines": { - "node": "^14.13.1 || >=16.0.0" - } - }, "node_modules/gifsicle": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/gifsicle/-/gifsicle-7.0.1.tgz", @@ -8924,43 +8817,42 @@ } }, "node_modules/sharp": { - "version": "0.33.4", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.4.tgz", - "integrity": "sha512-7i/dt5kGl7qR4gwPRD2biwD2/SvBn3O04J77XKFgL2OnZtQw+AG9wnuS/csmu80nPRHLYE9E41fyEiG8nhH6/Q==", + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", + "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.3", - "semver": "^7.6.0" + "semver": "^7.6.3" }, "engines": { - "libvips": ">=8.15.2", "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.33.4", - "@img/sharp-darwin-x64": "0.33.4", - "@img/sharp-libvips-darwin-arm64": "1.0.2", - "@img/sharp-libvips-darwin-x64": "1.0.2", - "@img/sharp-libvips-linux-arm": "1.0.2", - "@img/sharp-libvips-linux-arm64": "1.0.2", - "@img/sharp-libvips-linux-s390x": "1.0.2", - "@img/sharp-libvips-linux-x64": "1.0.2", - "@img/sharp-libvips-linuxmusl-arm64": "1.0.2", - "@img/sharp-libvips-linuxmusl-x64": "1.0.2", - "@img/sharp-linux-arm": "0.33.4", - "@img/sharp-linux-arm64": "0.33.4", - "@img/sharp-linux-s390x": "0.33.4", - "@img/sharp-linux-x64": "0.33.4", - "@img/sharp-linuxmusl-arm64": "0.33.4", - "@img/sharp-linuxmusl-x64": "0.33.4", - "@img/sharp-wasm32": "0.33.4", - "@img/sharp-win32-ia32": "0.33.4", - "@img/sharp-win32-x64": "0.33.4" + "@img/sharp-darwin-arm64": "0.33.5", + "@img/sharp-darwin-x64": "0.33.5", + "@img/sharp-libvips-darwin-arm64": "1.0.4", + "@img/sharp-libvips-darwin-x64": "1.0.4", + "@img/sharp-libvips-linux-arm": "1.0.5", + "@img/sharp-libvips-linux-arm64": "1.0.4", + "@img/sharp-libvips-linux-s390x": "1.0.4", + "@img/sharp-libvips-linux-x64": "1.0.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", + "@img/sharp-libvips-linuxmusl-x64": "1.0.4", + "@img/sharp-linux-arm": "0.33.5", + "@img/sharp-linux-arm64": "0.33.5", + "@img/sharp-linux-s390x": "0.33.5", + "@img/sharp-linux-x64": "0.33.5", + "@img/sharp-linuxmusl-arm64": "0.33.5", + "@img/sharp-linuxmusl-x64": "0.33.5", + "@img/sharp-wasm32": "0.33.5", + "@img/sharp-win32-ia32": "0.33.5", + "@img/sharp-win32-x64": "0.33.5" } }, "node_modules/shebang-command": { diff --git a/package.json b/package.json index 882d0af..68e4884 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@343dev/optimizt", - "version": "9.1.1", + "version": "10.0.0", "description": "CLI image optimization tool", "keywords": [ "svg", @@ -13,8 +13,7 @@ "sharp", "svgo", "gifsicle", - "guetzli", - "gif2webp" + "guetzli" ], "license": "MIT", "author": "Andrey Warkentin (https://github.com/343dev)", @@ -51,10 +50,9 @@ "commander": "^12.1.0", "exec-buffer": "^3.2.0", "fdir": "^6.4.0", - "gif2webp-bin": "^5.0.0", - "gifsicle": "^7.0.0", + "gifsicle": "^7.0.1", "p-limit": "^6.1.0", - "sharp": "^0.33.4", + "sharp": "^0.33.5", "svgo": "^3.3.2" }, "devDependencies": { diff --git a/tests/cli.test.js b/tests/cli.test.js index 3835ea3..d3818cd 100644 --- a/tests/cli.test.js +++ b/tests/cli.test.js @@ -134,7 +134,7 @@ describe('CLI', () => { const stdout = runCliWithParameters(`--avif ${workDirectory}${file}`); expectFileRatio({ - stdout, file, maxRatio: 90, minRatio: 85, outputExt: 'avif', + stdout, file, maxRatio: 85, minRatio: 80, outputExt: 'avif', }); expectFileNotModified(file); }); @@ -164,7 +164,7 @@ describe('CLI', () => { const stdoutRatio = grepTotalRatio(stdout); expectStringContains(stdout, 'Converting 6 images (lossy)...'); - expectRatio(stdoutRatio, 85, 95); + expectRatio(stdoutRatio, 80, 85); expectFileNotModified(`${fileBasename}.png`); expectFileExists(`${fileBasename}.avif`); }); @@ -179,7 +179,7 @@ describe('CLI', () => { const stdout = runCliWithParameters(`--avif --lossless ${workDirectory}${file}`); expectFileRatio({ - stdout, file, maxRatio: 40, minRatio: 35, outputExt: 'avif', + stdout, file, maxRatio: 30, minRatio: 25, outputExt: 'avif', }); expectFileNotModified(file); }); @@ -199,7 +199,7 @@ describe('CLI', () => { const stdoutRatio = grepTotalRatio(stdout); expectStringContains(stdout, 'Converting 6 images (lossless)...'); - expectRatio(stdoutRatio, 27, 31); + expectRatio(stdoutRatio, 15, 20); expectFileNotModified(`${fileBasename}.png`); expectFileExists(`${fileBasename}.avif`); @@ -236,7 +236,7 @@ describe('CLI', () => { const stdout = runCliWithParameters(`--webp ${workDirectory}${file}`); expectFileRatio({ - stdout, file, maxRatio: 40, minRatio: 35, outputExt: 'webp', + stdout, file, maxRatio: 30, minRatio: 25, outputExt: 'webp', }); expectFileNotModified(file); }); @@ -259,7 +259,7 @@ describe('CLI', () => { const stdout = runCliWithParameters(`--webp --lossless ${workDirectory}${file}`); expectFileRatio({ - stdout, file, maxRatio: 80, minRatio: 75, outputExt: 'webp', + stdout, file, maxRatio: 85, minRatio: 80, outputExt: 'webp', }); expectFileNotModified(file); }); @@ -269,7 +269,7 @@ describe('CLI', () => { const stdout = runCliWithParameters(`--webp --lossless ${workDirectory}${file}`); expectFileRatio({ - stdout, file, maxRatio: 45, minRatio: 40, outputExt: 'webp', + stdout, file, maxRatio: 50, minRatio: 45, outputExt: 'webp', }); expectFileNotModified(file); }); @@ -321,7 +321,7 @@ describe('CLI', () => { expectStringContains(stdout, 'Converting 1 image (lossless)...'); expectStringContains(stdout, path.join(temporary, `${fileBasename}.png`)); - expectRatio(stdoutRatio, 40, 45); + expectRatio(stdoutRatio, 35, 40); expectFileNotModified(`${fileBasename}.png`); expectFileExists(`${fileBasename}.avif`); expectFileExists(`${fileBasename}.webp`);