如何使用Rust的lopdf库向现有PDF文件添加hello world文本
用lopdf给现有PDF添加文本的正确实现
你现有代码的问题是完全新建了页面树和页面对象,覆盖了原PDF的所有页面结构,导致原有内容丢失,新增的内容也因为页面属性匹配问题无法正常显示。正确的做法是直接在原有页面的基础上追加内容,不要修改原有的页面树结构。
依赖配置
Cargo.toml中添加:
lopdf = "0.31"
完整可运行代码
use lopdf::{Document, Object, Stream, dictionary, Content, Operation}; fn main() { // 加载原有PDF let bytes = include_bytes!("dummy.pdf"); let mut doc = Document::load_mem(bytes).unwrap(); // 先创建全局共用的字体对象 let font_id = doc.add_object(dictionary! { "Type" => "Font", "Subtype" => "Type1", "BaseFont" => "Courier", }); // 构造要追加的文本内容 let add_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")]), Operation::new("ET", vec![]), Operation::new("BT", vec![]), Operation::new("Tf", vec!["F1".into(), 12.into()]), Operation::new("Td", vec![10.into(), 800.into()]), Operation::new( "Tj", vec![Object::string_literal("hello world.")], ), Operation::new("ET", vec![]), Operation::new("BT", vec![]), Operation::new("Tf", vec!["F1".into(), 10.into()]), Operation::new("Td", vec![10.into(), 780.into()]), Operation::new( "Tj", vec![Object::string_literal("to")], ), Operation::new("ET", vec![]), ], }; let add_content_bytes = add_content.encode().unwrap(); let add_content_id = doc.add_object(Stream::new(dictionary! {}, add_content_bytes)); // 遍历所有原有页面,追加内容 for (_, page_id) in doc.get_pages() { let page = doc.get_object_mut(page_id).unwrap().as_dict_mut().unwrap(); // 给当前页面添加字体资源 let resources = page.get_mut(b"Resources").and_then(|r| r.as_dict_mut()).ok(); match resources { Some(res) => { let fonts = res.get_mut(b"Font").and_then(|f| f.as_dict_mut()).ok(); match fonts { Some(font_dict) => { font_dict.set("F1", font_id); } None => { res.set("Font", dictionary! { "F1" => font_id }); } } } None => { page.set("Resources", dictionary! { "Font" => dictionary! { "F1" => font_id } }); } } // 合并原有内容流和新增内容流 let original_content = page.get(b"Contents").unwrap(); let new_contents = if original_content.is_array() { let mut arr = original_content.as_array().unwrap().clone(); arr.push(add_content_id.into()); Object::Array(arr) } else { Object::Array(vec![original_content.clone(), add_content_id.into()]) }; page.set("Contents", new_contents); } // 直接保存即可,不需要修改原有Catalog和Root doc.save("test.pdf").unwrap(); }
注意事项
- PDF的坐标原点在页面左下角,Y轴向上,你可以根据需要调整
Td操作的坐标值修改文本位置 - 如果要给不同页面加不同的文本,单独构造每个页面对应的内容流即可
- 针对有加密的PDF需要先调用解密接口处理后再修改
内容的提问来源于stack exchange,提问作者Anon21
相关产品推荐
相关产品推荐

