mirror of
https://github.com/storytold/figcraft.git
synced 2026-11-09 03:51:42 +00:00
Export: a converted JPG flattens translucent pixels before the conversion
A JPG exported in a profile other than the document's was converted while still translucent and then composited over white, so translucent fills, shadows and antialiased edges came out a few levels off what the document shows. The render is now flattened over white in the document's profile first. PNG and WebP keep their alpha and are unchanged.
This commit is contained in:
1 parent
afc5e13972
commit
b8fa8b87be
2 files changed
+26
-1
No files matched your search
@@ -411,7 +411,19 @@ pub fn export_file(doc: &Document, ids: &[NodeId], setting: &ExportSetting, scal
|
||||
// The render is in the document's profile; the setting's profile converts the pixels
|
||||
// (out-of-gamut colors clip) and tags the file.
|
||||
let profile = setting.color_profile.resolve(doc.color_profile);
|
||||
doc.color_profile.conversion_to(profile).apply_pixels(pix.data_mut());
|
||||
let conversion = doc.color_profile.conversion_to(profile);
|
||||
// JPG has no alpha: the render is flattened over white in the document's profile
|
||||
// before the conversion, so translucent pixels match what the document shows.
|
||||
if setting.format == ExportFormat::Jpg && !conversion.is_identity() {
|
||||
for [r, g, b, a] in pix.data_mut().as_chunks_mut::<4>().0.iter_mut() {
|
||||
let under = 255 - *a;
|
||||
*r = r.saturating_add(under);
|
||||
*g = g.saturating_add(under);
|
||||
*b = b.saturating_add(under);
|
||||
*a = 255;
|
||||
}
|
||||
}
|
||||
conversion.apply_pixels(pix.data_mut());
|
||||
Ok((figcraft_render::encode_export(&pix, setting.format, profile).map_err(EngineError::Other)?, Vec::new()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,6 +115,19 @@ fn jpg_and_webp_follow_the_setting() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_translucent_jpg_is_flattened_before_its_conversion() {
|
||||
let (mut s, r) = session();
|
||||
s.execute("fill.set", &json!({"ids": [r], "opacity": 0.5})).unwrap();
|
||||
// The sRGB document shows 50% red over white; the Display P3 JPG holds that color converted.
|
||||
let flat = export(&mut s, json!({"ids": [r], "format": "jpg", "colorProfile": "srgb"}));
|
||||
let [fr, fg, fb] = middle(&flat);
|
||||
let shown = Color::new(f32::from(fr) / 255.0, f32::from(fg) / 255.0, f32::from(fb) / 255.0, 1.0);
|
||||
let want = rgb8(ColorProfile::Srgb.conversion_to(ColorProfile::DisplayP3).apply(shown));
|
||||
let p3 = export(&mut s, json!({"ids": [r], "format": "jpg", "colorProfile": "displayP3"}));
|
||||
assert!(close(middle(&p3), want, 2), "{:?} vs {want:?} (sRGB {:?})", middle(&p3), [fr, fg, fb]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn svg_pdf_and_xml_stay_srgb() {
|
||||
let (mut s, r) = session();
|
||||
|
||||
Reference in new issue
Block a user