image-guard 5.2.0 → 5.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/README.md +2 -2
- package/bin/image-guard.test.js +6 -1
- package/package.json +1 -1
- package/src/utils.js +5 -8
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,14 @@ Starting with version 5.2.0, all notable changes to Image Guard are documented i
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [5.2.1] - 2026-02-17
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
* HEIC-to-AVIF conversion now uses lossy encoding (quality 80) instead of lossless, producing files smaller than the HEIC originals
|
|
12
|
+
* Removed redundant lossless compression pass after HEIC conversion
|
|
13
|
+
* Documented Display P3 to sRGB color space mapping during HEIC conversion
|
|
14
|
+
|
|
7
15
|
## [5.2.0] - 2026-02-17
|
|
8
16
|
|
|
9
17
|
### Added
|
package/README.md
CHANGED
|
@@ -111,7 +111,7 @@ npm pkg set scripts.postprepare="grep -qxF 'npx image-guard --staged' .husky/pre
|
|
|
111
111
|
|
|
112
112
|
* `--staged` (recommended with automated use) triggers a mode that watches PNG, JPG, GIF, WebP, and AVIF files (and HEIC/HEIF, when `--heic-to-avif` is used) in `git diff` and only processes those files—that approach makes Image Guard more efficient in operation.
|
|
113
113
|
|
|
114
|
-
* `--heic-to-avif` converts HEIC/HEIF files to
|
|
114
|
+
* `--heic-to-avif` converts HEIC/HEIF files to AVIF. Because HEIC sources are already lossy-compressed (HEVC), the conversion uses lossy AVIF encoding (quality 80) to produce files smaller than the originals at near-identical visual quality. Original HEIC/HEIF files are deleted after conversion by default. (Note: The conversion maps Display P3 colors—common on iPhones—to sRGB, which may result in slightly less vivid colors.)
|
|
115
115
|
|
|
116
116
|
- `--keep-heic` (used with `--heic-to-avif`) preserves the original HEIC/HEIF files instead of deleting them after conversion.
|
|
117
117
|
|
|
@@ -148,7 +148,7 @@ Tip: Use `--quiet` to suppress these per‑file lines and keep only the final su
|
|
|
148
148
|
|
|
149
149
|
Image Guard is a Node script that uses [sharp](https://www.npmjs.com/package/sharp) under the hood.
|
|
150
150
|
|
|
151
|
-
Automated compression works by monitoring whether a given [change list](https://webglossary.info/terms/change-list/) includes any PNGs, JPGs, GIFs, WebPs, or AVIFs (and HEIC/HEIF when opted in). It’s initiated by a Git hook. Only those images are compressed where there is an improvement. HEIC conversion uses [heic-decode](https://www.npmjs.com/package/heic-decode) for patent-free decoding and sharp for AVIF encoding. The processed images can then be committed to the underlying repository.
|
|
151
|
+
Automated compression works by monitoring whether a given [change list](https://webglossary.info/terms/change-list/) includes any PNGs, JPGs, GIFs, WebPs, or AVIFs (and HEIC/HEIF when opted in). It’s initiated by a Git hook. Only those images are compressed where there is an improvement. HEIC conversion uses [heic-decode](https://www.npmjs.com/package/heic-decode) for patent-free decoding and sharp for lossy AVIF encoding (quality 80). The processed images can then be committed to the underlying repository.
|
|
152
152
|
|
|
153
153
|
Through this approach, though glossed over here, Image Guard makes up for what’s missing or complicated in other packages, namely easy, near-riskless, automatable, resource-friendly in-repo optimization.
|
|
154
154
|
|
package/bin/image-guard.test.js
CHANGED
|
@@ -415,7 +415,12 @@ describe('Image Guard', () => {
|
|
|
415
415
|
|
|
416
416
|
// AVIF should be created by the conversion
|
|
417
417
|
assert.strictEqual(fs.existsSync(avifFile), true, 'AVIF file should be created')
|
|
418
|
-
|
|
418
|
+
const avifSize = fs.statSync(avifFile).size
|
|
419
|
+
assert.ok(avifSize > 0, 'AVIF file should not be empty')
|
|
420
|
+
|
|
421
|
+
// Lossy AVIF should not be larger than the HEIC source
|
|
422
|
+
const heicSize = fs.statSync(path.join(testFolder, 'test.heic')).size
|
|
423
|
+
assert.ok(avifSize <= heicSize, `AVIF (${avifSize}) should not be larger than HEIC (${heicSize})`)
|
|
419
424
|
|
|
420
425
|
// Original HEIC should be deleted
|
|
421
426
|
assert.strictEqual(fs.existsSync(heicFile), false, 'Original HEIC should be deleted')
|
package/package.json
CHANGED
package/src/utils.js
CHANGED
|
@@ -232,25 +232,22 @@ const conversion = async (filename, dry, keepOriginal, quiet = false) => {
|
|
|
232
232
|
return 0
|
|
233
233
|
}
|
|
234
234
|
|
|
235
|
-
// Encode as
|
|
235
|
+
// Encode as lossy AVIF—HEIC sources are already lossy (HEVC), so lossless
|
|
236
|
+
// re-encoding would inflate file sizes without any quality benefit
|
|
236
237
|
await sharp(data, { raw: { width, height, channels: 4 } })
|
|
237
|
-
.toFormat('avif', {
|
|
238
|
+
.toFormat('avif', { quality: 80, effort: 5 })
|
|
238
239
|
.toFile(avifPath)
|
|
239
240
|
|
|
240
241
|
const fileSizeAfter = await size(avifPath)
|
|
241
242
|
|
|
242
243
|
logMessage(`Converted ${filename} → ${path.basename(avifPath)} (${sizeReadable(fileSizeBefore)} → ${sizeReadable(fileSizeAfter)})`, dry, 'cyan', quiet)
|
|
243
244
|
|
|
244
|
-
//
|
|
245
|
-
const saved = await compression(avifPath, dry, quiet)
|
|
246
|
-
|
|
247
|
-
// Delete original HEIC/HEIF file unless --keep-heic is set (deferred until after compression succeeds)
|
|
245
|
+
// Delete original HEIC/HEIF file unless `--keep-heic` is set
|
|
248
246
|
if (!keepOriginal) {
|
|
249
247
|
await retryFileOperation(() => fs.promises.unlink(filename))
|
|
250
248
|
}
|
|
251
249
|
|
|
252
|
-
|
|
253
|
-
return saved
|
|
250
|
+
return fileSizeAfter < fileSizeBefore ? fileSizeBefore - fileSizeAfter : 0
|
|
254
251
|
|
|
255
252
|
} catch (err) {
|
|
256
253
|
// Clean up partial AVIF if it was created
|