mirror of
https://github.com/storytold/designcraft.git
synced 2026-11-05 18:19:57 +00:00
fix(pdf): indexed membership in page ranges, optional content and PDF/X scans (#2207)
This commit is contained in:
1 parent
36da81e03b
commit
7faf7029fb
5 files changed
+28
-8
No files matched your search
@@ -215,6 +215,8 @@ pub fn parse_page_range(s: &str, count: usize) -> Result<Vec<usize>> {
|
||||
let bad = || PdfError::BadRange(s.to_string());
|
||||
let num = |v: &str| v.trim().parse::<usize>().map_err(|_| bad());
|
||||
let mut out = Vec::new();
|
||||
// The pages selected so far, for ranges that overlap (`1-9, 2-8, …`): a set, not a search.
|
||||
let mut selected = vec![false; count];
|
||||
for part in t.split(',').map(str::trim).filter(|p| !p.is_empty()) {
|
||||
let (a, b) = match part.split_once('-') {
|
||||
Some((a, b)) => {
|
||||
@@ -234,7 +236,8 @@ pub fn parse_page_range(s: &str, count: usize) -> Result<Vec<usize>> {
|
||||
if p > count {
|
||||
return Err(PdfError::BadPage(p));
|
||||
}
|
||||
if !out.contains(&(p - 1)) {
|
||||
if let Some(new) = selected.get_mut(p - 1).filter(|s| !**s) {
|
||||
*new = true;
|
||||
out.push(p - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use hayro_syntax::Pdf;
|
||||
use hayro_syntax::object::{Array, Dict, MaybeRef, Name, Object, ObjectIdentifier, Stream};
|
||||
use hayro_syntax::reader::{Reader, ReaderExt};
|
||||
use std::collections::HashSet;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{PdfError, Result};
|
||||
@@ -218,10 +219,12 @@ pub(crate) fn prepare(bytes: &Arc<Vec<u8>>, choice: Option<&[String]>) -> Result
|
||||
}
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
if on.iter().any(|id| off.contains(id)) {
|
||||
let off_set: HashSet<_> = off.iter().copied().collect();
|
||||
if on.iter().any(|id| off_set.contains(id)) {
|
||||
return Err(invalid());
|
||||
}
|
||||
let incomplete = on.iter().chain(&off).any(|id| !groups.contains(id));
|
||||
let group_set: HashSet<_> = groups.iter().copied().collect();
|
||||
let incomplete = on.iter().chain(&off).any(|id| !group_set.contains(id));
|
||||
groups.extend(on.iter().chain(&off).copied());
|
||||
groups.sort();
|
||||
groups.dedup();
|
||||
|
||||
+10
-4
@@ -3,7 +3,7 @@
|
||||
//! krilla's PDF 1.6 output, and a check of the PDF/X-4 requirements this exporter is responsible
|
||||
//! for.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use hayro_syntax::content::UntypedIter;
|
||||
use hayro_syntax::object::{Array, Dict, Name, Object, ObjectIdentifier, Stream};
|
||||
@@ -217,6 +217,7 @@ fn device_rgb(file: Option<&hayro_syntax::Pdf>) -> Vec<String> {
|
||||
return Vec::new();
|
||||
}
|
||||
let mut found: Vec<(String, Vec<usize>)> = Vec::new();
|
||||
let mut at: HashMap<String, usize> = HashMap::new();
|
||||
for (i, page) in file.pages().iter().enumerate() {
|
||||
let mut scan = RgbScan::default();
|
||||
let res = page.resources();
|
||||
@@ -227,9 +228,12 @@ fn device_rgb(file: Option<&hayro_syntax::Pdf>) -> Vec<String> {
|
||||
scan.content(content, res, 0);
|
||||
}
|
||||
for what in scan.found {
|
||||
match found.iter_mut().find(|(w, _)| *w == what) {
|
||||
match at.get(&what).and_then(|k| found.get_mut(*k)) {
|
||||
Some((_, pages)) => pages.push(i + 1),
|
||||
None => found.push((what, vec![i + 1])),
|
||||
None => {
|
||||
at.insert(what.clone(), found.len());
|
||||
found.push((what, vec![i + 1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -274,14 +278,16 @@ pub(crate) const MAX_DEPTH: usize = 16;
|
||||
/// What one page uses in device RGB, in the order found.
|
||||
#[derive(Default)]
|
||||
struct RgbScan {
|
||||
/// What was found, in the order found; `known` is the same as a set.
|
||||
found: Vec<String>,
|
||||
known: HashSet<String>,
|
||||
/// Forms, images and patterns already looked at on this page.
|
||||
seen: HashSet<ObjectIdentifier>,
|
||||
}
|
||||
|
||||
impl RgbScan {
|
||||
fn add(&mut self, what: String) {
|
||||
if !self.found.contains(&what) {
|
||||
if self.known.insert(what.clone()) {
|
||||
self.found.push(what);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -520,7 +520,9 @@ fn disallowed(cs: &Object<'_>, res: &Resources<'_>, depth: usize) -> Option<Stri
|
||||
/// What one page has that PDF/X-1a doesn't allow, in the order found.
|
||||
#[derive(Default)]
|
||||
struct Scan {
|
||||
/// What was found, in the order found; `known` is the same as a set.
|
||||
found: Vec<String>,
|
||||
known: HashSet<String>,
|
||||
font_issues: Vec<String>,
|
||||
seen: HashSet<ObjectIdentifier>,
|
||||
fonts: HashSet<ObjectIdentifier>,
|
||||
@@ -528,7 +530,7 @@ struct Scan {
|
||||
|
||||
impl Scan {
|
||||
fn add(&mut self, what: String) {
|
||||
if !self.found.contains(&what) {
|
||||
if self.known.insert(what.clone()) {
|
||||
self.found.push(what);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,6 +178,12 @@ fn spreads_and_ranges() {
|
||||
assert_eq!(parse_page_range("1-2, 4", 4).unwrap(), vec![0, 1, 3]);
|
||||
assert_eq!(parse_page_range("3-", 4).unwrap(), vec![2, 3]);
|
||||
assert_eq!(parse_page_range("", 2).unwrap(), vec![0, 1]);
|
||||
// Ranges that overlap many times over: each page is selected once, in the order first named.
|
||||
let overlapping = std::iter::repeat_n("1-20000, 5-19000", 500).collect::<Vec<_>>().join(",");
|
||||
let t = std::time::Instant::now();
|
||||
assert_eq!(parse_page_range(&overlapping, 20000).unwrap().len(), 20000);
|
||||
assert!(t.elapsed() < std::time::Duration::from_secs(5), "{:?}", t.elapsed());
|
||||
assert_eq!(parse_page_range("3, 1-3", 4).unwrap(), vec![2, 0, 1]);
|
||||
assert!(parse_page_range("5", 4).is_err());
|
||||
assert!(parse_page_range("x", 4).is_err());
|
||||
let bytes = export_pdf(&d, &Cache::new(), &PdfOptions { pages: Some(vec![1, 2]), ..Default::default() }).unwrap();
|
||||
|
||||
Reference in new issue
Block a user