From a2121ec47bafaa084dd8c6911c89bbc4b4167f14 Mon Sep 17 00:00:00 2001 From: ergunsh Date: Sun, 27 Jun 2021 22:24:13 +0200 Subject: [PATCH] Typescriptify auto optimizer in libSquoosh --- .../{auto-optimizer.js => auto-optimizer.ts} | 69 +++++++++++++++---- 1 file changed, 57 insertions(+), 12 deletions(-) rename libsquoosh/src/{auto-optimizer.js => auto-optimizer.ts} (54%) diff --git a/libsquoosh/src/auto-optimizer.js b/libsquoosh/src/auto-optimizer.ts similarity index 54% rename from libsquoosh/src/auto-optimizer.js rename to libsquoosh/src/auto-optimizer.ts index 1c536a3d..bffa4dc3 100644 --- a/libsquoosh/src/auto-optimizer.js +++ b/libsquoosh/src/auto-optimizer.ts @@ -2,6 +2,39 @@ import { instantiateEmscriptenWasm } from './emscripten-utils.js'; import visdif from '../../codecs/visdif/visdif.js'; import visdifWasm from 'asset-url:../../codecs/visdif/visdif.wasm'; +import type ImageData from './image_data'; + +interface VisDiff { + distance: (data: Uint8ClampedArray) => number; + delete: () => void; +} + +interface VisdiffConstructor { + new (data: Uint8ClampedArray, width: number, height: number): VisDiff; +} + +interface VisDiffModule extends EmscriptenWasm.Module { + VisDiff: VisdiffConstructor; +} + +type VisDiffModuleFactory = EmscriptenWasm.ModuleFactory; + +interface BinarySearchParams { + min?: number; + max?: number; + epsilon?: number; + maxRounds?: number; +} + +interface AutoOptimizeParams extends BinarySearchParams { + butteraugliDistanceGoal?: number; +} + +interface AutoOptimizeResult { + bitmap: ImageData; + binary: Uint8Array; + quality: number; +} // `measure` is a (async) function that takes exactly one numeric parameter and // returns a value. The function is assumed to be monotonic (an increase in `parameter` @@ -9,9 +42,9 @@ import visdifWasm from 'asset-url:../../codecs/visdif/visdif.wasm'; // to find `parameter` such that `measure` returns `measureGoal`, within an error // of `epsilon`. It will use at most `maxRounds` attempts. export async function binarySearch( - measureGoal, - measure, - { min = 0, max = 100, epsilon = 0.1, maxRounds = 6 } = {}, + measureGoal: number, + measure: (val: number) => Promise, + { min = 0, max = 100, epsilon = 0.1, maxRounds = 6 }: BinarySearchParams = {}, ) { let parameter = (max - min) / 2 + min; let delta = (max - min) / 4; @@ -33,12 +66,21 @@ export async function binarySearch( } export async function autoOptimize( - bitmapIn, - encode, - decode, - { butteraugliDistanceGoal = 1.4, ...otherOpts } = {}, -) { - const { VisDiff } = await instantiateEmscriptenWasm(visdif, visdifWasm); + bitmapIn: ImageData, + encode: ( + bitmap: ImageData, + quality: number, + ) => Promise | Uint8Array, + decode: (binary: Uint8Array) => Promise | ImageData, + { + butteraugliDistanceGoal = 1.4, + ...binarySearchParams + }: AutoOptimizeParams = {}, +): Promise { + const { VisDiff } = await instantiateEmscriptenWasm( + visdif as VisDiffModuleFactory, + visdifWasm, + ); const comparator = new VisDiff( bitmapIn.data, @@ -46,8 +88,11 @@ export async function autoOptimize( bitmapIn.height, ); - let bitmapOut; - let binaryOut; + // We're able to do non null assertion because + // we know that binarySearch will set these values + let bitmapOut!: ImageData; + let binaryOut!: Uint8Array; + // Increasing quality means _decrease_ in Butteraugli distance. // `binarySearch` assumes that increasing `parameter` will // increase the metric value. So multipliy Butteraugli values by -1. @@ -58,7 +103,7 @@ export async function autoOptimize( bitmapOut = await decode(binaryOut); return -1 * comparator.distance(bitmapOut.data); }, - otherOpts, + binarySearchParams, ); comparator.delete();