use crate::model::image_format::ImageFormat;
#[derive(Debug, Clone)]
pub struct ImageObject {
pub x: f64,
pub y: f64,
pub width: f64,
pub height: f64,
pub data: Vec<u8>,
pub format: ImageFormat,
pub res_name: Option<String>,
}
impl ImageObject {
#[must_use]
pub fn new(
x: f64,
y: f64,
width: f64,
height: f64,
data: Vec<u8>,
format: ImageFormat,
) -> Self {
Self {
x,
y,
width,
height,
data,
format,
res_name: None,
}
}
#[must_use]
pub fn with_res_name(mut self, res_name: impl Into<String>) -> Self {
self.res_name = Some(res_name.into());
self
}
#[must_use]
pub fn jpeg(x: f64, y: f64, width: f64, height: f64, data: Vec<u8>) -> Self {
Self::new(x, y, width, height, data, ImageFormat::Jpeg)
}
#[must_use]
pub fn png(x: f64, y: f64, width: f64, height: f64, data: Vec<u8>) -> Self {
Self::new(x, y, width, height, data, ImageFormat::Png)
}
pub fn from_file(
x: f64,
y: f64,
width: f64,
height: f64,
path: impl AsRef<std::path::Path>,
) -> crate::OfdResult<Self> {
let data = std::fs::read(path.as_ref()).map_err(crate::OfdError::Io)?;
let format = detect_image_format(path.as_ref(), &data);
Ok(Self::new(x, y, width, height, data, format))
}
}
fn detect_image_format(path: &std::path::Path, data: &[u8]) -> ImageFormat {
if let Some(ext) = path.extension().and_then(|e| e.to_str()) {
match ext.to_lowercase().as_str() {
"jpg" | "jpeg" => return ImageFormat::Jpeg,
"png" => return ImageFormat::Png,
"bmp" => return ImageFormat::Bmp,
"tiff" | "tif" => return ImageFormat::Tiff,
_ => {}
}
}
if data.len() >= 2 && data[0] == 0xFF && data[1] == 0xD8 {
return ImageFormat::Jpeg;
}
if data.len() >= 4 && data[0] == 0x89 && data[1] == b'P' && data[2] == b'N' && data[3] == b'G' {
return ImageFormat::Png;
}
if data.len() >= 2 && data[0] == b'B' && data[1] == b'M' {
return ImageFormat::Bmp;
}
if data.len() >= 4
&& ((data[0] == b'I' && data[1] == b'I') || (data[0] == b'M' && data[1] == b'M'))
&& data[2] == 0x00
&& data[3] == 0x2A
{
return ImageFormat::Tiff;
}
ImageFormat::Jpeg
}