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
8pub static DOCX_EMU: f32 = 360000.0;
10pub static DOCX_MAX_EMU: u64 = (21.0 * 360000.0 / 2.0) as u64;
11static DPI: f64 = 96f64;
13static EMU: f64 = 914400f64;
15
16pub struct DocxImage {
18 pub image_path: String,
20 pub image_ext: String,
22 pub image_data: Vec<u8>,
24 pub relation_id: String,
26 pub width: u64,
28 pub height: u64,
30}
31
32impl DocxImage {
33 pub fn new(image_path: &str) -> Result<Self, DocxError> {
36 let mut file = File::open(image_path)?;
38 let mut image_data = Vec::new();
39 file.read_to_end(&mut image_data)?;
40 let ext = get_extension(image_path)?;
42 let (width_emu, height_emu) = get_image_size(&image_data)?;
43 Self::new_image_data_size(image_path, image_data, ext, width_emu, height_emu)
44 }
45
46 pub fn new_size(image_path: &str, width: u64, height: u64) -> Result<Self, DocxError> {
51 let mut file = File::open(image_path)?;
53 let mut image_data = Vec::new();
54 file.read_to_end(&mut image_data)?;
55 let ext = get_extension(image_path)?;
57 DocxImage::new_image_data_size(image_path, image_data, ext, width, height)
58 }
59
60 pub fn new_image_data(
64 image_url: &str,
65 image_data: Vec<u8>,
66 image_ext: &str,
67 ) -> Result<Self, DocxError> {
68 let (width_emu, height_emu) = get_image_size(&image_data)?;
69 DocxImage::new_image_data_size(image_url, image_data, image_ext, width_emu, height_emu)
70 }
71
72 pub fn new_image_data_size(
79 image_url: &str,
80 image_data: Vec<u8>,
81 image_ext: &str,
82 width: u64,
83 height: u64,
84 ) -> Result<Self, DocxError> {
85 Ok(DocxImage {
86 image_path: image_url.to_string(),
87 image_ext: image_ext.to_string(),
88 relation_id: format!("rId{}", Uuid::new_v4().simple()),
89 width,
90 height,
91 image_data,
92 })
93 }
94}
95
96fn get_image_size(image_data: &[u8]) -> Result<(u64, u64), DocxError> {
97 let img = load_from_memory(image_data)?;
98 let (width_px, height_px) = img.dimensions();
99 let mut width_emu = (width_px as f64 * EMU / DPI) as u64;
100 let mut height_emu = (height_px as f64 * EMU / DPI) as u64;
101 if width_emu > DOCX_MAX_EMU {
103 height_emu = DOCX_MAX_EMU * height_emu / width_emu;
104 width_emu = DOCX_MAX_EMU;
105 Ok((width_emu, height_emu))
106 } else {
107 Ok((width_emu, height_emu))
108 }
109}
110
111fn get_extension(image_path: &str) -> Result<&str, DocxError> {
115 Path::new(image_path)
116 .extension()
117 .and_then(|s| s.to_str())
118 .ok_or_else(|| DocxError::ImageNotFound("Could not determine image extension".to_string()))
119}