docx_template/
image.rs

1use crate::error::DocxError;
2use image::{GenericImageView, load_from_memory};
3use std::fs::File;
4use std::io::Read;
5use std::path::Path;
6use uuid::Uuid;
7
8// 1厘米约等于360000EMU
9pub static DOCX_EMU: f32 = 360000.0;
10pub static DOCX_MAX_EMU: u64 = (21.0 * 360000.0 / 2.0) as u64;
11// 1英寸=96像素
12static DPI: f64 = 96f64;
13// 1英寸=914400 EMU
14static EMU: f64 = 914400f64;
15
16// 添加的图标对象
17#[derive(Debug, Clone)]
18pub struct DocxImage {
19    // 图片路径
20    pub image_path: String,
21    // 图片扩展名
22    pub image_ext: String,
23    // 图片数据
24    pub image_data: Vec<u8>,
25    // 关联id
26    pub relation_id: String,
27    // 图片高度
28    pub width: u64,
29    // 图片高度
30    pub height: u64,
31}
32
33impl DocxImage {
34    /// 创建图片对象  
35    /// @param image_path 本地图片路径  
36    pub fn new(image_path: &str) -> Result<Self, DocxError> {
37        // 打开文件读取数据到数组中
38        let mut file = File::open(image_path)?;
39        let mut image_data = Vec::new();
40        file.read_to_end(&mut image_data)?;
41        // 获取扩展名
42        let ext = get_extension(image_path)?;
43        let (width_emu, height_emu) = get_image_size(&image_data)?;
44        Self::new_image_data_size(image_path, image_data, ext, width_emu, height_emu)
45    }
46
47    /// 设置图片大小  
48    /// @param image_path 图片路径  
49    /// @param width 图片宽度(emu)
50    /// @param height 图片高度 (emu)
51    pub fn new_size(image_path: &str, width: u64, height: u64) -> Result<Self, DocxError> {
52        // 打开文件读取数据到数组中
53        let mut file = File::open(image_path)?;
54        let mut image_data = Vec::new();
55        file.read_to_end(&mut image_data)?;
56        // 获取扩展名
57        let ext = get_extension(image_path)?;
58        DocxImage::new_image_data_size(image_path, image_data, ext, width, height)
59    }
60
61    /// 设置图片大小  
62    /// @param image_url 图片路径  
63    /// @param image_data 图片数据  
64    pub fn new_image_data(
65        image_url: &str,
66        image_data: Vec<u8>,
67        image_ext: &str,
68    ) -> Result<Self, DocxError> {
69        let (width_emu, height_emu) = get_image_size(&image_data)?;
70        DocxImage::new_image_data_size(image_url, image_data, image_ext, width_emu, height_emu)
71    }
72
73    /// 设置图片大小  
74    /// @param image_url 图片路径  
75    /// @param image_data 图片数据  
76    /// @param image_ext 图片扩展名  
77    /// @param width 图片宽度(emu)
78    /// @param height 图片高度(emu)
79    pub fn new_image_data_size(
80        image_url: &str,
81        image_data: Vec<u8>,
82        image_ext: &str,
83        width: u64,
84        height: u64,
85    ) -> Result<Self, DocxError> {
86        Ok(DocxImage {
87            image_path: image_url.to_string(),
88            image_ext: image_ext.to_string(),
89            relation_id: format!("rId{}", Uuid::new_v4().simple()),
90            width,
91            height,
92            image_data,
93        })
94    }
95
96    /// 设置图片大小  
97    /// @param image_url 图片路径  
98    /// @param image_data 图片数据  
99    /// @param image_ext 图片扩展名  
100    /// @param relation_id 关联编号
101    /// @param width 图片宽度(emu)
102    /// @param height 图片高度(emu)
103    pub fn new_image_data_size_relation(
104        image_url: &str,
105        image_data: Vec<u8>,
106        image_ext: &str,
107        relation_id: &str,
108        width: u64,
109        height: u64,
110    ) -> Self {
111        DocxImage {
112            image_path: image_url.to_string(),
113            image_ext: image_ext.to_string(),
114            relation_id: relation_id.to_string(),
115            width,
116            height,
117            image_data,
118        }
119    }
120
121    /// 克隆一个图片对象,并重新设置图片大小
122    /// @param docx_image 图片对象  
123    /// @param width 图片宽度(emu)
124    /// @param height 图片高度(emu)
125    pub fn clone_image_reset_size(docx_image: &DocxImage, width: u64, height: u64) -> Self {
126        DocxImage {
127            image_path: docx_image.image_path.clone(),
128            image_ext: docx_image.image_ext.clone(),
129            relation_id: docx_image.relation_id.clone(),
130            width,
131            height,
132            image_data: docx_image.image_data.clone(),
133        }
134    }
135}
136
137pub fn get_image_size(image_data: &[u8]) -> Result<(u64, u64), DocxError> {
138    let img = load_from_memory(image_data)?;
139    let (width_px, height_px) = img.dimensions();
140    let mut width_emu = (width_px as f64 * EMU / DPI) as u64;
141    let mut height_emu = (height_px as f64 * EMU / DPI) as u64;
142    // 判断图片是否大于文档宽度
143    if width_emu > DOCX_MAX_EMU {
144        height_emu = DOCX_MAX_EMU * height_emu / width_emu;
145        width_emu = DOCX_MAX_EMU;
146        Ok((width_emu, height_emu))
147    } else {
148        Ok((width_emu, height_emu))
149    }
150}
151
152/// 获取本地图片的扩展名
153/// @param image_path 本地图片路径
154/// @return 图片扩展名
155pub fn get_extension(image_path: &str) -> Result<&str, DocxError> {
156    Path::new(image_path)
157        .extension()
158        .and_then(|s| s.to_str())
159        .ok_or_else(|| DocxError::ImageNotFound("Could not determine image extension".to_string()))
160}