docx_template/
image.rs

1use crate::error::DocxError;
2use image::{GenericImageView, load_from_memory};
3use std::fs::File;
4use std::io::Read;
5use uuid::Uuid;
6
7// 1厘米约等于360000EMU
8pub static DOCX_EMU: f32 = 360000.0;
9pub static DOCX_MAX_EMU: u64 = (21.0 * 360000.0 / 2.0) as u64;
10// 1英寸=96像素
11static DPI: f64 = 96f64;
12// 1英寸=914400 EMU
13static EMU: f64 = 914400f64;
14
15// 添加的图标对象
16pub struct DocxImage {
17    // 图片路径
18    pub image_path: String,
19    // 图片数据
20    pub image_data: Vec<u8>,
21    // 关联id
22    pub relation_id: String,
23    // 图片高度
24    pub width: u64,
25    // 图片高度
26    pub height: u64,
27}
28
29impl DocxImage {
30    /// 创建图片对象  
31    /// @param image_path 图片路径  
32    pub fn new(image_path: &str) -> Result<Self, DocxError> {
33        // 打开文件读取数据到数组中
34        let mut file = File::open(image_path)?;
35        let mut image_data = Vec::new();
36        file.read_to_end(&mut image_data)?;
37        let (width_emu, height_emu) = get_image_size(&image_data)?;
38        Self::new_size_emu(image_path, image_data, width_emu, height_emu)
39    }
40    /// 设置图片大小  
41    /// @param image_path 图片路径  
42    /// @param width 图片宽度  
43    /// @param height 图片高度  
44    pub fn new_size_emu(
45        image_path: &str,
46        image_data: Vec<u8>,
47        width: u64,
48        height: u64,
49    ) -> Result<Self, DocxError> {
50        DocxImage::new_image_data_size(image_path, image_data, width, height)
51    }
52
53    /// 设置图片大小  
54    /// @param image_path 图片路径  
55    /// @param width 图片宽度(emu)
56    /// @param height 图片高度 (emu)
57    pub fn new_size(image_path: &str, width: u64, height: u64) -> Result<Self, DocxError> {
58        // 打开文件读取数据到数组中
59        let mut file = File::open(image_path)?;
60        let mut image_data = Vec::new();
61        file.read_to_end(&mut image_data)?;
62        DocxImage::new_image_data_size(image_path, image_data, width, height)
63    }
64
65    /// 设置图片大小  
66    /// @param image_url 图片路径  
67    /// @param image_data 图片数据  
68    pub fn new_image_data(image_url: &str, image_data: Vec<u8>) -> Result<Self, DocxError> {
69        let (width_emu, height_emu) = get_image_size(&image_data)?;
70        DocxImage::new_image_data_size(image_url, image_data, width_emu, height_emu)
71    }
72
73    /// 设置图片大小  
74    /// @param image_url 图片路径  
75    /// @param image_data 图片数据  
76    /// @param width 图片宽度(emu)
77    /// @param height 图片高度(emu)
78    pub fn new_image_data_size(
79        image_url: &str,
80        image_data: Vec<u8>,
81        width: u64,
82        height: u64,
83    ) -> Result<Self, DocxError> {
84        Ok(DocxImage {
85            image_path: image_url.to_string(),
86            relation_id: format!("rId{}", Uuid::new_v4().simple()),
87            width,
88            height,
89            image_data,
90        })
91    }
92}
93
94fn get_image_size(image_data: &[u8]) -> Result<(u64, u64), DocxError> {
95    let img = load_from_memory(image_data)?;
96    let (width_px, height_px) = img.dimensions();
97    let mut width_emu = (width_px as f64 * EMU / DPI) as u64;
98    let mut height_emu = (height_px as f64 * EMU / DPI) as u64;
99    // 判断图片是否大于文档宽度
100    if width_emu > DOCX_MAX_EMU {
101        height_emu = DOCX_MAX_EMU * height_emu / width_emu;
102        width_emu = DOCX_MAX_EMU;
103        Ok((width_emu, height_emu))
104    } else {
105        Ok((width_emu, height_emu))
106    }
107}