【Rust在WASM中实现pdf文件的生成】

Rust在WASM中实现pdf文件的生成

概念和依赖

. WASM

WebAssembly(简称WASM)是一个虚拟指令集体系架构(virtual ISA),旨在为C/C++等语言编写的程序提供一种高效的二进制格式,使其能够在Web平台上以接近原生应用的运行速度运行‌。‌

跨平台‌:WebAssembly兼容所有主流浏览器,如Chrome、Firefox、Safari和Edge。Rust编写的代码可以轻松移植到不同的平台‌。

. Rust

Rust是一种系统编程语言,以其内存安全和高性能著称,是开发WebAssembly应用的理想选择‌‌

. Trunk

Trunk 是一款专为 Rust 语言设计的 WASM 网页应用打包工具。它能够帮助开发者轻松构建、打包并发布 Rust 编写的 WASM 应用到 Web 平台。Trunk 的设计理念是简单、高效,通过一个源 HTML 文件,Trunk 可以自动处理 WASM、JS 片段以及其他资源(如图片、CSS、SCSS)的打包工作。

本文的大部分依照这个而来:https://trunkrs.dev/guide/getting-started/index.html

项目:https://github.com/trunk-rs/trunk/tree/main

. printpdf

目前使用0.7的版本

https://docs.rs/printpdf/latest/printpdf/index.html

这是一个rust实现的生成pdf的工具,目前documnet-info.rs会在wasm中有两处错误。删除出错行就能在wasm环境使用。

问题描述

https://blog.csdn.net/wjcroom/article/details/143548767

在这个文章中,虽然使用了后端flask生成pdf,但唯一目的是打印,后端完全无必要来回传数据。本文要实现的wasm将图片在本地转pdf并显示。

因为这是一个验证性的工作,不具备很大的实际意义。但此架构可以构造一些功能强大本地wasn应用,比如,批量格式化一批数据到pdf格式,套用模板打印等等。

分步实现

  • 图片到pdf的转换
    先建立空项目
c 复制代码
$ cargo new hello_cargo
$ cd hello_cargo

本文所用printpdf,要想开始image功能需要在Cargo.toml文件定义以下内容

c 复制代码
[dependencies]
printpdf = { version = "0.7.0", features = [ "embedded_images" ] }

然后在main中测试主逻辑,拷贝printpdf在演示代码

c 复制代码
fn main() {
    println!("Hello, world!");

let (doc, page1, layer1) = PdfDocument::new("PDF_Document_title",  Mm(210.0),Mm(297.0), "Layer 1");
let current_layer = doc.get_page(page1).get_layer(layer1);

// currently, the only reliable file formats are bmp/jpeg/png
// this is an issue of the image library, not a fault of printpdf
let mut image_file = File::open("tmp.png").unwrap();
let image = Image::try_from( image_crate::codecs::png::PngDecoder::new(&mut image_file).unwrap()).unwrap();
let rotation_center_x = Px((image.image.width.0 as f32 / 2.0) as usize);
let rotation_center_y = Px((image.image.height.0 as f32 / 2.0) as usize);

// layer,
image.add_to_layer(
    current_layer.clone(),
    ImageTransform {
        rotate: Some(ImageRotation {
            angle_ccw_degrees: 0.0,
            rotation_center_x,
            rotation_center_y,
        }),
        scale_x:  Some( 2.4),
        scale_y:   Some( 2.4),
        translate_x: Some(Mm(9.0)),
        translate_y: Some(Mm(9.0)),
        ..Default::default()
    },
);


doc.save(&mut BufWriter::new(File::create("test_working.pdf").unwrap())).unwrap();
}

最终会生成来自png的一个pdf,

scale_x: Some( 2.4),

scale_y: Some( 2.4), 这两个参数是x,y的放大倍数。以适应页面。translate_x这是距离左下角的,位置。

  • 建立trunk项目
