Merge pull request #3042 from KnottyDyes/squad/place-pdf-keeps-text

PDF: placed and pasted pages keep live text
This commit is contained in:
BFlat
2026-10-19 23:13:58 +07:00
committed by GitHub
5 changed files with 79 additions and 3 deletions
+2 -2
View File
@@ -143,13 +143,13 @@ pub(super) fn import(bytes: &[u8], o: &LoadOptions, editor_document: bool) -> Re
}
/// Page `page` (0-based) of a PDF as a document of one artboard (its `o.crop` box) and one
/// layer of what it shows (text as outlines: it looks as printed), and the import notes.
/// layer of what it shows, with the same text choice as Open, and the import notes.
pub fn page_document(bytes: &[u8], page: usize, o: &LoadOptions) -> Result<(Document, Vec<String>)> {
let opts = ImportOptions {
pages: Some(vec![page]),
crop: o.crop,
password: o.password.clone(),
text_as: TextAs::Outlines,
text_as: o.text_as,
layers: false,
..Default::default()
};
@@ -38,6 +38,64 @@ fn text_opens_as_type_or_outlines() {
assert!(e.contains("textAs must be one of text, outlines"), "{e}");
}
fn live_text_pdf() -> Vec<u8> {
let page = |text: &str| PdfPage {
resources: "/Font << /F1 << /Type /Font /Subtype /Type1 /BaseFont /Helvetica >> >>".into(),
..PdfPage::new(200.0, 100.0, &format!("BT /F1 12 Tf 10 50 Td ({text}) Tj ET"))
};
pdf(&[page("First page"), page("Second page")], None)
}
fn live_texts(s: &Session) -> Vec<String> {
let mut texts = vec![];
s.doc().unwrap().doc.walk(|n| {
if let NodeKind::Text(t) = &n.kind {
texts.push(t.plain_text());
}
});
texts
}
#[test]
fn pdf_place_keeps_live_text_from_bytes_and_unlinked_paths() {
let bytes = live_text_pdf();
let dir = vectorcraft_testkit::temp_dir("pdf-place-live-text");
let path = dir.join("text.pdf");
std::fs::write(&path, &bytes).unwrap();
for source in [json!({"name": "text.pdf", "dataBase64": vectorcraft_format::base64_encode(&bytes)}), json!({"path": path, "link": false})] {
let mut s = Session::new();
s.execute("file.new", &json!({"width": 400, "height": 300})).unwrap();
let mut p = source;
p["page"] = json!(2);
let r = s.execute("file.place", &p).unwrap();
assert_eq!(live_texts(&s), ["Second page"], "{r}");
assert!(!r["warnings"].to_string().contains("outlines"), "{r}");
}
std::fs::remove_dir_all(dir).unwrap();
}
#[test]
fn pdf_clipboard_paste_keeps_live_text_on_the_selected_page() {
let bytes = live_text_pdf();
let mut s = Session::new();
s.execute("file.new", &json!({"width": 400, "height": 300})).unwrap();
let r = s.execute("clipboard.importPdf", &json!({"dataBase64": vectorcraft_format::base64_encode(&bytes), "page": 2})).unwrap();
s.execute("edit.paste", &json!({})).unwrap();
assert_eq!(live_texts(&s), ["Second page"], "{r}");
assert!(!r["warnings"].to_string().contains("outlines"), "{r}");
}
#[test]
fn pdf_place_honors_explicit_text_outlines() {
let bytes = live_text_pdf();
let mut s = Session::new();
s.execute("file.new", &json!({"width": 400, "height": 300})).unwrap();
let r =
s.execute("file.place", &json!({"name": "text.pdf", "dataBase64": vectorcraft_format::base64_encode(&bytes), "textAs": "outlines"})).unwrap();
assert!(live_texts(&s).is_empty());
assert!(r["warnings"].to_string().contains("outlines"), "{r}");
}
#[test]
fn layers_option_keeps_or_flattens_optional_content() {
let (a, b) = (first_extra(1), first_extra(1) + 1);
File diff suppressed because one or more lines are too long
+5
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long