ICC Profile
Is there a way like for Encoder of the Image crate to embed an ICC profile in the encoder?
/// Set the ICC profile to use for the image.
///
/// This function is a no-op for formats that don't support ICC profiles.
/// For formats that do support ICC profiles, the profile will be embedded
/// in the image when it is saved.
///
/// # Errors
///
/// This function returns an error if the format does not support ICC profiles.
fn set_icc_profile(&mut self, icc_profile: Vec<u8>) -> Result<(), UnsupportedError> {
let _ = icc_profile;
Err(UnsupportedError::from_format_and_kind(
ImageFormatHint::Unknown,
UnsupportedErrorKind::GenericFeature(
"ICC profiles are not supported for this format".into(),
),
))
}
WebP Specification: https://developers.google.com/speed/webp/docs/riff_container
Color Profile: Chunk Size bytes ICC profile. This chunk MUST appear before the image data.
There SHOULD be at most one such chunk. If there are more such chunks, readers MAY ignore all except the first one. See the ICC Specification for details.
If this chunk is not present, sRGB SHOULD be assumed.
I am also very interested in this. I would like to use this crate to convert images from JPEG and PNG to WebP, but due to the lack of support for embedding an ICC profile into the generated WebP file I cannot do that without major color distortion for some images.
We are interested as well.
We are also missing this feature.
As a workaround, we solved it by adding libwebp-sys2 = {version = "0.2.0", features = ["mux"]} to our dependencies, as well as this function:
/// Adds the given ICC profile to the given WebP data using libwebp's mux functionality.
/// Returns `Some<Vec<u8>>` containing the new WebP data with the ICC profile if successful, otherwise `None`.
fn mux_icc_profile(webp_data: &[u8], icc_profile: &[u8]) -> Option<Vec<u8>> {
unsafe {
// Wrap WebP data
let webp_data_struct = libwebp_sys::WebPData {
bytes: webp_data.as_ptr(),
size: webp_data.len(),
};
// Create mux
let mux = libwebp_sys::WebPMuxNew();
if mux.is_null() {
return None;
}
// Set image data
if libwebp_sys::WebPMuxSetImage(mux, &webp_data_struct, 1) != libwebp_sys::WEBP_MUX_OK {
libwebp_sys::WebPMuxDelete(mux);
return None;
}
// Add ICC profile chunk
let icc_data = libwebp_sys::WebPData {
bytes: icc_profile.as_ptr(),
size: icc_profile.len(),
};
if libwebp_sys::WebPMuxSetChunk(mux, c"ICCP".as_ptr(), &icc_data, 1) != libwebp_sys::WEBP_MUX_OK {
libwebp_sys::WebPMuxDelete(mux);
return None;
}
// Assemble final WebP
let mut output = libwebp_sys::WebPData { bytes: std::ptr::null(), size: 0 };
if libwebp_sys::WebPMuxAssemble(mux, &mut output) != libwebp_sys::WEBP_MUX_OK {
libwebp_sys::WebPMuxDelete(mux);
return None;
}
// Copy to Vec<u8>
let result = std::slice::from_raw_parts(output.bytes, output.size).to_vec();
// Free
libwebp_sys::WebPDataClear(&mut output);
libwebp_sys::WebPMuxDelete(mux);
Some(result)
}
}