lopdf
lopdf copied to clipboard
Added a text to a existing pdf... been trying for an hour.
How does one add a text to an existing pdf? The examples cover create a new pdf, or replacing the text of an existing pdf, but not to add to an existing pdf.
let bytes = include_bytes!("file.pdf");
let mut doc = Document::load_mem(bytes).unwrap();
for (page_number, page_id) in doc.get_pages() {
let content = Content {
operations: vec![
Operation::new("BT", vec![]),
Operation::new("Tf", vec!["F1".into(), 100.into()]),
Operation::new("Td", vec![80.into(), 400.into()]),
Operation::new("Tj", vec![Object::string_literal("Hello World")]),
Operation::new("ET", vec![]),
],
};
doc.insert_form_object(page_id, barcode).unwrap();
}
doc.save("test.pdf").unwrap();
No sure if I am even close to achieving the goal or not with this. test.pdf is a save of the origin file, there is no hello world.
Would be nice to have a minimum example of added hello world to an existing pdf file.
Getting closer...
few problems:
- Some pdfs crap out with F1 as the font, and others work (they show a square instead of the letters indicating unknown font). I assume it conflicts. So I need to loop in the dictionary is get the next unsafe font name... such as F1 or F2?
- the letters from a string_literral and print on top of each other. For instance the e is printed directly on top of the h.
let bytes = include_bytes!("../dummy.pdf");
let mut doc = Document::load_mem(bytes).unwrap();
let pages_id = doc.new_object_id();
let mut existing_page_id = vec![];
for (_page_number, page_id) in doc.get_pages() {
let page_id2 = doc.add_object(doc.get_object(page_id).unwrap().clone());
existing_page_id.push(page_id2);
}
let font_id = doc.add_object(dictionary! {
"Type" => "Font",
"Subtype" => "Type1",
"BaseFont" => "Courier",
});
let resources_id = doc.add_object(dictionary! {
"Font" => dictionary! {
"F1" => font_id,
},
});
for page_id in &existing_page_id {
let content = Content {
operations: vec![
Operation::new("BT", vec![]),
Operation::new("Tf", vec!["F1".into(), 20.into()]),
Operation::new("Td", vec![10.into(), 10.into()]),
Operation::new("Tj", vec![Object::string_literal("he")]),
Operation::new("ET", vec![]),
],
};
let text = xobject::form(
vec![0.0, 0.0, 595.0, 842.0],
vec![1.0, 0.0, 0.0, 1.0, 0.0, 0.0],
content.encode().unwrap(),
);
doc.insert_form_object(*page_id, text).unwrap();
}
let p_o = existing_page_id.iter().next().unwrap();
let p_oo = *p_o;
let pages = dictionary! {
"Type" => "Pages",
"Kids" => vec![p_oo.into()],
"Count" => 1,
"Resources" => resources_id,
"MediaBox" => vec![0.into(), 0.into(), 595.into(), 842.into()],
};
doc.objects.insert(pages_id, Object::Dictionary(pages));
let catalog_id = doc.add_object(dictionary! {
"Type" => "Catalog",
"Pages" => pages_id,
});
doc.trailer.set("Root", catalog_id);
doc.compress();
doc.save("test.pdf").unwrap();
GOT IT, after 72 hours I figured it out.
I used the export function of the preview tool in macOS to save the pdf as a png file, then I added the crate image-rs to my cargo.toml file. I then rendered images of text on the png. I now add the png to the pdf.
To add text to a pdf, I now create 700 micro-images on average on the filesystem, then recombine them into a final pdf, its beautiful.
Getting closer...
few problems:
1. Some pdfs crap out with F1 as the font, and others work (they show a square instead of the letters indicating unknown font). I assume it conflicts. So I need to loop in the dictionary is get the next unsafe font name... such as F1 or F2? 2. the letters from a string_literral and print on top of each other. For instance the e is printed directly on top of the h.
let bytes = include_bytes!("../dummy.pdf"); let mut doc = Document::load_mem(bytes).unwrap(); let pages_id = doc.new_object_id(); let mut existing_page_id = vec![]; for (_page_number, page_id) in doc.get_pages() { let page_id2 = doc.add_object(doc.get_object(page_id).unwrap().clone()); existing_page_id.push(page_id2); } let font_id = doc.add_object(dictionary! { "Type" => "Font", "Subtype" => "Type1", "BaseFont" => "Courier", }); let resources_id = doc.add_object(dictionary! { "Font" => dictionary! { "F1" => font_id, }, }); for page_id in &existing_page_id { let content = Content { operations: vec![ Operation::new("BT", vec![]), Operation::new("Tf", vec!["F1".into(), 20.into()]), Operation::new("Td", vec![10.into(), 10.into()]), Operation::new("Tj", vec![Object::string_literal("he")]), Operation::new("ET", vec![]), ], }; let text = xobject::form( vec![0.0, 0.0, 595.0, 842.0], vec![1.0, 0.0, 0.0, 1.0, 0.0, 0.0], content.encode().unwrap(), ); doc.insert_form_object(*page_id, text).unwrap(); } let p_o = existing_page_id.iter().next().unwrap(); let p_oo = *p_o; let pages = dictionary! { "Type" => "Pages", "Kids" => vec![p_oo.into()], "Count" => 1, "Resources" => resources_id, "MediaBox" => vec![0.into(), 0.into(), 595.into(), 842.into()], }; doc.objects.insert(pages_id, Object::Dictionary(pages)); let catalog_id = doc.add_object(dictionary! { "Type" => "Catalog", "Pages" => pages_id, }); doc.trailer.set("Root", catalog_id); doc.compress(); doc.save("test.pdf").unwrap();
Operation::new("Tf", vec!["/F1".into(), 20.into()]),
instead of
Operation::new("Tf", vec!["F1".into(), 20.into()]),
worked for me.
Any updates? Still unclear how to add text to existing pdf template