Rust PDF处理库pdf_derive的使用,简化PDF文件生成与解析的派生宏实现

以下是关于Rust PDF处理库pdf_derive的使用介绍,简化PDF文件生成与解析的派生宏实现的完整示例:

首先需要在Cargo.toml中添加依赖:

[dependencies]
pdf_derive = "0.2.0"

然后是一个使用pdf_derive派生宏的完整示例:

use pdf_derive::*;
use std::collections::HashMap;

// 定义一个PDF对象结构体
#[derive(Debug, PdfObject)]
struct MyPdfDocument {
    #[pdf(key="Type")]        // 指定PDF字典中的键名为"Type"
    doc_type: String,         // 文档类型字段
    #[pdf(key="Pages")]       // 指定PDF字典中的键名为"Pages"
    pages_count: i32,         // 页数字段
    #[pdf(key="Author")]      // 指定PDF字典中的键名为"Author"
    author: Option<String>,   // 可选作者字段
    #[pdf(key="Metadata", default)] // 指定默认值
    metadata: Vec<u8>,        // 元数据字段
}

fn main() {
    // 创建一个PDF文档实例
    let doc = MyPdfDocument {
        doc_type: "Catalog".to_string(),
        pages_count: 10,
        author: Some("John Doe".to_string()),
        metadata: vec![], // 使用默认值
    };

    // 将PDF对象序列化为字典
    let dict = doc.to_dict();
    println!("Serialized PDF dictionary: {:?}", dict);

    // 从字典反序列化PDF对象
    let mut dict = HashMap::new();
    dict.insert("Type".to_string(), PdfObject::Name("Catalog".to_string()));
    dict.insert("Pages".to_string(), PdfObject::Integer(10));
    dict.insert("Author".to_string(), PdfObject::Name("John Doe".to_string()));
    
    let doc: MyPdfDocument = MyPdfDocument::from_dict(&dict).unwrap();
    println!("Deserialized PDF document: {:?}", doc);
}

这个示例展示了如何使用pdf_derive的PdfObject派生宏来:

  1. 定义一个PDF文档结构体
  2. 使用属性宏指定PDF字段名和默认值
  3. 自动实现序列化和反序列化方法
  4. 处理可选字段和默认值

关键特性说明:

  • #[pdf(key="...")] 属性指定PDF字典中的键名
  • Option<T> 类型表示可选字段
  • #[pdf(default)] 属性指定字段使用默认值
  • 自动实现to_dict()from_dict()方法用于序列化和反序列化

该库简化了PDF文档的生成和解析过程,通过派生宏自动处理了大部分样板代码。

以下是更完整的示例demo,展示了PDF文档的创建、修改和保存:

use pdf_derive::*;
use std::collections::HashMap;
use std::fs::File;
use std::io::Write;

#[derive(Debug, PdfObject)]
struct PdfCatalog {
    #[pdf(key="Type")]
    doc_type: String,
    #[pdf(key="Pages")]
    pages: i32,
    #[pdf(key="Title")]
    title: Option<String>,
}

#[derive(Debug, PdfObject)]
struct PdfPage {
    #[pdf(key="Type")]
    page_type: String,
    #[pdf(key="Parent")]
    parent: String,
    #[pdf(key="Contents")]
    contents: Vec<u8>,
}

fn main() -> std::io::Result<()> {
    // 创建PDF目录
    let mut catalog = PdfCatalog {
        doc_type: "Catalog".to_string(),
        pages: 1,
        title: Some("My PDF Document".to_string()),
    };

    // 创建PDF页面
    let page = PdfPage {
        page_type: "Page".to_string(),
        parent: "Catalog".to_string(),
        contents: b"Hello PDF World!".to_vec(),
    };

    // 序列化对象
    let catalog_dict = catalog.to_dict();
    let page_dict = page.to_dict();

    println!("Catalog: {:?}", catalog_dict);
    println!("Page: {:?}", page_dict);

    // 修改页面内容
    let mut modified_page = page;
    modified_page.contents = b"Modified Content!".to_vec();

    // 保存到文件
    let mut file = File::create("document.pdf")?;
    file.write_all(b"%PDF-1.7\n")?;
    // 这里添加实际的PDF内容写入逻辑
    file.write_all(b"%%EOF\n")?;

    Ok(())
}

这个完整示例展示了:

  1. 定义多个PDF对象结构体
  2. 创建和修改PDF对象
  3. 序列化为字典格式
  4. 基本的PDF文件保存功能
  5. 展示了更复杂的PDF文档结构

注意:实际生成PDF文件需要更完整的PDF格式实现,这个示例主要展示pdf_derive库的使用方法。


1 回复

Rust PDF处理库pdf_derive的使用指南

概述

pdf_derive是一个Rust库,通过派生宏(derive macro)简化PDF文件的生成和解析过程。它允许开发者使用Rust结构体来定义PDF文档结构,然后自动生成序列化和反序列化的代码。

主要特性

  • 通过派生宏自动实现PDF对象的序列化/反序列化
  • 简化PDF文档结构的定义
  • 类型安全的PDF操作
  • 减少手动编写PDF格式代码的工作量

安装

在Cargo.toml中添加依赖:

[dependencies]
pdf_derive = "0.1"  # 请检查最新版本
pdf = "0.8"  # 基础pdf库

基本使用方法

1. 定义PDF对象结构体

