mirror of
https://github.com/storytold/designcraft.git
synced 2026-11-03 07:01:09 -06:00
Integration: PDF crop box is part of an asset's identity; clippings keep anchored graphics (#391)
Asset::same_file compares pdf_crop (#362) with type, page and bytes: one PDF page shown with two crop boxes keeps two assets, so add_asset, adopt_asset, insert_asset (IDML/INDD import) and the load/save merge never point a placement at another crop. Test in identical_files_share_one_asset. The copy clipping (edit.rs clip_doc) keeps the assets used_assets finds in it, so graphics anchored in copied text, graphic table cells (#379), notes and media posters keep their files; it collected only graphics on the copied items before. Test: copied_text_frames_keep_the_graphics_anchored_in_their_text.
This commit is contained in:
@@ -15,10 +15,11 @@ use crate::{Asset, AssetId, Content, Document, Item};
|
||||
const MAX_DEPTH: usize = 64;
|
||||
|
||||
impl Asset {
|
||||
/// Whether `other` holds the same file: the same type, page and bytes. Assets without bytes
|
||||
/// (a link that couldn't be read) are the same only when they link to the same path.
|
||||
/// Whether `other` holds the same file: the same type, page, PDF crop box and bytes. Assets
|
||||
/// without bytes (a link that couldn't be read) are the same only when they link to the same
|
||||
/// path.
|
||||
pub fn same_file(&self, other: &Asset) -> bool {
|
||||
if self.mime != other.mime || self.page != other.page {
|
||||
if self.mime != other.mime || self.page != other.page || self.pdf_crop != other.pdf_crop {
|
||||
return false;
|
||||
}
|
||||
match (self.data.is_empty(), other.data.is_empty()) {
|
||||
@@ -306,6 +307,13 @@ mod tests {
|
||||
let b = d.add_asset(Asset { link: Some("/x/p.png".into()), ..asset(2, b"same") });
|
||||
let c = d.add_asset(asset(3, b"diff"));
|
||||
let p = d.add_asset(Asset { page: 1, ..asset(4, b"same") });
|
||||
// One PDF page shown with two crop boxes: two assets (the box is the asset's).
|
||||
let pdf = |id, pdf_crop| Asset { mime: "application/pdf".into(), pdf_crop, ..asset(id, b"%PDF") };
|
||||
let crop = d.add_asset(pdf(9, crate::PdfCrop::Crop));
|
||||
let art = d.add_asset(pdf(10, crate::PdfCrop::Art));
|
||||
assert_ne!(crop, art);
|
||||
assert_eq!(d.add_asset(pdf(11, crate::PdfCrop::Art)), art);
|
||||
d.assets.retain(|id, _| ![crop, art].contains(id));
|
||||
assert_eq!(a, b);
|
||||
assert_ne!(a, c);
|
||||
assert_ne!(a, p);
|
||||
|
||||
@@ -300,18 +300,13 @@ pub(crate) fn clip_doc(s: &Session) -> Result<designcraft_doc::Document> {
|
||||
for sp in d.spreads.iter_mut() {
|
||||
Arc::make_mut(sp).items.clear();
|
||||
}
|
||||
// Kept frames and graphics (including inside groups).
|
||||
// Kept frames (including inside groups).
|
||||
let mut frames = std::collections::HashSet::new();
|
||||
let mut assets = std::collections::HashSet::new();
|
||||
for it in &items {
|
||||
it.walk(&mut |i| match &i.content {
|
||||
designcraft_doc::Content::Text(_) => {
|
||||
it.walk(&mut |i| {
|
||||
if let designcraft_doc::Content::Text(_) = &i.content {
|
||||
frames.insert(i.id);
|
||||
}
|
||||
designcraft_doc::Content::Graphic(g) => {
|
||||
assets.insert(g.asset);
|
||||
}
|
||||
_ => {}
|
||||
});
|
||||
}
|
||||
if let Some(sp) = d.spreads.first_mut() {
|
||||
@@ -325,6 +320,8 @@ pub(crate) fn clip_doc(s: &Session) -> Result<designcraft_doc::Document> {
|
||||
for st in d.stories.values_mut() {
|
||||
Arc::make_mut(st).frames.retain(|f| frames.contains(f));
|
||||
}
|
||||
// Graphics on the items and in the kept stories (anchored objects, graphic cells, notes).
|
||||
let assets = d.used_assets();
|
||||
d.assets.retain(|k, _| assets.contains(k));
|
||||
d.hyperlinks.clear();
|
||||
d.bookmarks.clear();
|
||||
@@ -545,6 +542,28 @@ mod paste_tests {
|
||||
assert_eq!(pasted(&mut s, "edit.pasteInPlace", json!({"spread": 1})), (SpreadRef::Doc(1), Rect::new(w + 36.0, 36.0, w + 136.0, 136.0)));
|
||||
}
|
||||
|
||||
/// A copied text frame's clipping holds the files its anchored graphics show.
|
||||
#[test]
|
||||
fn copied_text_frames_keep_the_graphics_anchored_in_their_text() {
|
||||
let mut s = Session::new();
|
||||
s.execute("file.new", &json!({})).unwrap();
|
||||
let png = designcraft_render::Rendered { width: 4, height: 4, pixels: vec![200u8; 64] }.to_png();
|
||||
let placed = s.execute("file.place", &json!({"base64": super::super::file::base64_encode(&png), "name": "a.png", "x": 72, "y": 72})).unwrap();
|
||||
let (g, aid) = (ItemId(placed["id"].as_u64().unwrap()), designcraft_doc::AssetId(placed["asset"].as_u64().unwrap()));
|
||||
let f = ItemId(s.execute("frame.create", &json!({"rect": [36, 200, 300, 400], "content": "text"})).unwrap()["id"].as_u64().unwrap());
|
||||
s.edit(|d, _| {
|
||||
let it = d.item(g).cloned().ok_or(designcraft_doc::DocError::NoItem(g))?;
|
||||
let sid = d.item(f).and_then(|i| i.text_frame()).map(|t| t.story).ok_or(designcraft_doc::DocError::NoItem(f))?;
|
||||
super::super::anchored::anchor_items(d, sid, 0, vec![it], &Default::default())?;
|
||||
Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
s.execute("selection.set", &json!({"ids": [f.0]})).unwrap();
|
||||
s.execute("edit.copy", &json!({})).unwrap();
|
||||
let clip = s.clipboard.clone().unwrap();
|
||||
assert_eq!(clip.assets.keys().copied().collect::<Vec<_>>(), [aid]);
|
||||
}
|
||||
|
||||
/// Undo leaves the id of the copy it removed in the selection. Copy measures from the spread
|
||||
/// of the first selected object that is still there.
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user