mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-10 13:01:29 +00:00
Optimize: remove every page's reference to a shared link left with no action
A link annotation listed twice in one page's /Annots, or by two pages, kept its later references after the first one stripped its external action, leaving inert links on the page. Every reference to a link that ends up with no action and no /Dest is now removed. A shared link counts once in external_links.
This commit is contained in:
1 parent
daf93fc532
commit
b87b0d3592
2 files changed
+39
-1
No files matched your search
@@ -373,6 +373,7 @@ fn discard_bookmarks(doc: &mut Document) -> Result<usize, OptimizeError> {
|
||||
/// changed; a link counts whether it was removed or kept for its other actions.
|
||||
pub(crate) fn discard(doc: &mut Document, pages: &[ObjRef]) -> Result<(usize, usize), OptimizeError> {
|
||||
let mut links = 0;
|
||||
let mut removed_links = HashSet::new();
|
||||
for p in pages {
|
||||
let Some(pd) = doc.get(*p).as_dict().cloned() else { continue };
|
||||
let Some(annots) = pd.get(b"Annots").map(|a| doc.resolve(a)).and_then(|a| a.as_array().cloned()) else { continue };
|
||||
@@ -393,7 +394,11 @@ pub(crate) fn discard(doc: &mut Document, pages: &[ObjRef]) -> Result<(usize, us
|
||||
_ => None,
|
||||
};
|
||||
let Some(action) = stripped else {
|
||||
keep.push(x.clone());
|
||||
if !matches!(x, Object::Ref(r) if removed_links.contains(r)) {
|
||||
keep.push(x.clone());
|
||||
} else {
|
||||
changed = true;
|
||||
}
|
||||
continue;
|
||||
};
|
||||
links += 1;
|
||||
@@ -408,6 +413,7 @@ pub(crate) fn discard(doc: &mut Document, pages: &[ObjRef]) -> Result<(usize, us
|
||||
Object::Ref(r) => {
|
||||
doc.set(*r, Object::Dict(d));
|
||||
if removed {
|
||||
removed_links.insert(*r);
|
||||
changed = true;
|
||||
} else {
|
||||
keep.push(x.clone());
|
||||
|
||||
@@ -2436,6 +2436,38 @@ fn links_and_bookmarks_to_other_documents_are_discarded_and_links_within_stay()
|
||||
assert_eq!(chain(&doc, bookmark(&doc, items[1]).get(b"A").unwrap()), ["Named"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn repeated_indirect_remote_link_is_removed_from_one_page() {
|
||||
let (mut doc, p, _) = linked_doc(
|
||||
|doc, _| {
|
||||
let link = doc.add(link_with(Some(action("GoToR", None)), None));
|
||||
vec![Object::Ref(link), Object::Ref(link)]
|
||||
},
|
||||
&[],
|
||||
);
|
||||
let report = optimize(&mut doc, &Settings { discard_external_refs: true, ..Settings::default() }).unwrap();
|
||||
assert_eq!(report.external_links, 1, "{report:?}");
|
||||
assert!(annots_of(&doc, p).is_empty(), "both references leave the page");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shared_indirect_remote_link_with_empty_next_is_removed_from_every_page() {
|
||||
let (mut doc, first, items) = linked_doc(|_, _| Vec::new(), &[action("Named", None), action("GoToR", None)]);
|
||||
let second = page(&mut doc, &[], "BT ET");
|
||||
let link = doc.add(link_with(Some(action("GoToR", Some(Object::Array(vec![Object::Null])))), None));
|
||||
for p in [first, second] {
|
||||
doc.update_dict(p, |d| d.set(b"Annots".to_vec(), Object::Array(vec![Object::Ref(link)]))).unwrap();
|
||||
}
|
||||
doc.update_dict(items[0], |d| d.set(b"First".to_vec(), Object::Ref(items[1]))).unwrap();
|
||||
let report = optimize(&mut doc, &Settings { discard_external_refs: true, ..Settings::default() }).unwrap();
|
||||
assert_eq!(report.external_links, 1, "{report:?}");
|
||||
assert_eq!(report.external_bookmarks, 1, "{report:?}");
|
||||
assert!(doc.get(items[1]).as_dict().unwrap().get(b"A").is_none(), "the shared bookmark has no action");
|
||||
assert!(annots_of(&doc, first).is_empty(), "the first page loses the link");
|
||||
assert!(annots_of(&doc, second).is_empty(), "the second page loses the link");
|
||||
assert!(doc.get(link).as_dict().unwrap().get(b"A").is_none(), "the shared link has no action");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_action_to_another_document_hands_its_place_to_the_actions_after_it() {
|
||||
let (doc, p, _) = linked_doc(
|
||||
|
||||
Reference in new issue
Block a user