fix: 粘贴图片填充时避开目标文件已占用的图片键

目标文件已有同名键但数据不同时,粘贴的 paint 改用复制数据的内容哈希键,避免渲染成目标文件里的图片;目标文件原图片保留给已有图层。
This commit is contained in:
Nicek
2026-10-29 09:33:55 +08:00
committed by trae-solo-agent
parent c6ba81b6e6
commit 4c0eb71a4c
2 changed files with 33 additions and 5 deletions
+10 -5
View File
@@ -365,7 +365,7 @@ pub(super) fn paint_copy(s: &mut Session, p: &Value, fills: bool) -> Result<Valu
/// stroke's copied settings go onto each target too.
pub(super) fn paint_paste(s: &mut Session, p: &Value, fills: bool) -> Result<Value> {
let cmd = if fills { "fill.paste" } else { "stroke.paste" };
let Some((copied_fills, paint)) = s.clipboard.paint.clone() else {
let Some((copied_fills, mut paint)) = s.clipboard.paint.clone() else {
return Err(EngineError::Disabled(cmd.into(), "no copied fill or stroke".into()));
};
if copied_fills != fills {
@@ -386,10 +386,15 @@ pub(super) fn paint_paste(s: &mut Session, p: &Value, fills: bool) -> Result<Val
}
}
// An image paint names its data by key; a copy from another file brings the data with it.
if let figcraft_color::PaintKind::Image(img) = &paint.kind {
let key = img.image.clone();
if let Some(d) = s.clipboard.paint_images.get(&key).cloned() {
s.doc_mut()?.images.entry(key).or_insert(d);
if let figcraft_color::PaintKind::Image(img) = &mut paint.kind {
let copied = img.image.clone();
if let Some(d) = s.clipboard.paint_images.get(&copied).cloned() {
let doc = s.doc_mut()?;
// The destination may already use that key for different data (other layers keep
// that image): the pasted paint takes the copied data's content hash instead.
let key = if doc.images.get(&copied).is_some_and(|existing| existing != &d) { figcraft_format::image_hash(&d.bytes) } else { copied };
doc.images.entry(key.clone()).or_insert(d);
img.image = key;
}
}
let mut q = json!({"ids": ids, "paint": serde_json::to_value(paint).map_err(|e| bad(cmd, e.to_string()))?});
+23
View File
@@ -120,6 +120,29 @@ fn a_copied_image_fill_brings_its_image_to_another_file() {
assert!(matches!(node(&s, b).fills[0].kind, figcraft_color::PaintKind::Image(_)));
}
#[test]
fn a_copied_image_key_taken_in_another_file_gets_the_copied_data() {
let mut s = Session::new();
let a = rect(&mut s);
let copied = figcraft_doc::ImageData { bytes: std::sync::Arc::new(vec![1, 2, 3]), width: 2, height: 2 };
let taken = figcraft_doc::ImageData { bytes: std::sync::Arc::new(vec![9, 9, 9]), width: 3, height: 3 };
ex(&mut s, "fill.add", json!({"ids": [a], "paint": {"type": "image", "image": "img-key"}}));
s.doc_mut().unwrap().images.insert("img-key".into(), copied.clone());
ex(&mut s, "fill.copy", json!({"id": a, "index": 1}));
// The other file already uses that key for different data: the pasted paint takes a content
// key for the copied data instead, and the destination's image stays as it is.
ex(&mut s, "file.new", json!({}));
let b = rect(&mut s);
s.doc_mut().unwrap().images.insert("img-key".into(), taken.clone());
ex(&mut s, "fill.paste", json!({"ids": [b], "index": 0}));
let doc = s.doc().unwrap();
let fill = &doc.node(b).unwrap().fills[0];
let figcraft_color::PaintKind::Image(img) = &fill.kind else { panic!("the pasted fill is an image") };
assert_ne!(img.image, "img-key");
assert_eq!(doc.images.get(&img.image), Some(&copied));
assert_eq!(doc.images.get("img-key"), Some(&taken), "the destination's image stays");
}
#[test]
fn a_copied_pattern_does_not_paste_into_another_file() {
let mut s = Session::new();