Skip to content

Commit 9269bf2

Browse files
matmenclaude
andcommitted
Lossy WebP encoder: default to effort 2
Effort 3 and up add the full rate-distortion search of the intra 4x4 modes: on a 1920x1080 photo at quality 75, effort 2 takes ~245 ms for 101.6 kB (38.87 dB), effort 4 ~905 ms for 96.6 kB (39.32 dB). The default becomes 2 for images and animations; effort 4 still encodes like cwebp's default. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lfv41PqHEGbU7SLg5onpG1
1 parent d09456f commit 9269bf2

3 files changed

Lines changed: 8 additions & 5 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010

1111
### Improvements
1212

13+
- Lossy WebP encoding defaults to `effort: 2` instead of 4: about a quarter of the time (about 250 ms instead of
14+
900 ms for a 1920x1080 photo) for files about 5% larger at a slightly lower quality (about 0.5 dB PSNR).
15+
`effort: 4` encodes like cwebp's default as before.
1316
- AVIF encoding also tries splitting blocks into halves (horizontal or vertical, from 64x64 to 16x16) where the whole
1417
block and its quarters cost about the same: files about 2% smaller at the default effort, encoding about 20% slower.
1518
- AVIF encoding with `effort: 2` also chooses smaller transforms within blocks (transform depth): files about 1% smaller

‎src/animation.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export interface WebPAnimationEncodeOptions extends AnimationEncodeOptions {
6262
* frames are lossless
6363
*/
6464
quality?: number;
65-
/** How much effort lossy frames take (0-6), see {@link WebPEncodeOptions.effort}. Default: `4` */
65+
/** How much effort lossy frames take (0-6), see {@link WebPEncodeOptions.effort}. Default: `2` */
6666
effort?: number;
6767
}
6868

@@ -287,7 +287,7 @@ export class Animation extends Array<Frame> {
287287
* shows the same animation, but doesn't necessarily decode to the same frames
288288
* @param options See {@link WebPAnimationEncodeOptions}
289289
*/
290-
async encodeWebP({ metadata = {}, optimize = true, quality, effort = 4 }: WebPAnimationEncodeOptions = {}): Promise<Uint8Array> {
290+
async encodeWebP({ metadata = {}, optimize = true, quality, effort = 2 }: WebPAnimationEncodeOptions = {}): Promise<Uint8Array> {
291291
this.__validate__();
292292
if (!this.length) throw new Error('An animation needs at least one frame');
293293
if (quality !== undefined) {

‎src/image.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,13 +106,13 @@ export interface JPEGEncodeOptions {
106106
export interface WebPEncodeOptions {
107107
/**
108108
* Lossy compression (0-100, like libwebp's quality: 75 is its default): the image is encoded like cwebp encodes it
109-
* with its default settings, much smaller than lossless. Without it the image is encoded losslessly
109+
* (with `-m` set to the effort), much smaller than lossless. Without it the image is encoded losslessly
110110
*/
111111
quality?: number;
112112
/**
113113
* How much effort lossy compression takes (0-6, libwebp's method): higher is smaller but slower. 0-2 pick the
114114
* predictions by how close they are, 3 and up also by how many bits they take, 5 and 6 also optimize the
115-
* quantized values. Default: `4` (like cwebp)
115+
* quantized values. Default: `2`: about a quarter of the time of 4 (cwebp's default) for files about 5% larger
116116
*/
117117
effort?: number;
118118
/** Metadata to include, see {@link Metadata} */
@@ -2045,7 +2045,7 @@ export class Image {
20452045
* quality
20462046
* @param options See {@link WebPEncodeOptions}
20472047
*/
2048-
async encodeWebP({ quality, effort = 4, metadata = {} }: WebPEncodeOptions = {}): Promise<Uint8Array> {
2048+
async encodeWebP({ quality, effort = 2, metadata = {} }: WebPEncodeOptions = {}): Promise<Uint8Array> {
20492049
const exif = exifData(resolveMetadata(metadata));
20502050
if (quality === undefined) return webp.encode(this.__bytes__(), this.width, this.height, exif);
20512051
const q = finite(quality, 'quality');

0 commit comments

Comments
 (0)