mirror of
https://github.com/storytold/photocraft.git
synced 2026-11-01 05:47:31 -06:00
fix(io): preserve selected real PSD masks (#130)
This commit is contained in:
@@ -67,6 +67,12 @@ fn doc_mode(m: PsdMode) -> Option<ColorMode> {
|
||||
})
|
||||
}
|
||||
|
||||
// Real-mask metadata without a -3 channel still selects the synthetic -2 mask.
|
||||
fn selected_real_mask(rec: &LayerRecord) -> Option<photocraft_psd::RealMask> {
|
||||
rec.channel(CHANNEL_REAL_USER_MASK)?;
|
||||
rec.layer_mask()?.real
|
||||
}
|
||||
|
||||
impl Ctx<'_> {
|
||||
fn warn(&mut self, s: impl Into<String>) {
|
||||
self.warnings.push(s.into());
|
||||
@@ -108,8 +114,8 @@ impl Ctx<'_> {
|
||||
|
||||
fn record_mask(&mut self, rec: &LayerRecord, name: &str) -> Option<LayerMask> {
|
||||
let m = rec.layer_mask()?;
|
||||
let (id, rect, default, flags) = match (rec.channel(CHANNEL_REAL_USER_MASK), m.real) {
|
||||
(Some(_), Some(real)) => (CHANNEL_REAL_USER_MASK, real.rect, real.background, real.flags),
|
||||
let (id, rect, default, flags) = match selected_real_mask(rec) {
|
||||
Some(real) => (CHANNEL_REAL_USER_MASK, real.rect, real.background, real.flags),
|
||||
_ => {
|
||||
rec.channel(CHANNEL_USER_MASK)?;
|
||||
(CHANNEL_USER_MASK, m.rect, m.default_color, m.flags)
|
||||
@@ -272,7 +278,7 @@ impl Ctx<'_> {
|
||||
// Mask flag bit 3: the user mask was rendered from vector data. For
|
||||
// shape/text/smart layers the cached pixels already include that
|
||||
// coverage, so applying it again would double-mask.
|
||||
if rendered && rec.layer_mask().is_some_and(|m| m.flags & 8 != 0) {
|
||||
if rendered && selected_real_mask(rec).is_none() && rec.layer_mask().is_some_and(|m| m.flags & 8 != 0) {
|
||||
l.mask = None;
|
||||
}
|
||||
if !matches!(l.content, LayerContent::Shape(_)) {
|
||||
@@ -292,7 +298,7 @@ impl Ctx<'_> {
|
||||
vm.density = p.vector_density.map_or(1.0, |d| f32::from(d) / 255.0);
|
||||
vm.feather = p.vector_feather.map_or(0.0, |f| f as f32);
|
||||
}
|
||||
if m.flags & 8 != 0 && m.real.is_none() {
|
||||
if m.flags & 8 != 0 && selected_real_mask(rec).is_none() {
|
||||
l.mask = None;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,6 +446,18 @@ fn vector_rendered_mask_not_doubled_on_shapes() {
|
||||
let l = d.layers.last().unwrap();
|
||||
assert_eq!(l.content.kind_name(), "Shape");
|
||||
assert!(l.mask.is_none());
|
||||
|
||||
let record = f.layers_mut().last_mut().unwrap();
|
||||
let photocraft_psd::MaskData::Mask(mask) = &mut record.mask else { panic!("fixture has a mask") };
|
||||
mask.real = Some(photocraft_psd::RealMask { flags: 0, background: 255, rect: photocraft_psd::Rect { top: 0, left: 0, bottom: 1, right: 1 } });
|
||||
record.channels.push(photocraft_psd::ChannelData { id: -3, compression: Some(Compression::Raw), data: vec![64] });
|
||||
let (imported, _) = psd_to_document(&f);
|
||||
assert_eq!(imported.layers.last().unwrap().content.kind_name(), "Shape");
|
||||
let mask = imported.layers.last().unwrap().mask.as_ref().expect("selected real mask must survive synthetic cleanup");
|
||||
assert!((mask.surface.sample_channel(0, 0, 0) - 64.0 / 255.0).abs() < 1e-6);
|
||||
let exported = export(&imported, "real-mask.psd", &Default::default()).unwrap();
|
||||
let reopened = import("real-mask.psd", &exported.bytes).unwrap().document;
|
||||
assert_eq!(reopened.layers.last().unwrap().mask.as_ref().unwrap().surface.pixel(0, 0), mask.surface.pixel(0, 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user