diff --git a/libsquoosh/README.md b/libsquoosh/README.md index 3c11e010..af8c9a93 100644 --- a/libsquoosh/README.md +++ b/libsquoosh/README.md @@ -42,11 +42,19 @@ When an image has been ingested, you can start preprocessing it and encoding it await image.decoded; //Wait until the image is decoded before running preprocessors. const preprocessOptions = { + //When both width and height are specified, the image resized to specified size. resize: { enabled: true, width: 100, height: 50, } + /* + //When either width or height is specified, the image resized to specified size keeping aspect ratio. + resize: { + enabled: true, + width: 100, + } + */ } await image.preprocess(preprocessOptions); 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(); diff --git a/src/client/lazy-app/Compress/Options/Range/index.tsx b/src/client/lazy-app/Compress/Options/Range/index.tsx index da6e37e2..8b1150e3 100644 --- a/src/client/lazy-app/Compress/Options/Range/index.tsx +++ b/src/client/lazy-app/Compress/Options/Range/index.tsx @@ -6,10 +6,13 @@ import './custom-els/RangeInput'; import { linkRef } from 'shared/prerendered-app/util'; interface Props extends preact.JSX.HTMLAttributes {} -interface State {} +interface State { + textFocused: boolean; +} export default class Range extends Component { rangeWc?: RangeInputElement; + inputEl?: HTMLInputElement; private onTextInput = (event: Event) => { const input = event.target as HTMLInputElement; @@ -23,10 +26,19 @@ export default class Range extends Component { ); }; - render(props: Props) { + private onTextFocus = () => { + this.setState({ textFocused: true }); + }; + + private onTextBlur = () => { + this.setState({ textFocused: false }); + }; + + render(props: Props, state: State) { const { children, ...otherProps } = props; const { value, min, max, step } = props; + const textValue = state.textFocused ? this.inputEl!.value : value; return ( );