c 复制代码
rustup target add wasm32-unknown-unknown
cargo install --locked trunk
cargo new trunk-hello-world
cd trunk-hello-world

https://github.com/trunk-rs/trunk/tree/main 的example目录,拷贝一个示例的内容,集成了printpdf是这样,

大家可以删除pdf在部分,只体会一下trunk在能量。

c 复制代码
 use printpdf::*;
use std::fs::File;
use std::io::BufWriter;
use web_sys::window;
fn start_app( show:&str) {
    let document = window()
        .and_then(|win| win.document())
        .expect("Could not access document");
    let body = document.body().expect("Could not access document.body");
    let text_node = document.create_text_node( &format!("Hello, world from Vanilla Rust!{}",show) );
    body.append_child(text_node.as_ref())
        .expect("Failed to append text");

}

fn main() {
    console_error_panic_hook::set_once();

  
        let (doc, page1, layer1) = PdfDocument::new("PDF_Document_title", Mm(247.0), Mm(210.0), "Layer 1");
let (page2, layer1) = doc.add_page(Mm(10.0), Mm(250.0),"Page 2, Layer 1");
let pdf_bytes = doc.save_to_bytes().unwrap();

 // doc.save(&mut BufWriter::new(File::create("/tmp/test_working.pdf").unwrap())).unwrap();   
       
    start_app(&String::from_utf8_lossy(&pdf_bytes)) ;
}

这部分代码会显示刚生成的pdf最简单的单页文件在 字节码。

最后

将pdf在bytes,传递给js,显示在一个iframe 中,是我最后的想法

c 复制代码
<!DOCTYPE html>
<html>
<head>
    <title>PDF Viewer</title>
</head>
<body>
    <iframe id="pdfViewer" width="100%" height="800px"></iframe>
 
    <script>
        // 假设这是你已经有的PDF Blob数据
        var pdfBlob = yourPDFBlobData; // 这里应该是你实际的Blob数据
 
        // 创建一个新的URL,指向这个Blob
        var url = URL.createObjectURL(pdfBlob);
 
        // 获取iframe元素并设置其src属性为PDF的URL
        var viewer = document.getElementById('pdfViewer');
        viewer.src = url;
    </script>
</body>
</html>

trunk sever是边改,边自动编译的命令,但是有个别时候,需要手工中止,ctr +c、然后再启动一次。

运行无错,均已实现后可truck build,生成的内容,一个*.wasm , 一个js,一个html、

参考html加入两个库到现有的页面,即可实现本文的要求了。

细节请根据文档调整。

由于时间仓促,且实际已无大的阻碍,当前没有实现最终版。所以本文暂时如此,后期看情形,将更新为上线运行版的代码。

特别感谢 【前端柒八九】提供的 Rust赋能前端:纯血前端将table导出excel提供的启发。

相关推荐
泡泡Java1 小时前
使用WebStorm开发Vue3项目
ide·rust·webstorm
企鹅侠客7 小时前
开源免费文档翻译工具 可支持pdf、word、excel、ppt
人工智能·pdf·word·excel·自动翻译
近冬的阳光12 小时前
PDF文档管理系统V2.0
pdf
Driver_tu12 小时前
在windows10上基于Python部署marker,实现PDF转markdown文件(保姆级)
pdf
黄铎彦12 小时前
使用GDI+、文件和目录和打印API,批量将图片按文件名分组打包成PDF
c++·windows·pdf
梅如你12 小时前
IEEE官方期刊缩写查询pdf分享
pdf
jxf_jxfcsdn15 小时前
python读取pdf文档
开发语言·python·pdf
蜗牛沐雨15 小时前
如何生成美观且内容稳定的PDF文档:从基础到进阶的全方案解析
人工智能·pdf·tensorflow
Jamence16 小时前
国产开源PDF解析工具MinerU
人工智能·pdf·aigc
伟贤AI之路1 天前
清华大学:DeepSeek与AI幻觉(31页PDF)
人工智能·pdf