mirror of
https://github.com/Brooooooklyn/Image.git
synced 2025-12-08 18:36:03 +00:00
feat(png): add automatic gamma detection from PNG metadata for color-accurate quantization (#152)
* Initial plan * Initial analysis of PNG quantization color distortion issue Co-authored-by: Brooooooklyn <3468483+Brooooooklyn@users.noreply.github.com> * fix(png): correct gamma handling in PNG quantization to prevent color distortion Co-authored-by: Brooooooklyn <3468483+Brooooooklyn@users.noreply.github.com> * feat(png): add configurable gamma parameter for non-sRGB images in quantization - Add optional gamma parameter to PngQuantOptions - Default to 0.45 (sRGB) but allow override for linear RGB (1.0) and other color spaces - Added comprehensive documentation with common gamma values - Addresses concern about non-sRGB source images Co-authored-by: Brooooooklyn <3468483+Brooooooklyn@users.noreply.github.com> * feat(png): add automatic gamma detection from PNG metadata in quantization Co-authored-by: Brooooooklyn <3468483+Brooooooklyn@users.noreply.github.com> * feat(png): remove manual gamma override, use only automatic detection Removed the gamma field from PngQuantOptions struct per feedback from @Brooooooklyn. Now only uses detect_gamma_from_png_info() for automatic gamma detection from PNG metadata (sRGB chunk, gAMA chunk, or sRGB fallback). Co-authored-by: Brooooooklyn <3468483+Brooooooklyn@users.noreply.github.com> * remove package-lock.json and add to gitignore Co-authored-by: Brooooooklyn <3468483+Brooooooklyn@users.noreply.github.com> * revert accidental yarn.lock format change and generated files Co-authored-by: Brooooooklyn <3468483+Brooooooklyn@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Brooooooklyn <3468483+Brooooooklyn@users.noreply.github.com>
This commit is contained in:
parent
ab7bff6929
commit
ec6e322148
3
.gitignore
vendored
3
.gitignore
vendored
@ -24,4 +24,5 @@ nasa-small.*
|
||||
output-overlay-png.png
|
||||
output-debian.jpeg
|
||||
*.wasm
|
||||
packages/binding/npm
|
||||
packages/binding/npm
|
||||
package-lock.json
|
||||
@ -255,6 +255,11 @@ fn png_quantize_inner(input: &[u8], options: &PngQuantOptions) -> Result<Vec<u8>
|
||||
if decoded_buf.len() < (width * height * 4) as usize {
|
||||
return Ok(input.to_vec());
|
||||
}
|
||||
|
||||
// Configure gamma for quantization - this affects color accuracy during palette generation
|
||||
// Automatically detect gamma from PNG metadata (gAMA chunk, sRGB chunk, or sRGB fallback)
|
||||
let gamma = detect_gamma_from_png_info(reader.info());
|
||||
|
||||
let mut liq = imagequant::new();
|
||||
liq
|
||||
.set_speed(options.speed.unwrap_or(5) as i32)
|
||||
@ -266,7 +271,12 @@ fn png_quantize_inner(input: &[u8], options: &PngQuantOptions) -> Result<Vec<u8>
|
||||
)
|
||||
.map_err(|err| Error::new(Status::GenericFailure, format!("{err}")))?;
|
||||
let mut img = liq
|
||||
.new_image(decoded_buf.as_rgba(), width as usize, height as usize, 0.0)
|
||||
.new_image(
|
||||
decoded_buf.as_rgba(),
|
||||
width as usize,
|
||||
height as usize,
|
||||
gamma
|
||||
)
|
||||
.map_err(|err| Error::new(Status::GenericFailure, format!("Create image failed {err}")))?;
|
||||
let mut quantization_result = liq
|
||||
.quantize(&mut img)
|
||||
@ -295,6 +305,33 @@ fn png_quantize_inner(input: &[u8], options: &PngQuantOptions) -> Result<Vec<u8>
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
/// Detects the appropriate gamma value for quantization from PNG metadata
|
||||
///
|
||||
/// Priority order:
|
||||
/// 1. If sRGB chunk is present, use sRGB gamma (reciprocal ~0.45)
|
||||
/// 2. If gAMA chunk is present, use reciprocal of gamma value
|
||||
/// 3. Default fallback to 0.45 (sRGB)
|
||||
fn detect_gamma_from_png_info(info: &png::Info) -> f64 {
|
||||
// sRGB color space implies gamma ~2.2, reciprocal ~0.45
|
||||
if info.srgb.is_some() {
|
||||
return 0.45;
|
||||
}
|
||||
|
||||
// Check for gAMA chunk or source_gamma (same information, different representation)
|
||||
if let Some(gamma) = info.source_gamma {
|
||||
let gamma_value = gamma.into_value() as f64;
|
||||
return 1.0 / gamma_value;
|
||||
}
|
||||
|
||||
if let Some(gama) = info.gama_chunk {
|
||||
let gamma_value = gama.into_value() as f64;
|
||||
return 1.0 / gamma_value;
|
||||
}
|
||||
|
||||
// Default fallback to sRGB
|
||||
0.45
|
||||
}
|
||||
|
||||
pub struct PngQuantTask {
|
||||
input: Uint8Array,
|
||||
options: PngQuantOptions,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user