mirror of
https://github.com/GoogleChromeLabs/squoosh.git
synced 2025-11-15 10:09:45 +00:00
Add node version to AVIF
This commit is contained in:
@@ -1,62 +1,62 @@
|
||||
import { promises as fsp } from "fs";
|
||||
import { instantiateEmscriptenWasm, pathify } from "./emscripten-utils.js";
|
||||
import { promises as fsp } from 'fs';
|
||||
import { instantiateEmscriptenWasm, pathify } from './emscripten-utils.js';
|
||||
|
||||
// MozJPEG
|
||||
import mozEnc from "../../codecs/mozjpeg/enc/mozjpeg_enc.js";
|
||||
import mozEncWasm from "asset-url:../../codecs/mozjpeg/enc/mozjpeg_enc.wasm";
|
||||
import mozDec from "../../codecs/mozjpeg/dec/mozjpeg_dec.js";
|
||||
import mozDecWasm from "asset-url:../../codecs/mozjpeg/dec/mozjpeg_dec.wasm";
|
||||
// import mozEnc from '../../codecs/mozjpeg/enc/mozjpeg_enc.js';
|
||||
// import mozEncWasm from 'asset-url:../../codecs/mozjpeg/enc/mozjpeg_enc.wasm';
|
||||
// import mozDec from '../../codecs/mozjpeg/dec/mozjpeg_dec.js';
|
||||
// import mozDecWasm from 'asset-url:../../codecs/mozjpeg/dec/mozjpeg_dec.wasm';
|
||||
|
||||
// WebP
|
||||
import webpEnc from "../../codecs/webp/enc/webp_enc.js";
|
||||
import webpEncWasm from "asset-url:../../codecs/webp/enc/webp_enc.wasm";
|
||||
import webpDec from "../../codecs/webp/dec/webp_dec.js";
|
||||
import webpDecWasm from "asset-url:../../codecs/webp/dec/webp_dec.wasm";
|
||||
import webpEnc from '../../codecs/webp/enc/webp_enc.js';
|
||||
import webpEncWasm from 'asset-url:../../codecs/webp/enc/webp_enc.wasm';
|
||||
import webpDec from '../../codecs/webp/dec/webp_dec.js';
|
||||
import webpDecWasm from 'asset-url:../../codecs/webp/dec/webp_dec.wasm';
|
||||
|
||||
// AVIF
|
||||
import avifEnc from "../../codecs/avif/enc/avif_enc.js";
|
||||
import avifEncWasm from "asset-url:../../codecs/avif/enc/avif_enc.wasm";
|
||||
import avifDec from "../../codecs/avif/dec/avif_dec.js";
|
||||
import avifDecWasm from "asset-url:../../codecs/avif/dec/avif_dec.wasm";
|
||||
import avifEnc from '../../codecs/avif/enc/avif_node_enc.js';
|
||||
import avifEncWasm from 'asset-url:../../codecs/avif/enc/avif_node_enc.wasm';
|
||||
import avifDec from '../../codecs/avif/dec/avif_node_dec.js';
|
||||
import avifDecWasm from 'asset-url:../../codecs/avif/dec/avif_node_dec.wasm';
|
||||
|
||||
// PNG
|
||||
import * as pngEncDec from "../../codecs/png/pkg/squoosh_png.js";
|
||||
import pngEncDecWasm from "asset-url:../../codecs/png/pkg/squoosh_png_bg.wasm";
|
||||
const pngEncDecPromise = pngEncDec.default(
|
||||
fsp.readFile(pathify(pngEncDecWasm))
|
||||
);
|
||||
import * as pngEncDec from '../../codecs/png/pkg/squoosh_png.js';
|
||||
import pngEncDecWasm from 'asset-url:../../codecs/png/pkg/squoosh_png_bg.wasm';
|
||||
// const pngEncDecPromise = pngEncDec.default(
|
||||
// fsp.readFile(pathify(pngEncDecWasm))
|
||||
// );
|
||||
|
||||
// OxiPNG
|
||||
import * as oxipng from "../../codecs/oxipng/pkg/squoosh_oxipng.js";
|
||||
import oxipngWasm from "asset-url:../../codecs/oxipng/pkg/squoosh_oxipng_bg.wasm";
|
||||
const oxipngPromise = oxipng.default(fsp.readFile(pathify(oxipngWasm)));
|
||||
import * as oxipng from '../../codecs/oxipng/pkg/squoosh_oxipng.js';
|
||||
import oxipngWasm from 'asset-url:../../codecs/oxipng/pkg/squoosh_oxipng_bg.wasm';
|
||||
// const oxipngPromise = oxipng.default(fsp.readFile(pathify(oxipngWasm)));
|
||||
|
||||
// Resize
|
||||
import * as resize from "../../codecs/resize/pkg/squoosh_resize.js";
|
||||
import resizeWasm from "asset-url:../../codecs/resize/pkg/squoosh_resize_bg.wasm";
|
||||
const resizePromise = resize.default(fsp.readFile(pathify(resizeWasm)));
|
||||
import * as resize from '../../codecs/resize/pkg/squoosh_resize.js';
|
||||
import resizeWasm from 'asset-url:../../codecs/resize/pkg/squoosh_resize_bg.wasm';
|
||||
// const resizePromise = resize.default(fsp.readFile(pathify(resizeWasm)));
|
||||
|
||||
// rotate
|
||||
import rotateWasm from "asset-url:../../codecs/rotate/rotate.wasm";
|
||||
import rotateWasm from 'asset-url:../../codecs/rotate/rotate.wasm';
|
||||
|
||||
// ImageQuant
|
||||
import imageQuant from "../../codecs/imagequant/imagequant.js";
|
||||
import imageQuantWasm from "asset-url:../../codecs/imagequant/imagequant.wasm";
|
||||
const imageQuantPromise = instantiateEmscriptenWasm(imageQuant, imageQuantWasm);
|
||||
import imageQuant from '../../codecs/imagequant/imagequant.js';
|
||||
import imageQuantWasm from 'asset-url:../../codecs/imagequant/imagequant.wasm';
|
||||
// const imageQuantPromise = instantiateEmscriptenWasm(imageQuant, imageQuantWasm);
|
||||
|
||||
// Our decoders currently rely on a `ImageData` global.
|
||||
import ImageData from "./image_data.js";
|
||||
import ImageData from './image_data.js';
|
||||
globalThis.ImageData = ImageData;
|
||||
|
||||
function resizeNameToIndex(name) {
|
||||
switch (name) {
|
||||
case "triangle":
|
||||
case 'triangle':
|
||||
return 0;
|
||||
case "catrom":
|
||||
case 'catrom':
|
||||
return 1;
|
||||
case "mitchell":
|
||||
case 'mitchell':
|
||||
return 2;
|
||||
case "lanczos3":
|
||||
case 'lanczos3':
|
||||
return 3;
|
||||
default:
|
||||
throw Error(`Unknown resize algorithm "${name}"`);
|
||||
@@ -67,10 +67,10 @@ function resizeWithAspect({
|
||||
input_width,
|
||||
input_height,
|
||||
target_width,
|
||||
target_height
|
||||
target_height,
|
||||
}) {
|
||||
if (!target_width && !target_height) {
|
||||
throw Error("Need to specify at least width or height when resizing");
|
||||
throw Error('Need to specify at least width or height when resizing');
|
||||
}
|
||||
if (target_width && target_height) {
|
||||
return { width: target_width, height: target_height };
|
||||
@@ -78,226 +78,228 @@ function resizeWithAspect({
|
||||
if (!target_width) {
|
||||
return {
|
||||
width: Math.round((input_width / input_height) * target_height),
|
||||
height: target_height
|
||||
height: target_height,
|
||||
};
|
||||
}
|
||||
if (!target_height) {
|
||||
return {
|
||||
width: target_width,
|
||||
height: Math.round((input_height / input_width) * target_width)
|
||||
height: Math.round((input_height / input_width) * target_width),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const preprocessors = {
|
||||
resize: {
|
||||
name: "Resize",
|
||||
description: "Resize the image before compressing",
|
||||
instantiate: async () => {
|
||||
await resizePromise;
|
||||
return (
|
||||
buffer,
|
||||
input_width,
|
||||
input_height,
|
||||
{ width, height, method, premultiply, linearRGB }
|
||||
) => {
|
||||
({ width, height } = resizeWithAspect({
|
||||
input_width,
|
||||
input_height,
|
||||
target_width: width,
|
||||
target_height: height
|
||||
}));
|
||||
return new ImageData(
|
||||
resize.resize(
|
||||
buffer,
|
||||
input_width,
|
||||
input_height,
|
||||
width,
|
||||
height,
|
||||
resizeNameToIndex(method),
|
||||
premultiply,
|
||||
linearRGB
|
||||
),
|
||||
width,
|
||||
height
|
||||
);
|
||||
};
|
||||
},
|
||||
defaultOptions: {
|
||||
method: "lanczos3",
|
||||
fitMethod: "stretch",
|
||||
premultiply: true,
|
||||
linearRGB: true
|
||||
}
|
||||
},
|
||||
// TODO: Need to handle SVGs and HQX
|
||||
quant: {
|
||||
name: "ImageQuant",
|
||||
description: "Reduce the number of colors used (aka. paletting)",
|
||||
instantiate: async () => {
|
||||
const imageQuant = await imageQuantPromise;
|
||||
return (buffer, width, height, { numColors, dither }) =>
|
||||
new ImageData(
|
||||
imageQuant.quantize(buffer, width, height, numColors, dither),
|
||||
width,
|
||||
height
|
||||
);
|
||||
},
|
||||
defaultOptions: {
|
||||
numColors: 255,
|
||||
dither: 1.0
|
||||
}
|
||||
},
|
||||
rotate: {
|
||||
name: "Rotate",
|
||||
description: "Rotate image",
|
||||
instantiate: async () => {
|
||||
return async (buffer, width, height, { degrees }) => {
|
||||
const sameDimensions = degrees == 0 || degrees == 180;
|
||||
const size = width * height * 4;
|
||||
const { instance } = await WebAssembly.instantiate(
|
||||
await fsp.readFile(pathify(rotateWasm))
|
||||
);
|
||||
const { memory } = instance.exports;
|
||||
const pagesNeeded = Math.ceil(
|
||||
(size * 2 - memory.buffer.byteLength) / (64 * 1024)
|
||||
);
|
||||
memory.grow(pagesNeeded);
|
||||
const view = new Uint8ClampedArray(memory.buffer);
|
||||
view.set(buffer, 8);
|
||||
instance.exports.rotate(width, height, degrees);
|
||||
return new ImageData(
|
||||
new Uint8ClampedArray(view.slice(size + 8, size * 2 + 8)),
|
||||
sameDimensions ? width : height,
|
||||
sameDimensions ? height : width
|
||||
);
|
||||
};
|
||||
},
|
||||
defaultOptions: {
|
||||
numRotations: 0
|
||||
}
|
||||
}
|
||||
// resize: {
|
||||
// name: "Resize",
|
||||
// description: "Resize the image before compressing",
|
||||
// instantiate: async () => {
|
||||
// await resizePromise;
|
||||
// return (
|
||||
// buffer,
|
||||
// input_width,
|
||||
// input_height,
|
||||
// { width, height, method, premultiply, linearRGB }
|
||||
// ) => {
|
||||
// ({ width, height } = resizeWithAspect({
|
||||
// input_width,
|
||||
// input_height,
|
||||
// target_width: width,
|
||||
// target_height: height
|
||||
// }));
|
||||
// return new ImageData(
|
||||
// resize.resize(
|
||||
// buffer,
|
||||
// input_width,
|
||||
// input_height,
|
||||
// width,
|
||||
// height,
|
||||
// resizeNameToIndex(method),
|
||||
// premultiply,
|
||||
// linearRGB
|
||||
// ),
|
||||
// width,
|
||||
// height
|
||||
// );
|
||||
// };
|
||||
// },
|
||||
// defaultOptions: {
|
||||
// method: "lanczos3",
|
||||
// fitMethod: "stretch",
|
||||
// premultiply: true,
|
||||
// linearRGB: true
|
||||
// }
|
||||
// },
|
||||
// // TODO: Need to handle SVGs and HQX
|
||||
// quant: {
|
||||
// name: "ImageQuant",
|
||||
// description: "Reduce the number of colors used (aka. paletting)",
|
||||
// instantiate: async () => {
|
||||
// const imageQuant = await imageQuantPromise;
|
||||
// return (buffer, width, height, { numColors, dither }) =>
|
||||
// new ImageData(
|
||||
// imageQuant.quantize(buffer, width, height, numColors, dither),
|
||||
// width,
|
||||
// height
|
||||
// );
|
||||
// },
|
||||
// defaultOptions: {
|
||||
// numColors: 255,
|
||||
// dither: 1.0
|
||||
// }
|
||||
// },
|
||||
// rotate: {
|
||||
// name: "Rotate",
|
||||
// description: "Rotate image",
|
||||
// instantiate: async () => {
|
||||
// return async (buffer, width, height, { degrees }) => {
|
||||
// const sameDimensions = degrees == 0 || degrees == 180;
|
||||
// const size = width * height * 4;
|
||||
// const { instance } = await WebAssembly.instantiate(
|
||||
// await fsp.readFile(pathify(rotateWasm))
|
||||
// );
|
||||
// const { memory } = instance.exports;
|
||||
// const pagesNeeded = Math.ceil(
|
||||
// (size * 2 - memory.buffer.byteLength) / (64 * 1024)
|
||||
// );
|
||||
// memory.grow(pagesNeeded);
|
||||
// const view = new Uint8ClampedArray(memory.buffer);
|
||||
// view.set(buffer, 8);
|
||||
// instance.exports.rotate(width, height, degrees);
|
||||
// return new ImageData(
|
||||
// new Uint8ClampedArray(view.slice(size + 8, size * 2 + 8)),
|
||||
// sameDimensions ? width : height,
|
||||
// sameDimensions ? height : width
|
||||
// );
|
||||
// };
|
||||
// },
|
||||
// defaultOptions: {
|
||||
// numRotations: 0
|
||||
// }
|
||||
// }
|
||||
};
|
||||
|
||||
export const codecs = {
|
||||
mozjpeg: {
|
||||
name: "MozJPEG",
|
||||
extension: "jpg",
|
||||
detectors: [/^\xFF\xD8\xFF/],
|
||||
dec: () => instantiateEmscriptenWasm(mozDec, mozDecWasm),
|
||||
enc: () => instantiateEmscriptenWasm(mozEnc, mozEncWasm),
|
||||
defaultEncoderOptions: {
|
||||
quality: 75,
|
||||
baseline: false,
|
||||
arithmetic: false,
|
||||
progressive: true,
|
||||
optimize_coding: true,
|
||||
smoothing: 0,
|
||||
color_space: 3 /*YCbCr*/,
|
||||
quant_table: 3,
|
||||
trellis_multipass: false,
|
||||
trellis_opt_zero: false,
|
||||
trellis_opt_table: false,
|
||||
trellis_loops: 1,
|
||||
auto_subsample: true,
|
||||
chroma_subsample: 2,
|
||||
separate_chroma_quality: false,
|
||||
chroma_quality: 75
|
||||
},
|
||||
autoOptimize: {
|
||||
option: "quality",
|
||||
min: 0,
|
||||
max: 100
|
||||
}
|
||||
},
|
||||
webp: {
|
||||
name: "WebP",
|
||||
extension: "webp",
|
||||
detectors: [/^RIFF....WEBPVP8[LX ]/],
|
||||
dec: () => instantiateEmscriptenWasm(webpDec, webpDecWasm),
|
||||
enc: () => instantiateEmscriptenWasm(webpEnc, webpEncWasm),
|
||||
defaultEncoderOptions: {
|
||||
quality: 75,
|
||||
target_size: 0,
|
||||
target_PSNR: 0,
|
||||
method: 4,
|
||||
sns_strength: 50,
|
||||
filter_strength: 60,
|
||||
filter_sharpness: 0,
|
||||
filter_type: 1,
|
||||
partitions: 0,
|
||||
segments: 4,
|
||||
pass: 1,
|
||||
show_compressed: 0,
|
||||
preprocessing: 0,
|
||||
autofilter: 0,
|
||||
partition_limit: 0,
|
||||
alpha_compression: 1,
|
||||
alpha_filtering: 1,
|
||||
alpha_quality: 100,
|
||||
lossless: 0,
|
||||
exact: 0,
|
||||
image_hint: 0,
|
||||
emulate_jpeg_size: 0,
|
||||
thread_level: 0,
|
||||
low_memory: 0,
|
||||
near_lossless: 100,
|
||||
use_delta_palette: 0,
|
||||
use_sharp_yuv: 0
|
||||
},
|
||||
autoOptimize: {
|
||||
option: "quality",
|
||||
min: 0,
|
||||
max: 100
|
||||
}
|
||||
},
|
||||
// mozjpeg: {
|
||||
// name: "MozJPEG",
|
||||
// extension: "jpg",
|
||||
// detectors: [/^\xFF\xD8\xFF/],
|
||||
// dec: () => instantiateEmscriptenWasm(mozDec, mozDecWasm),
|
||||
// enc: () => instantiateEmscriptenWasm(mozEnc, mozEncWasm),
|
||||
// defaultEncoderOptions: {
|
||||
// quality: 75,
|
||||
// baseline: false,
|
||||
// arithmetic: false,
|
||||
// progressive: true,
|
||||
// optimize_coding: true,
|
||||
// smoothing: 0,
|
||||
// color_space: 3 /*YCbCr*/,
|
||||
// quant_table: 3,
|
||||
// trellis_multipass: false,
|
||||
// trellis_opt_zero: false,
|
||||
// trellis_opt_table: false,
|
||||
// trellis_loops: 1,
|
||||
// auto_subsample: true,
|
||||
// chroma_subsample: 2,
|
||||
// separate_chroma_quality: false,
|
||||
// chroma_quality: 75
|
||||
// },
|
||||
// autoOptimize: {
|
||||
// option: "quality",
|
||||
// min: 0,
|
||||
// max: 100
|
||||
// }
|
||||
// },
|
||||
// webp: {
|
||||
// name: "WebP",
|
||||
// extension: "webp",
|
||||
// detectors: [/^RIFF....WEBPVP8[LX ]/],
|
||||
// dec: () => instantiateEmscriptenWasm(webpDec, webpDecWasm),
|
||||
// enc: () => instantiateEmscriptenWasm(webpEnc, webpEncWasm),
|
||||
// defaultEncoderOptions: {
|
||||
// quality: 75,
|
||||
// target_size: 0,
|
||||
// target_PSNR: 0,
|
||||
// method: 4,
|
||||
// sns_strength: 50,
|
||||
// filter_strength: 60,
|
||||
// filter_sharpness: 0,
|
||||
// filter_type: 1,
|
||||
// partitions: 0,
|
||||
// segments: 4,
|
||||
// pass: 1,
|
||||
// show_compressed: 0,
|
||||
// preprocessing: 0,
|
||||
// autofilter: 0,
|
||||
// partition_limit: 0,
|
||||
// alpha_compression: 1,
|
||||
// alpha_filtering: 1,
|
||||
// alpha_quality: 100,
|
||||
// lossless: 0,
|
||||
// exact: 0,
|
||||
// image_hint: 0,
|
||||
// emulate_jpeg_size: 0,
|
||||
// thread_level: 0,
|
||||
// low_memory: 0,
|
||||
// near_lossless: 100,
|
||||
// use_delta_palette: 0,
|
||||
// use_sharp_yuv: 0
|
||||
// },
|
||||
// autoOptimize: {
|
||||
// option: "quality",
|
||||
// min: 0,
|
||||
// max: 100
|
||||
// }
|
||||
// },
|
||||
avif: {
|
||||
name: "AVIF",
|
||||
extension: "avif",
|
||||
name: 'AVIF',
|
||||
extension: 'avif',
|
||||
detectors: [/^\x00\x00\x00 ftypavif\x00\x00\x00\x00/],
|
||||
dec: () => instantiateEmscriptenWasm(avifDec, avifDecWasm),
|
||||
enc: () => instantiateEmscriptenWasm(avifEnc, avifEncWasm),
|
||||
defaultEncoderOptions: {
|
||||
minQuantizer: 16,
|
||||
maxQuantizer: 16,
|
||||
minQuantizer: 33,
|
||||
maxQuantizer: 63,
|
||||
minQuantizerAlpha: 33,
|
||||
maxQuantizerAlpha: 63,
|
||||
tileColsLog2: 0,
|
||||
tileRowsLog2: 0,
|
||||
speed: 10,
|
||||
subsample: 0
|
||||
speed: 8,
|
||||
subsample: 1,
|
||||
},
|
||||
autoOptimize: {
|
||||
option: "maxQuantizer",
|
||||
option: 'maxQuantizer',
|
||||
min: 0,
|
||||
max: 62
|
||||
}
|
||||
max: 62,
|
||||
},
|
||||
},
|
||||
oxipng: {
|
||||
name: "OxiPNG",
|
||||
extension: "png",
|
||||
detectors: [/^\x89PNG\x0D\x0A\x1A\x0A/],
|
||||
dec: async () => {
|
||||
await pngEncDecPromise;
|
||||
return { decode: pngEncDec.decode };
|
||||
},
|
||||
enc: async () => {
|
||||
await pngEncDecPromise;
|
||||
await oxipngPromise;
|
||||
return {
|
||||
encode: (buffer, width, height, opts) => {
|
||||
const simplePng = new Uint8Array(
|
||||
pngEncDec.encode(new Uint8Array(buffer), width, height)
|
||||
);
|
||||
return new Uint8Array(oxipng.optimise(simplePng, opts.level));
|
||||
}
|
||||
};
|
||||
},
|
||||
defaultEncoderOptions: {
|
||||
level: 2
|
||||
},
|
||||
autoOptimize: {
|
||||
option: "level",
|
||||
min: 6,
|
||||
max: 1
|
||||
}
|
||||
}
|
||||
// oxipng: {
|
||||
// name: "OxiPNG",
|
||||
// extension: "png",
|
||||
// detectors: [/^\x89PNG\x0D\x0A\x1A\x0A/],
|
||||
// dec: async () => {
|
||||
// await pngEncDecPromise;
|
||||
// return { decode: pngEncDec.decode };
|
||||
// },
|
||||
// enc: async () => {
|
||||
// await pngEncDecPromise;
|
||||
// await oxipngPromise;
|
||||
// return {
|
||||
// encode: (buffer, width, height, opts) => {
|
||||
// const simplePng = new Uint8Array(
|
||||
// pngEncDec.encode(new Uint8Array(buffer), width, height)
|
||||
// );
|
||||
// return new Uint8Array(oxipng.optimise(simplePng, opts.level));
|
||||
// }
|
||||
// };
|
||||
// },
|
||||
// defaultEncoderOptions: {
|
||||
// level: 2
|
||||
// },
|
||||
// autoOptimize: {
|
||||
// option: "level",
|
||||
// min: 6,
|
||||
// max: 1
|
||||
// }
|
||||
// }
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user