From 405dd1cdfae4a240f961f690d104e1720c1e9dc9 Mon Sep 17 00:00:00 2001 From: Surma Date: Sun, 13 Dec 2020 16:27:59 +0000 Subject: [PATCH 1/6] Fix banding from linear RGB color space conversion --- codecs/resize/Cargo.lock | 22 ++- codecs/resize/Cargo.toml | 2 +- codecs/resize/build.rs | 6 - codecs/resize/pkg/squoosh_resize.d.ts | 70 +++------- codecs/resize/pkg/squoosh_resize.js | 166 ++++++++++------------- codecs/resize/pkg/squoosh_resize_bg.wasm | Bin 18107 -> 37207 bytes codecs/resize/src/lib.rs | 98 ++++++++----- 7 files changed, 176 insertions(+), 188 deletions(-) diff --git a/codecs/resize/Cargo.lock b/codecs/resize/Cargo.lock index c8e03297..99cbde89 100644 --- a/codecs/resize/Cargo.lock +++ b/codecs/resize/Cargo.lock @@ -6,6 +6,12 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" +[[package]] +name = "bytemuck" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41aa2ec95ca3b5c54cf73c91acf06d24f4495d5f1b1c12506ae3483d646177ac" + [[package]] name = "cfg-if" version = "0.1.10" @@ -102,9 +108,21 @@ dependencies = [ [[package]] name = "resize" -version = "0.3.1" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e653e390eafbfebb2b3c5fcfbc90d801bc410d0de1f44f266ffbf2151d28aa" +checksum = "f2a08c42ea86684dc00256494c4eb8b54707890ddac50c05060a717f29669029" +dependencies = [ + "rgb", +] + +[[package]] +name = "rgb" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287f3c3f8236abb92d8b7e36797f19159df4b58f0a658cc3fb6dd3004b1f3bd3" +dependencies = [ + "bytemuck", +] [[package]] name = "scoped-tls" diff --git a/codecs/resize/Cargo.toml b/codecs/resize/Cargo.toml index c0bf17a5..76d2b153 100644 --- a/codecs/resize/Cargo.toml +++ b/codecs/resize/Cargo.toml @@ -14,7 +14,7 @@ default = ["console_error_panic_hook", "wee_alloc"] [dependencies] cfg-if = "0.1.2" wasm-bindgen = "0.2.38" -resize = "0.3.0" +resize = "0.5.5" # The `console_error_panic_hook` crate provides better debugging of panics by # logging them with `console.error`. This is great for development, but requires diff --git a/codecs/resize/build.rs b/codecs/resize/build.rs index 8feb48a8..077ab730 100644 --- a/codecs/resize/build.rs +++ b/codecs/resize/build.rs @@ -4,20 +4,14 @@ use std::io::Write; fn main() -> std::io::Result<()> { let mut srgb_to_linear_lut = String::from("static SRGB_TO_LINEAR_LUT: [f32; 256] = ["); - let mut linear_to_srgb_lut = String::from("static LINEAR_TO_SRGB_LUT: [f32; 256] = ["); for i in 0..256 { srgb_to_linear_lut.push_str(&format!("{0:.7}", srgb_to_linear((i as f32) / 255.0))); srgb_to_linear_lut.push_str(","); - linear_to_srgb_lut.push_str(&format!("{0:.7}", linear_to_srgb((i as f32) / 255.0))); - linear_to_srgb_lut.push_str(","); } srgb_to_linear_lut.pop().unwrap(); - linear_to_srgb_lut.pop().unwrap(); srgb_to_linear_lut.push_str("];"); - linear_to_srgb_lut.push_str("];"); let mut file = std::fs::File::create("src/lut.inc")?; file.write_all(srgb_to_linear_lut.as_bytes())?; - file.write_all(linear_to_srgb_lut.as_bytes())?; Ok(()) } diff --git a/codecs/resize/pkg/squoosh_resize.d.ts b/codecs/resize/pkg/squoosh_resize.d.ts index a07bae4c..c5899071 100644 --- a/codecs/resize/pkg/squoosh_resize.d.ts +++ b/codecs/resize/pkg/squoosh_resize.d.ts @@ -1,60 +1,34 @@ /* tslint:disable */ /* eslint-disable */ /** - * @param {Uint8Array} input_image - * @param {number} input_width - * @param {number} input_height - * @param {number} output_width - * @param {number} output_height - * @param {number} typ_idx - * @param {boolean} premultiply - * @param {boolean} color_space_conversion - * @returns {Uint8Array} - */ -export function resize( - input_image: Uint8Array, - input_width: number, - input_height: number, - output_width: number, - output_height: number, - typ_idx: number, - premultiply: boolean, - color_space_conversion: boolean, -): Uint8Array; +* @param {Uint8Array} input_image +* @param {number} input_width +* @param {number} input_height +* @param {number} output_width +* @param {number} output_height +* @param {number} typ_idx +* @param {boolean} premultiply +* @param {boolean} color_space_conversion +* @returns {Uint8Array} +*/ +export function resize(input_image: Uint8Array, input_width: number, input_height: number, output_width: number, output_height: number, typ_idx: number, premultiply: boolean, color_space_conversion: boolean): Uint8Array; -export type InitInput = - | RequestInfo - | URL - | Response - | BufferSource - | WebAssembly.Module; +export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module; export interface InitOutput { readonly memory: WebAssembly.Memory; - readonly resize: ( - a: number, - b: number, - c: number, - d: number, - e: number, - f: number, - g: number, - h: number, - i: number, - j: number, - ) => void; + readonly resize: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number) => void; readonly __wbindgen_malloc: (a: number) => number; readonly __wbindgen_free: (a: number, b: number) => void; } /** - * If `module_or_path` is {RequestInfo} or {URL}, makes a request and - * for everything else, calls `WebAssembly.instantiate` directly. - * - * @param {InitInput | Promise} module_or_path - * - * @returns {Promise} - */ -export default function init( - module_or_path?: InitInput | Promise, -): Promise; +* If `module_or_path` is {RequestInfo} or {URL}, makes a request and +* for everything else, calls `WebAssembly.instantiate` directly. +* +* @param {InitInput | Promise} module_or_path +* +* @returns {Promise} +*/ +export default function init (module_or_path?: InitInput | Promise): Promise; + \ No newline at end of file diff --git a/codecs/resize/pkg/squoosh_resize.js b/codecs/resize/pkg/squoosh_resize.js index bfb298ba..74f31d1f 100644 --- a/codecs/resize/pkg/squoosh_resize.js +++ b/codecs/resize/pkg/squoosh_resize.js @@ -1,131 +1,107 @@ + let wasm; let cachegetUint8Memory0 = null; function getUint8Memory0() { - if ( - cachegetUint8Memory0 === null || - cachegetUint8Memory0.buffer !== wasm.memory.buffer - ) { - cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer); - } - return cachegetUint8Memory0; + if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== wasm.memory.buffer) { + cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer); + } + return cachegetUint8Memory0; } let WASM_VECTOR_LEN = 0; function passArray8ToWasm0(arg, malloc) { - const ptr = malloc(arg.length * 1); - getUint8Memory0().set(arg, ptr / 1); - WASM_VECTOR_LEN = arg.length; - return ptr; + const ptr = malloc(arg.length * 1); + getUint8Memory0().set(arg, ptr / 1); + WASM_VECTOR_LEN = arg.length; + return ptr; } let cachegetInt32Memory0 = null; function getInt32Memory0() { - if ( - cachegetInt32Memory0 === null || - cachegetInt32Memory0.buffer !== wasm.memory.buffer - ) { - cachegetInt32Memory0 = new Int32Array(wasm.memory.buffer); - } - return cachegetInt32Memory0; + if (cachegetInt32Memory0 === null || cachegetInt32Memory0.buffer !== wasm.memory.buffer) { + cachegetInt32Memory0 = new Int32Array(wasm.memory.buffer); + } + return cachegetInt32Memory0; } function getArrayU8FromWasm0(ptr, len) { - return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len); + return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len); } /** - * @param {Uint8Array} input_image - * @param {number} input_width - * @param {number} input_height - * @param {number} output_width - * @param {number} output_height - * @param {number} typ_idx - * @param {boolean} premultiply - * @param {boolean} color_space_conversion - * @returns {Uint8Array} - */ -export function resize( - input_image, - input_width, - input_height, - output_width, - output_height, - typ_idx, - premultiply, - color_space_conversion, -) { - var ptr0 = passArray8ToWasm0(input_image, wasm.__wbindgen_malloc); - var len0 = WASM_VECTOR_LEN; - wasm.resize( - 8, - ptr0, - len0, - input_width, - input_height, - output_width, - output_height, - typ_idx, - premultiply, - color_space_conversion, - ); - var r0 = getInt32Memory0()[8 / 4 + 0]; - var r1 = getInt32Memory0()[8 / 4 + 1]; - var v1 = getArrayU8FromWasm0(r0, r1).slice(); - wasm.__wbindgen_free(r0, r1 * 1); - return v1; +* @param {Uint8Array} input_image +* @param {number} input_width +* @param {number} input_height +* @param {number} output_width +* @param {number} output_height +* @param {number} typ_idx +* @param {boolean} premultiply +* @param {boolean} color_space_conversion +* @returns {Uint8Array} +*/ +export function resize(input_image, input_width, input_height, output_width, output_height, typ_idx, premultiply, color_space_conversion) { + var ptr0 = passArray8ToWasm0(input_image, wasm.__wbindgen_malloc); + var len0 = WASM_VECTOR_LEN; + wasm.resize(8, ptr0, len0, input_width, input_height, output_width, output_height, typ_idx, premultiply, color_space_conversion); + var r0 = getInt32Memory0()[8 / 4 + 0]; + var r1 = getInt32Memory0()[8 / 4 + 1]; + var v1 = getArrayU8FromWasm0(r0, r1).slice(); + wasm.__wbindgen_free(r0, r1 * 1); + return v1; } async function load(module, imports) { - if (typeof Response === 'function' && module instanceof Response) { - if (typeof WebAssembly.instantiateStreaming === 'function') { - try { - return await WebAssembly.instantiateStreaming(module, imports); - } catch (e) { - if (module.headers.get('Content-Type') != 'application/wasm') { - console.warn( - '`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n', - e, - ); - } else { - throw e; + if (typeof Response === 'function' && module instanceof Response) { + + if (typeof WebAssembly.instantiateStreaming === 'function') { + try { + return await WebAssembly.instantiateStreaming(module, imports); + + } catch (e) { + if (module.headers.get('Content-Type') != 'application/wasm') { + console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e); + + } else { + throw e; + } + } } - } - } - const bytes = await module.arrayBuffer(); - return await WebAssembly.instantiate(bytes, imports); - } else { - const instance = await WebAssembly.instantiate(module, imports); + const bytes = await module.arrayBuffer(); + return await WebAssembly.instantiate(bytes, imports); - if (instance instanceof WebAssembly.Instance) { - return { instance, module }; } else { - return instance; + + const instance = await WebAssembly.instantiate(module, imports); + + if (instance instanceof WebAssembly.Instance) { + return { instance, module }; + + } else { + return instance; + } } - } } async function init(input) { - if (typeof input === 'undefined') { - input = import.meta.url.replace(/\.js$/, '_bg.wasm'); - } - const imports = {}; + if (typeof input === 'undefined') { + input = import.meta.url.replace(/\.js$/, '_bg.wasm'); + } + const imports = {}; - if ( - typeof input === 'string' || - (typeof Request === 'function' && input instanceof Request) || - (typeof URL === 'function' && input instanceof URL) - ) { - input = fetch(input); - } - const { instance, module } = await load(await input, imports); + if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) { + input = fetch(input); + } - wasm = instance.exports; - init.__wbindgen_wasm_module = module; + const { instance, module } = await load(await input, imports); - return wasm; + wasm = instance.exports; + init.__wbindgen_wasm_module = module; + + return wasm; } export default init; + diff --git a/codecs/resize/pkg/squoosh_resize_bg.wasm b/codecs/resize/pkg/squoosh_resize_bg.wasm index f0d8264f994fdcc28269a735c77772ffd2a58662..a1f04051025c813582a9a0b433e873335008be2a 100644 GIT binary patch literal 37207 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 bqw(`u_@Nu`EEoCicOF2RtMw1ub@=}PS} ((fn(u8) -> f32), (fn(f32) -> u8)) { +fn srgb_converter_funcs(with_space_conversion: bool) -> (fn(u8) -> f32, fn(f32) -> u8) { if with_space_conversion { ( - |v| SRGB_TO_LINEAR_LUT[v as usize] * 255.0, - |v| (LINEAR_TO_SRGB_LUT[v as usize] * 255.0) as u8, + |v| SRGB_TO_LINEAR_LUT[v as usize], + |v| (linear_to_srgb(v) * 255.0).clamp(0.0, 255.0) as u8, ) } else { - (|v| v as f32, |v| v as u8) + ( + |v| (v as f32) / 255.0, + |v| (v * 255.0).clamp(0.0, 255.0) as u8, + ) } } @@ -44,21 +47,24 @@ fn converter_funcs(with_space_conversion: bool) -> ((fn(u8) -> f32), (fn(f32) -> // false, the functions just return the channel value. fn alpha_multiplier_funcs( with_alpha_premultiplication: bool, -) -> ((fn(f32, u8) -> u8), (fn(u8, u8) -> f32)) { +) -> (fn(f32, f32) -> f32, fn(f32, f32) -> f32) { if with_alpha_premultiplication { - ( - |v, a| (v * (a as f32) / 255.0) as u8, - |v, a| ((v as f32) * 255.0 / (a as f32)).clamp(0.0, 255.0), - ) + (|v, a| v * a, |v, a| v / a) } else { - (|v, _a| v as u8, |v, _a| v as f32) + (|v, _a| v, |v, _a| v) } } +fn vec_with_len(len: usize, item: T) -> Vec { + let mut v: Vec = Vec::with_capacity(len); + v.resize(len, item); + return v; +} + #[wasm_bindgen] #[no_mangle] pub fn resize( - mut input_image: Vec, + input_image: Vec, input_width: usize, input_height: usize, output_width: usize, @@ -77,44 +83,64 @@ pub fn resize( let num_input_pixels = input_width * input_height; let num_output_pixels = output_width * output_height; - let (to_linear, to_color_space) = converter_funcs(color_space_conversion); - let (premultiplier, demultiplier) = alpha_multiplier_funcs(premultiply); + let mut output_image: Vec = vec_with_len(num_output_pixels * 4, 0); // If both options are false, there is no preprocessing on the pixel valus // and we can skip the loop. - if premultiply || color_space_conversion { - for i in 0..num_input_pixels { - for j in 0..3 { - input_image[4 * i + j] = - premultiplier(to_linear(input_image[4 * i + j]), input_image[4 * i + 3]); - } + if !premultiply && !color_space_conversion { + let mut resizer = resize::new( + input_width, + input_height, + output_width, + output_height, + Pixel::RGBA, + typ, + ); + resizer.resize(input_image.as_slice(), output_image.as_mut_slice()); + return output_image; + } + + // Otherwise, we convert to f32 images so we don’t introduce + // banding through the conversions. + let (to_linear, to_srgb) = srgb_converter_funcs(color_space_conversion); + let (premultiplier, demultiplier) = alpha_multiplier_funcs(premultiply); + + let mut preprocessed_input_image: Vec = Vec::with_capacity(input_image.len()); + preprocessed_input_image.resize(input_image.len(), 0.0f32); + for i in 0..num_input_pixels { + for j in 0..3 { + preprocessed_input_image[4 * i + j] = premultiplier( + to_linear(input_image[4 * i + j]), + (input_image[4 * i + 3] as f32) / 255.0, + ); + preprocessed_input_image[4 * i + 3] = (input_image[4 * i + 3] as f32) / 255.0; } } + let mut unprocessed_output_image: Vec = vec_with_len(num_output_pixels * 4, 0.0f32); + let mut resizer = resize::new( input_width, input_height, output_width, output_height, - RGBA, + Pixel::RGBAF32, typ, ); - let mut output_image = Vec::::with_capacity(num_output_pixels * 4); - output_image.resize(num_output_pixels * 4, 0); - resizer.resize(input_image.as_slice(), output_image.as_mut_slice()); + resizer.resize( + preprocessed_input_image.as_slice(), + unprocessed_output_image.as_mut_slice(), + ); - if premultiply || color_space_conversion { - for i in 0..num_output_pixels { - for j in 0..3 { - // We don’t need to worry about division by zero, as division by zero - // is well-defined on floats to return ±Inf. ±Inf is converted to 0 - // when casting to integers. - output_image[4 * i + j] = to_color_space(demultiplier( - output_image[4 * i + j], - output_image[4 * i + 3], - )); - } + for i in 0..num_output_pixels { + for j in 0..3 { + output_image[4 * i + j] = to_srgb(demultiplier( + unprocessed_output_image[4 * i + j], + unprocessed_output_image[4 * i + 3], + )); } + output_image[4 * i + 3] = + (unprocessed_output_image[4 * i + 3] * 255.0).clamp(0.0, 255.0) as u8; } return output_image; From c63120d4ceedd141c14fd69a203793af5e76f1e6 Mon Sep 17 00:00:00 2001 From: Surma Date: Sun, 13 Dec 2020 16:36:00 +0000 Subject: [PATCH 2/6] Minor cleanup --- codecs/resize/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/codecs/resize/src/lib.rs b/codecs/resize/src/lib.rs index 65f40a46..5473706b 100644 --- a/codecs/resize/src/lib.rs +++ b/codecs/resize/src/lib.rs @@ -10,7 +10,7 @@ use resize::Type; use wasm_bindgen::prelude::*; mod srgb; -use srgb::{linear_to_srgb, srgb_to_linear, Clamp}; +use srgb::{linear_to_srgb, Clamp}; cfg_if! { // When the `wee_alloc` feature is enabled, use `wee_alloc` as the global @@ -85,7 +85,7 @@ pub fn resize( let mut output_image: Vec = vec_with_len(num_output_pixels * 4, 0); - // If both options are false, there is no preprocessing on the pixel valus + // If both options are false, there is no preprocessing on the pixel values // and we can skip the loop. if !premultiply && !color_space_conversion { let mut resizer = resize::new( @@ -100,8 +100,8 @@ pub fn resize( return output_image; } - // Otherwise, we convert to f32 images so we don’t introduce - // banding through the conversions. + // Otherwise, we convert to f32 images to keep the + // conversions as lossless and high-fidelity as possible. let (to_linear, to_srgb) = srgb_converter_funcs(color_space_conversion); let (premultiplier, demultiplier) = alpha_multiplier_funcs(premultiply); From f55e4cf9a8bfbcdb5476f0ecc3003b9f9ee7164f Mon Sep 17 00:00:00 2001 From: Surma Date: Tue, 5 Jan 2021 14:49:08 +0000 Subject: [PATCH 3/6] Update codecs/resize/src/lib.rs Co-authored-by: Ingvar Stepanyan --- codecs/resize/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codecs/resize/src/lib.rs b/codecs/resize/src/lib.rs index 5473706b..16b292dd 100644 --- a/codecs/resize/src/lib.rs +++ b/codecs/resize/src/lib.rs @@ -117,7 +117,7 @@ pub fn resize( } } - let mut unprocessed_output_image: Vec = vec_with_len(num_output_pixels * 4, 0.0f32); + let mut unprocessed_output_image = vec![0.0f32; num_output_pixels * 4]; let mut resizer = resize::new( input_width, From e260994600f871b2de787631441e886f9bfe637d Mon Sep 17 00:00:00 2001 From: Surma Date: Tue, 5 Jan 2021 14:49:41 +0000 Subject: [PATCH 4/6] Update codecs/resize/src/lib.rs --- codecs/resize/src/lib.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/codecs/resize/src/lib.rs b/codecs/resize/src/lib.rs index 16b292dd..ef9b051e 100644 --- a/codecs/resize/src/lib.rs +++ b/codecs/resize/src/lib.rs @@ -55,12 +55,6 @@ fn alpha_multiplier_funcs( } } -fn vec_with_len(len: usize, item: T) -> Vec { - let mut v: Vec = Vec::with_capacity(len); - v.resize(len, item); - return v; -} - #[wasm_bindgen] #[no_mangle] pub fn resize( From ad075847303b075816fe4f7cbfbf8dcc19e068bc Mon Sep 17 00:00:00 2001 From: Surma Date: Tue, 5 Jan 2021 14:50:08 +0000 Subject: [PATCH 5/6] Update codecs/resize/src/lib.rs Co-authored-by: Ingvar Stepanyan --- codecs/resize/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codecs/resize/src/lib.rs b/codecs/resize/src/lib.rs index ef9b051e..798e34dc 100644 --- a/codecs/resize/src/lib.rs +++ b/codecs/resize/src/lib.rs @@ -77,7 +77,7 @@ pub fn resize( let num_input_pixels = input_width * input_height; let num_output_pixels = output_width * output_height; - let mut output_image: Vec = vec_with_len(num_output_pixels * 4, 0); + let mut output_image = vec![0u8; num_output_pixels * 4]; // If both options are false, there is no preprocessing on the pixel values // and we can skip the loop. From 36293d756b8c4491f41e6b305bea2dffe9f0fedf Mon Sep 17 00:00:00 2001 From: Surma Date: Tue, 5 Jan 2021 15:29:57 +0000 Subject: [PATCH 6/6] Move variable assignment out of loop --- codecs/resize/pkg/squoosh_resize_bg.wasm | Bin 37207 -> 37004 bytes codecs/resize/src/lib.rs | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/codecs/resize/pkg/squoosh_resize_bg.wasm b/codecs/resize/pkg/squoosh_resize_bg.wasm index a1f04051025c813582a9a0b433e873335008be2a..0a10cca382dccd4cf661442e834b3d7256d02aa3 100644 GIT binary patch delta 7622 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 diff --git a/codecs/resize/src/lib.rs b/codecs/resize/src/lib.rs index 798e34dc..bb7df8ad 100644 --- a/codecs/resize/src/lib.rs +++ b/codecs/resize/src/lib.rs @@ -107,8 +107,8 @@ pub fn resize( to_linear(input_image[4 * i + j]), (input_image[4 * i + 3] as f32) / 255.0, ); - preprocessed_input_image[4 * i + 3] = (input_image[4 * i + 3] as f32) / 255.0; } + preprocessed_input_image[4 * i + 3] = (input_image[4 * i + 3] as f32) / 255.0; } let mut unprocessed_output_image = vec![0.0f32; num_output_pixels * 4];