mod xml;
#[cfg(test)]
mod tests;
use crate::dml::effect::ShadowFormat;
use crate::dml::effect3d::{Scene3D, Shape3D};
use crate::dml::line::LineFormat;
use crate::enums::shapes::MsoAutoShapeType;
use crate::error::PptxError;
use crate::media::Image;
use crate::shapes::action::ActionSetting;
use crate::shapes::placeholder::PlaceholderFormat;
use crate::units::{Emu, ShapeId};
#[derive(Debug, Clone, PartialEq)]
pub struct Picture {
pub shape_id: ShapeId,
pub name: String,
pub left: Emu,
pub top: Emu,
pub width: Emu,
pub height: Emu,
pub rotation: f64,
pub image_r_id: Option<String>,
pub description: Option<String>,
pub placeholder: Option<PlaceholderFormat>,
pub crop_left: f64,
pub crop_right: f64,
pub crop_top: f64,
pub crop_bottom: f64,
pub line: Option<LineFormat>,
pub click_action: Option<ActionSetting>,
pub hover_action: Option<ActionSetting>,
pub shadow: Option<ShadowFormat>,
pub auto_shape_type: Option<MsoAutoShapeType>,
pub image_data: Option<Vec<u8>>,
pub image_content_type: Option<String>,
pub scene_3d: Option<Scene3D>,
pub shape_3d: Option<Shape3D>,
}
impl Picture {
pub fn new(
shape_id: ShapeId,
name: impl Into<String>,
left: Emu,
top: Emu,
width: Emu,
height: Emu,
image_r_id: impl Into<String>,
) -> Self {
Self {
shape_id,
name: name.into(),
left,
top,
width,
height,
rotation: 0.0,
image_r_id: Some(image_r_id.into()),
description: None,
placeholder: None,
crop_left: 0.0,
crop_right: 0.0,
crop_top: 0.0,
crop_bottom: 0.0,
line: None,
click_action: None,
hover_action: None,
shadow: None,
auto_shape_type: None,
image_data: None,
image_content_type: None,
scene_3d: None,
shape_3d: None,
}
}
pub fn set_line(&mut self, line: LineFormat) {
self.line = Some(line);
}
pub fn set_crop(
&mut self,
left: f64,
top: f64,
right: f64,
bottom: f64,
) -> Result<(), PptxError> {
Self::check_crop("Picture.crop_left", left)?;
Self::check_crop("Picture.crop_top", top)?;
Self::check_crop("Picture.crop_right", right)?;
Self::check_crop("Picture.crop_bottom", bottom)?;
self.crop_left = left;
self.crop_top = top;
self.crop_right = right;
self.crop_bottom = bottom;
Ok(())
}
pub fn set_crop_left(&mut self, value: f64) -> Result<(), PptxError> {
Self::check_crop("Picture.crop_left", value)?;
self.crop_left = value;
Ok(())
}
pub fn set_crop_top(&mut self, value: f64) -> Result<(), PptxError> {
Self::check_crop("Picture.crop_top", value)?;
self.crop_top = value;
Ok(())
}
pub fn set_crop_right(&mut self, value: f64) -> Result<(), PptxError> {
Self::check_crop("Picture.crop_right", value)?;
self.crop_right = value;
Ok(())
}
pub fn set_crop_bottom(&mut self, value: f64) -> Result<(), PptxError> {
Self::check_crop("Picture.crop_bottom", value)?;
self.crop_bottom = value;
Ok(())
}
fn check_crop(field: &'static str, val: f64) -> Result<(), PptxError> {
if !(0.0..=1.0).contains(&val) {
return Err(PptxError::InvalidValue {
field,
value: val.to_string(),
expected: "0.0 to 1.0",
});
}
Ok(())
}
pub fn set_click_action(&mut self, action: ActionSetting) {
self.click_action = Some(action);
}
pub fn set_hover_action(&mut self, action: ActionSetting) {
self.hover_action = Some(action);
}
pub fn set_shadow(&mut self, shadow: ShadowFormat) {
self.shadow = Some(shadow);
}
pub fn set_auto_shape_type(&mut self, shape_type: MsoAutoShapeType) {
self.auto_shape_type = Some(shape_type);
}
#[must_use]
pub const fn scene_3d(&self) -> Option<&Scene3D> {
self.scene_3d.as_ref()
}
pub fn set_scene_3d(&mut self, scene: Scene3D) {
self.scene_3d = Some(scene);
}
#[must_use]
pub const fn shape_3d(&self) -> Option<&Shape3D> {
self.shape_3d.as_ref()
}
pub fn set_shape_3d(&mut self, shape3d: Shape3D) {
self.shape_3d = Some(shape3d);
}
#[must_use]
pub fn image(&self) -> Option<Image> {
let data = self.image_data.as_ref()?;
let ct = self.image_content_type.as_deref()?;
Some(Image::from_bytes(data.clone(), ct))
}
}
impl std::fmt::Display for Picture {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Picture(\"{}\")", self.name)
}
}