mirror of
https://github.com/storytold/photocraft.git
synced 2026-10-22 18:22:00 +00:00
Background: an opacity, fill, blend mode or Select and Mask layer mask makes it Layer 0 (#4837)
The Background has none of them. layer.setProps applied them to it as it was, and Select and Mask's Layer Mask output gave it a mask. Like Photoshop (and like PhotoCraft already does for moving, transforming, erasing, styles and Layer > Layer Mask), it now becomes a normal layer, "Layer 0", first. Values that leave its look alone (opacity and fill 100 %, Normal) keep it the Background. Fixes #4836
This commit is contained in:
1 parent
7c916d9ecd
commit
2da2889546
3 files changed
+34
No files matched your search
@@ -144,6 +144,32 @@ mod tests {
|
||||
(s, [bg, a, b])
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn opacity_fill_or_a_blend_mode_turn_the_background_into_a_layer() {
|
||||
// Like Photoshop: the Background takes none of them, so it becomes "Layer 0" first.
|
||||
for (key, value) in [("opacity", json!(0.5)), ("fill", json!(0.5)), ("blend", json!("Multiply"))] {
|
||||
let (mut s, [bg, ..]) = with_background();
|
||||
s.execute("layer.setProps", json!({"layer": bg.0, key: value})).unwrap();
|
||||
let l = doc(&s).layer(bg).unwrap();
|
||||
assert!(!doc(&s).is_background(bg) && l.name == "Layer 0", "{key}");
|
||||
assert!(l.opacity < 1.0 || l.fill_opacity < 1.0 || l.blend == photocraft_color::BlendMode::Multiply, "{key}: applied");
|
||||
}
|
||||
// Values that leave its look alone keep it the Background.
|
||||
let (mut s, [bg, ..]) = with_background();
|
||||
s.execute("layer.setProps", json!({"layer": bg.0, "opacity": 1.0, "fill": 1.0, "blend": "Normal", "visible": false})).unwrap();
|
||||
assert!(doc(&s).is_background(bg));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn select_and_mask_output_to_a_layer_mask_turns_the_background_into_a_layer() {
|
||||
let (mut s, [bg, ..]) = with_background();
|
||||
s.execute("layer.select", json!({"layer": bg.0})).unwrap();
|
||||
s.execute("select.rect", json!({"x": 2, "y": 2, "width": 6, "height": 6})).unwrap();
|
||||
s.execute("select.refineEdge", json!({"output": "layerMask"})).unwrap();
|
||||
let l = doc(&s).layer(bg).unwrap();
|
||||
assert!(l.mask.is_some() && !doc(&s).is_background(bg) && l.name == "Layer 0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn makes_the_layer_the_background_at_the_bottom() {
|
||||
for depth in [8, 16, 32] {
|
||||
|
||||
@@ -688,6 +688,13 @@ fn build() -> Vec<CommandSpec> {
|
||||
// Clipping and channel changes reach the layers around it: recomposite everything.
|
||||
let local = p.get("clipped").is_none() && p.get("channels").is_none();
|
||||
s.edit(label, |doc, _| {
|
||||
// The Background has no opacity, fill or blend mode: like Photoshop, setting
|
||||
// one that changes its look turns it into a normal layer ("Layer 0") first.
|
||||
let num = |k: &str| p.get(k).and_then(Value::as_f64).is_some_and(|v| v < 1.0);
|
||||
let blends = p.get("blend").and_then(Value::as_str).and_then(blend_from_str).is_some_and(|b| b != photocraft_color::BlendMode::Normal);
|
||||
if num("opacity") || num("fill") || blends {
|
||||
crate::extra_cmds::background_to_layer(doc, id);
|
||||
}
|
||||
let l = doc.layer_mut(id).ok_or(EngineError::NoLayer(id))?;
|
||||
if let Some(v) = p.get("name").and_then(Value::as_str) {
|
||||
l.name = v.to_string();
|
||||
|
||||
@@ -417,6 +417,7 @@ fn refine_edge(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
s.edit("Select and Mask", |doc, _| {
|
||||
let surface =
|
||||
region.as_ref().map(matting::region_surface).unwrap_or_else(|| photocraft_raster::Surface::new(photocraft_color::PixelFormat::GRAY8));
|
||||
crate::extra_cmds::background_to_layer_for_mask(doc, id);
|
||||
let existing = doc.layer(id).and_then(|l| l.mask.as_ref()).cloned().unwrap_or_else(LayerMask::reveal_all);
|
||||
doc.layer_mut(id).ok_or(EngineError::NoLayer(id))?.mask = Some(LayerMask { surface, ..existing });
|
||||
doc.selection = None;
|
||||
|
||||
Reference in new issue
Block a user