#pdf-document #object #content #stream #dictionary #reference #lopdf

lopdf_bugfix_19072017

Rust 用于 PDF 文档操作的库

1 个不稳定版本

使用旧的 Rust 2015

0.9.0 2017年7月19日

#17 in #pdf-document

MIT 许可证

59KB
1.5K SLoC

lopdf

Crates.io Build Status

Rust 用于 PDF 文档操作的库。

示例代码

  • 创建 PDF 文档
extern crate lopdf;
use lopdf::{Document, Object, Dictionary, Stream, StringFormat};
use lopdf::content::{Content, Operation};
use Object::Reference;
use std::iter::FromIterator;

let mut doc = Document::new();
doc.version = "1.5".to_string();
let pages_id = doc.new_object_id();
let font_id = doc.add_object(
	Dictionary::from_iter(vec![
		("Type", "Font".into()),
		("Subtype", "Type1".into()),
		("BaseFont", "Courier".into()),
	])
);
let resources_id = doc.add_object(
	Dictionary::from_iter(vec![
		("Font", Dictionary::from_iter(vec![
			("F1", Reference(font_id)),
		]).into()),
	])
);
let content = Content{operations: vec![
	Operation::new("BT", vec![]),
	Operation::new("Tf", vec!["F1".into(), 48.into()]),
	Operation::new("Td", vec![100.into(), 600.into()]),
	Operation::new("Tj", vec![Object::String(b"Hello World!".to_vec(), StringFormat::Literal)]),
	Operation::new("ET", vec![]),
]};
let content_id = doc.add_object(Stream::new(Dictionary::new(), content.encode().unwrap()));
let page_id = doc.add_object(
	Dictionary::from_iter(vec![
		("Type", "Page".into()),
		("Parent", Reference(pages_id)),
		("Contents", vec![Reference(content_id)].into()),
	])
);
let pages = Dictionary::from_iter(vec![
	("Type", "Pages".into()),
	("Kids", vec![Reference(page_id)].into()),
	("Count", 1.into()),
	("Resources", Reference(resources_id)),
	("MediaBox", vec![0.into(), 0.into(), 595.into(), 842.into()].into()),
]);
doc.objects.insert(pages_id, Object::Dictionary(pages));
let catalog_id = doc.add_object(
	Dictionary::from_iter(vec![
		("Type", "Catalog".into()),
		("Pages", Reference(pages_id)),
	])
);
doc.trailer.set("Root", Reference(catalog_id));
doc.compress();
doc.save("example.pdf").unwrap();
  • 修改 PDF 文档
let mut doc = Document::load("example.pdf")?;
doc.version = "1.4".to_string();
if let Some(content_stream) = doc.objects.get_mut(&(3, 0)) {
	match *content_stream {
		Object::Stream(ref mut stream) => {
			let mut content = stream.decode_content().unwrap();
			content.operations[3].operands[0] = Object::String(
				b"Modified text!".to_vec(),
				StringFormat::Literal);
			stream.set_content(content.encode().unwrap());
		},
		_ => ()
	}
}
doc.save("modified.pdf")?;

常见问题解答

  • 为什么直到最终序列化整个文档之前都将所有内容保持在内存中作为高级对象?

    通常 PDF 文档不会很大,大小从几十 KB 到几百 MB。内存大小不是当今计算机的瓶颈。通过将整个文档保持在内存中,可以预先计算流长度,无需使用引用对象来计算 Length 条目,生成的 PDF 文件更适合分发,并且 PDF 消费者处理起来更快。

    生产是一次性工作,而消费则更多。

依赖关系

~3.5MB
~54K SLoC