fix(io): detect merged PSD alpha at the stored sample precision (#111)

This commit is contained in:
MikeeI 2026-10-05 07:00:57 +02:00 committed by GitHub
parent fb79564f2a
commit f4cf980a37
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 18 additions and 1 deletions

View File

@ -502,7 +502,12 @@ fn merged_planes(doc: &Document, fmt: &PixelFormat, cmyk: bool, matte: bool) ->
let w = canvas.width() as usize;
let space = photocraft_compose::cmyk_space(doc);
let _ = photocraft_compose::render_bands(doc, canvas, 0, |band| -> Result<(), ()> {
has_alpha |= band.px.iter().any(|p| q255(p[3]) < 255 || (sample == SampleType::F32 && p[3] < 1.0));
// Retain alpha whenever it differs from opaque at the stored precision.
has_alpha |= band.px.iter().any(|p| match sample {
SampleType::U8 => q255(p[3]) < 255,
SampleType::U16 => (p[3].clamp(0.0, 1.0) * 65535.0 + 0.5) as u16 != u16::MAX,
SampleType::F32 => p[3] != 1.0,
});
translucent |= band.px.iter().any(|p| p[3] < 1.0);
let start = (band.rect.y0 - canvas.y0) as usize * w;
// Converted and encoded on all cores, then copied into each plane.

View File

@ -171,4 +171,16 @@ fn merged_alpha_written_when_transparent() {
assert!(f.merged_has_alpha());
let merged = merged_composite(&f).unwrap();
assert_eq!(merged[3][3], 0.0);
// U8 rounding must not erase transparency that is representable in the exported U16 plane.
let mut near = photocraft_doc::Document::new("near opaque", photocraft_geom::Size::new(1, 1), ColorMode::Rgb, SampleType::U16);
let mut layer = photocraft_doc::Layer::raster("pixel", near.pixel_format());
layer.surface_mut().unwrap().fill_rect(near.bounds(), &[1.0, 0.0, 0.0, 65500.0 / 65535.0]);
near.layers.push(layer);
let out = export(&near, "near.psd", &ExportOptions::default()).unwrap();
let file = PsdFile::from_bytes(&out.bytes).unwrap();
assert_eq!(file.header.channels, 4);
assert!(file.merged_has_alpha());
let samples = file.decode_merged().unwrap();
assert_eq!(u16::from_be_bytes([samples[6], samples[7]]), 65500);
}