【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提供的启发。

相关推荐
红烧code10 小时前
【Rust GUI开发入门】编写一个本地音乐播放器(4. 绘制按钮组件)
rust·gui·svg·slint
朝阳58113 小时前
使用过程宏实现自动化新增功能
后端·rust
JordanHaidee13 小时前
【Rust GUI开发入门】编写一个本地音乐播放器(8. 从文件中提取歌曲元信息)
rust
精致先生15 小时前
多模态PDF解析
pdf·大模型·rag
清心91516 小时前
Windows系统Rust安装与配置,解决安装慢问题
rust
清心91516 小时前
Windows系统Rust安装,自定义安装目录
rust
恒云客19 小时前
Rust开发环境配置
开发语言·后端·rust
啦啦91171421 小时前
Print Conductor打印软件安装教程!一款非常好用的批量打印软件!支持PDF、Word、Excel、图片等
pdf·excel
yz17800414101 天前
window pdf文件批量转高清图片png、jpg
pdf·bash
红烧code2 天前
【Rust GUI开发入门】编写一个本地音乐播放器(1. 主要技术选型&架构设计)
rust·gui·slint·rodio·lofty