use pdf_derive::{PdfWrite, PdfObj};

#[derive(PdfObj, PdfWrite)]
struct MyPdfObject {
    title: String,
    author: String,
    page_count: u32,
    is_encrypted: bool,
}

2. 生成PDF文档

use pdf::file::File;
use pdf::object::*;
use pdf::build::*;

fn create_pdf() -> Result<(), pdf::error::PdfError> {
    let mut builder = Builder::new();
    
    let my_obj = MyPdfObject {
        title: "My Document".to_string(),
        author: "John Doe".to_string(),
        page_count: 10,
        is_encrypted: false,
    };
    
    let obj_ref = builder.add(my_obj)?;
    
    // 创建文档结构
    let mut catalog = CatalogBuilder::new();
    let mut pages = PagesBuilder::new();
    
    // 添加页面等操作...
    
    builder.build("output.pdf")?;
    Ok(())
}

3. 解析PDF文档

fn read_pdf(path: &str) -> Result<(), pdf::error::PdfError> {
    let file = File::open(path)?;
    
    // 假设我们知道对象在索引1的位置
    if let Some(my_obj) = file.get(1)?.as_dict() {
        let parsed: MyPdfObject = my_obj.try_into()?;
        println!("Title: {}", parsed.title);
        println!("Author: {}", parsed.author);
    }
    
    Ok(())
}

高级用法

自定义字段映射

#[derive(PdfObj, PdfWrite)]
struct CustomObject {
    #[pdf(key = "/CustomName")]
    normal_name: String,
    
    #[pdf(skip)]  // 跳过序列化
    internal_data: Vec<u8>,
}

嵌套对象

#[derive(PdfObj, PdfWrite)]
struct PageInfo {
    width: f32,
    height: f32,
}

#[derive(PdfObj, PdfWrite)]
struct Document {
    info: PageInfo,
    pages: Vec<String>,  // 页面内容
}

完整示例代码

// src/pdf_models.rs
use pdf_derive::{PdfObj, PdfWrite};

// 定义PDF文档信息结构体
#[derive(PdfObj, PdfWrite, Debug)]
pub struct DocumentInfo {
    #[pdf(key = "/Title")]
    pub title: String,
    
    #[pdf(key = "/Author")]
    pub author: String,
    
    #[pdf(key = "/CreationDate")]
    pub creation_date: String,
    
    #[pdf(skip)]
    pub internal_id: u32,  // 不序列化到PDF中
}

// 定义页面结构体
#[derive(PdfObj, PdfWrite)]
pub struct PdfPage {
    pub width: f32,
    pub height: f32,
    pub contents: String,
}

// src/main.rs
use pdf::{
    build::*,
    error::PdfError,
    file::File,
    object::*,
};
use pdf_derive::{PdfObj, PdfWrite};
use crate::pdf_models::{DocumentInfo, PdfPage};

fn main() -> Result<(), PdfError> {
    // 创建PDF文档
    create_sample_pdf()?;
    
    // 读取PDF文档
    read_sample_pdf("sample.pdf")?;
    
    Ok(())
}

fn create_sample_pdf() -> Result<(), PdfError> {
    let mut builder = Builder::new();
    
    // 创建文档信息
    let info = DocumentInfo {
        title: "示例文档".to_string(),
        author: "Rust开发者".to_string(),
        creation_date: "D:20230101000000".to_string(),
        internal_id: 12345,
    };
    
    // 创建页面内容
    let page1 = PdfPage {
        width: 595.0,  // A4宽度
        height: 842.0, // A4高度
        contents: "BT /F1 24 Tf 100 700 Td (Hello, PDF世界!) Tj ET".to_string(),
    };
    
    // 添加到PDF构建器
    let _info_ref = builder.add(info)?;
    let _page_ref = builder.add(page1)?;
    
    // 构建并保存PDF
    builder.build("sample.pdf")?;
    
    println!("PDF创建成功!");
    Ok(())
}

fn read_sample_pdf(path: &str) -> Result<(), PdfError> {
    let file = File::open(path)?;
    
    // 遍历所有对象
    for i in 1..file.len() {
        if let Ok(obj) = file.get(i) {
            if let Some(dict) = obj.as_dict() {
                // 尝试解析为DocumentInfo
                if let Ok(info) = dict.try_into::<DocumentInfo>() {
                    println!("找到文档信息:");
                    println!("标题: {}", info.title);
                    println!("作者: {}", info.author);
                    println!("创建日期: {}", info.creation_date);
                }
                
                // 尝试解析为PdfPage
                if let Ok(page) = dict.try_into::<PdfPage>() {
                    println!("\n找到页面:");
                    println!("尺寸: {}x{}", page.width, page.height);
                    println!("内容: {}", page.contents);
                }
            }
        }
    }
    
    Ok(())
}

注意事项

  1. 确保结构体字段类型实现了必要的trait(如PdfWrite
  2. 复杂PDF操作可能需要直接使用底层的pdf
  3. 派生宏目前可能不支持所有PDF特性,检查文档了解限制

示例项目结构

my_pdf_project/
├── Cargo.toml
└── src/
    ├── main.rs
    └── pdf_models.rs  # 放置PDF结构体定义

pdf_derive通过简化PDF处理代码,让开发者能更专注于业务逻辑而不是PDF格式细节。对于更复杂的需求,可以结合使用底层的pdf库功能。

回到顶部