Merge PR #7011: Artboards to Files: paths, notes, slices and marks move with the board (#7010)

This commit is contained in:
aiongg
2026-10-18 20:33:44 +00:00
2 changed files with 31 additions and 1 deletions
+4 -1
View File
@@ -9,7 +9,7 @@
use photocraft_color::{Color, ColorMode, PixelFormat, SampleType};
use photocraft_doc::{Artboard, ArtboardBackground, Document, Layer, LayerContent, LayerId, Size};
use photocraft_geom::Rect;
use photocraft_geom::{Affine, Rect};
use photocraft_raster::Surface;
use serde_json::{Value, json};
@@ -506,6 +506,9 @@ pub fn artboard_document(doc: &Document, id: LayerId) -> Result<Option<Document>
one.layer_comps.clear();
one.last_applied_comp = None;
one.last_document_state = None;
// Paths, notes, slices and Count/Ruler marks move with the board. This also shifts
// `one.guides`, but they are rebuilt below from the source's, so nothing moves twice.
crate::canvas_geom::transform_doc_marks(&mut one, &Affine::translate(f64::from(dx), f64::from(dy)));
let shift = |v: &[f64], o: i32, len: u32| v.iter().map(|g| g - f64::from(o)).filter(|g| *g > 0.0 && *g < f64::from(len)).collect::<Vec<_>>();
one.guides.vertical = shift(&doc.guides.vertical, r.x0, r.width());
one.guides.horizontal = shift(&doc.guides.horizontal, r.y0, r.height());
+27
View File
@@ -331,6 +331,33 @@ fn export_rejects_a_board_too_far_from_the_origin() {
assert_eq!(one.artboards()[0].2.rect, Rect::new(0, 0, 50, 50));
}
/// Artboards to Files moves paths, notes, slices and Count/Ruler marks with the board, like its
/// layers and guides, so they land on the same pixels in the exported file.
#[test]
fn artboard_export_moves_paths_notes_slices_and_marks_with_the_board() {
use photocraft_doc::{CountGroup, NamedPath, Note, Path, Slice, Subpath};
let mut s = session(8);
s.execute("layer.new.artboard", json!({"x": 200, "y": 100, "width": 50, "height": 50})).unwrap();
s.edit("marks", |d, _| {
d.paths.push(NamedPath { name: "P".into(), path: Path::new(vec![Subpath::polygon(&[(210.0, 110.0), (240.0, 110.0), (240.0, 140.0)])]), psd_raw: None });
d.work_path = Some(Path::new(vec![Subpath::polygon(&[(205.0, 105.0), (215.0, 105.0), (215.0, 115.0)])]));
d.notes.push(Note { position: [220.0, 120.0], popup: [220.0, 120.0, 260.0, 160.0], ..Default::default() });
d.slices.list.push(Slice { id: 1, rect: Rect::new(210, 110, 230, 130), ..Default::default() });
d.measurement.count_groups.push(CountGroup { points: vec![[225.0, 125.0]], ..Default::default() });
Ok(())
})
.unwrap();
let one = artboard_document(doc(&s), doc(&s).artboards()[0].0).unwrap().unwrap();
let k = &one.paths[0].path.subpaths[0].knots[0].anchor;
assert_eq!((k.x, k.y), (10.0, 10.0));
let w = &one.work_path.as_ref().unwrap().subpaths[0].knots[0].anchor;
assert_eq!((w.x, w.y), (5.0, 5.0));
assert_eq!(one.notes[0].position, [20.0, 20.0]);
assert_eq!(one.notes[0].popup, [20.0, 20.0, 60.0, 60.0]);
assert_eq!(one.slices.list[0].rect, Rect::new(10, 10, 30, 30));
assert_eq!(one.measurement.count_groups[0].points, vec![[25.0, 25.0]]);
}
/// #1531: a board 40×40 at (10, 10) holding a red square at (10..30)², the artboard active.
fn board_with_square(s: &mut Session) -> LayerId {
add_square(s, Rect::new(10, 10, 30, 30), [1.0, 0.0, 0.0, 1.0]);