use std::{
fs,
fs::File,
io::{
BufReader,
Cursor,
Read,
},
};
use base64::{
Engine as _,
engine::general_purpose::STANDARD,
};
use quick_xml::Writer;
use crate::{
structs::{
MediaObject,
drawing::{
FillRectangle,
PresetGeometry,
Stretch,
spreadsheet::{
MarkerType,
OneCellAnchor,
Picture,
TwoCellAnchor,
},
},
},
traits::AdjustmentCoordinate,
};
#[derive(Clone, Default, Debug)]
pub struct Image {
two_cell_anchor: Option<Box<TwoCellAnchor>>,
one_cell_anchor: Option<Box<OneCellAnchor>>,
}
impl Image {
#[inline]
#[must_use]
pub fn two_cell_anchor(&self) -> Option<&TwoCellAnchor> {
self.two_cell_anchor.as_deref()
}
#[inline]
#[must_use]
#[deprecated(since = "3.0.0", note = "Use two_cell_anchor()")]
pub fn get_two_cell_anchor(&self) -> Option<&TwoCellAnchor> {
self.two_cell_anchor()
}
#[inline]
pub fn two_cell_anchor_mut(&mut self) -> Option<&mut TwoCellAnchor> {
self.two_cell_anchor.as_deref_mut()
}
#[inline]
#[deprecated(since = "3.0.0", note = "Use two_cell_anchor_mut()")]
pub fn get_two_cell_anchor_mut(&mut self) -> Option<&mut TwoCellAnchor> {
self.two_cell_anchor_mut()
}
#[inline]
pub fn set_two_cell_anchor(&mut self, value: TwoCellAnchor) -> &mut Self {
self.two_cell_anchor = Some(Box::new(value));
self
}
#[inline]
pub fn remove_two_cell_anchor(&mut self) -> &mut Self {
self.two_cell_anchor = None;
self
}
#[inline]
#[must_use]
pub fn one_cell_anchor(&self) -> Option<&OneCellAnchor> {
self.one_cell_anchor.as_deref()
}
#[inline]
#[must_use]
#[deprecated(since = "3.0.0", note = "Use one_cell_anchor()")]
pub fn get_one_cell_anchor(&self) -> Option<&OneCellAnchor> {
self.one_cell_anchor()
}
#[inline]
pub fn one_cell_anchor_mut(&mut self) -> Option<&mut OneCellAnchor> {
self.one_cell_anchor.as_deref_mut()
}
#[inline]
#[deprecated(since = "3.0.0", note = "Use one_cell_anchor_mut()")]
pub fn get_one_cell_anchor_mut(&mut self) -> Option<&mut OneCellAnchor> {
self.one_cell_anchor_mut()
}
#[inline]
pub fn set_one_cell_anchor(&mut self, value: OneCellAnchor) -> &mut Self {
self.one_cell_anchor = Some(Box::new(value));
self
}
#[inline]
pub fn remove_one_cell_anchor(&mut self) -> &mut Self {
self.one_cell_anchor = None;
self
}
#[allow(clippy::cast_possible_truncation)]
pub fn new_image(&mut self, path: &str, marker: MarkerType) {
let path = std::path::Path::new(path);
let size = imagesize::size(path).unwrap();
let image_name = path.file_name().unwrap().to_str().unwrap();
let mut buf = Vec::new();
let file = File::open(path).unwrap();
BufReader::new(file).read_to_end(&mut buf).unwrap();
self.new_image_with_dimensions(size.height as u32, size.width as u32, image_name, buf, marker);
}
pub fn new_image_with_dimensions<B: Into<Vec<u8>>>(
&mut self,
height: u32,
width: u32,
image_name: &str,
bytes: B,
marker: MarkerType,
) {
let mut picture = Picture::default();
picture
.blip_fill_mut()
.blip_mut()
.set_cstate("print")
.image_mut()
.set_image_name(image_name)
.set_image_data(bytes.into());
picture
.non_visual_picture_properties_mut()
.non_visual_drawing_properties_mut()
.set_name(image_name);
picture
.non_visual_picture_properties_mut()
.non_visual_picture_drawing_properties_mut()
.set_prefer_relative_resize(false);
let fill_rectangle = FillRectangle::default();
let mut stretch = Stretch::default();
stretch.set_fill_rectangle(fill_rectangle);
picture.blip_fill_mut().set_stretch(stretch);
picture
.shape_properties_mut()
.geometry_mut()
.set_geometry(PresetGeometry::GEOMETRY_RECT);
let mut one_cell_anchor = OneCellAnchor::default();
one_cell_anchor.set_from_marker(marker);
one_cell_anchor
.extent_mut()
.set_cy(i64::from(height) * 9525);
one_cell_anchor
.extent_mut()
.set_cx(i64::from(width) * 9525);
one_cell_anchor.set_picture(picture);
self.set_one_cell_anchor(one_cell_anchor);
}
#[inline]
pub fn change_image(&mut self, path: &str) {
let marker = self.from_marker_type().clone();
self.remove_two_cell_anchor();
self.remove_one_cell_anchor();
self.new_image(path, marker);
}
#[inline]
pub fn download_image(&self, path: &str) {
fs::write(path, self.image_data()).unwrap();
}
#[inline]
#[must_use]
pub fn has_image(&self) -> bool {
!self.media_object().is_empty()
}
#[inline]
#[must_use]
pub fn image_name(&self) -> &str {
match self.media_object().first() {
Some(v) => v.image_name(),
None => "",
}
}
#[inline]
#[must_use]
#[deprecated(since = "3.0.0", note = "Use image_name()")]
pub fn get_image_name(&self) -> &str {
self.image_name()
}
#[inline]
#[must_use]
pub fn image_data(&self) -> &[u8] {
match self.media_object().first() {
Some(v) => v.image_data(),
None => &[0u8; 0],
}
}
#[inline]
#[must_use]
#[deprecated(since = "3.0.0", note = "Use image_data()")]
pub fn get_image_data(&self) -> &[u8] {
self.image_data()
}
#[inline]
#[must_use]
pub fn image_data_base64(&self) -> String {
STANDARD.encode(self.image_data())
}
#[inline]
#[must_use]
#[deprecated(since = "3.0.0", note = "Use image_data_base64()")]
pub fn get_image_data_base64(&self) -> String {
self.image_data_base64()
}
#[inline]
#[must_use]
pub fn coordinate(&self) -> String {
self.from_marker_type().coordinate()
}
#[inline]
#[must_use]
#[deprecated(since = "3.0.0", note = "Use coordinate()")]
pub fn get_coordinate(&self) -> String {
self.coordinate()
}
#[inline]
#[must_use]
pub fn col(&self) -> u32 {
self.from_marker_type().col()
}
#[inline]
#[must_use]
#[deprecated(since = "3.0.0", note = "Use col()")]
pub fn get_col(&self) -> u32 {
self.col()
}
#[inline]
#[must_use]
pub fn row(&self) -> u32 {
self.from_marker_type().row()
}
#[inline]
#[must_use]
#[deprecated(since = "3.0.0", note = "Use row()")]
pub fn get_row(&self) -> u32 {
self.row()
}
#[inline]
#[must_use]
pub fn from_marker_type(&self) -> &MarkerType {
if let Some(anchor) = self.two_cell_anchor() {
return anchor.from_marker();
}
if let Some(anchor) = self.one_cell_anchor() {
return anchor.from_marker();
}
panic!("Not Found MediaObject");
}
#[inline]
#[must_use]
#[deprecated(since = "3.0.0", note = "Use from_marker_type()")]
pub fn get_from_marker_type(&self) -> &MarkerType {
self.from_marker_type()
}
#[inline]
#[must_use]
pub fn to_marker_type(&self) -> Option<&MarkerType> {
self.two_cell_anchor()
.as_ref()
.map(|anchor| anchor.to_marker())
}
#[inline]
#[must_use]
#[deprecated(since = "3.0.0", note = "Use to_marker_type()")]
pub fn get_to_marker_type(&self) -> Option<&MarkerType> {
self.to_marker_type()
}
pub(crate) fn media_object(&self) -> Vec<&MediaObject> {
let mut result: Vec<&MediaObject> = Vec::new();
if let Some(anchor) = self.two_cell_anchor() {
if let Some(v) = anchor.picture() {
result.push(v.blip_fill().blip().image());
}
if let Some(v) = anchor.shape() {
if let Some(bf) = v.shape_properties().blip_fill() {
result.push(bf.blip().image());
}
}
if let Some(v) = anchor.connection_shape() {
if let Some(bf) = v.shape_properties().blip_fill() {
result.push(bf.blip().image());
}
}
if let Some(v) = anchor.group_shape() {
for pic in v.picture_collection() {
result.push(pic.blip_fill().blip().image());
}
for shp in v.shape_collection() {
if let Some(bf) = shp.shape_properties().blip_fill() {
result.push(bf.blip().image());
}
}
}
}
if let Some(anchor) = self.one_cell_anchor() {
if let Some(v) = anchor.picture() {
result.push(v.blip_fill().blip().image());
}
if let Some(v) = anchor.shape() {
if let Some(bf) = v.shape_properties().blip_fill() {
result.push(bf.blip().image());
}
}
if let Some(v) = anchor.group_shape() {
for pic in v.picture_collection() {
result.push(pic.blip_fill().blip().image());
}
for shp in v.shape_collection() {
if let Some(bf) = shp.shape_properties().blip_fill() {
result.push(bf.blip().image());
}
}
}
}
result
}
#[deprecated(since = "3.0.0", note = "Use media_object()")]
pub(crate) fn get_media_object(&self) -> Vec<&MediaObject> {
self.media_object()
}
#[inline]
pub(crate) fn write_to(
&self,
writer: &mut Writer<Cursor<Vec<u8>>>,
rel_list: &mut Vec<(String, String)>,
) {
if let Some(anchor) = self.two_cell_anchor() {
anchor.write_to(writer, rel_list, 0);
}
if let Some(anchor) = self.one_cell_anchor() {
anchor.write_to(writer, rel_list);
}
}
}
impl AdjustmentCoordinate for Image {
#[inline]
fn adjustment_insert_coordinate(
&mut self,
root_col_num: u32,
offset_col_num: u32,
root_row_num: u32,
offset_row_num: u32,
) {
if let Some(anchor) = self.one_cell_anchor.as_mut() {
anchor.adjustment_insert_coordinate(
root_col_num,
offset_col_num,
root_row_num,
offset_row_num,
);
}
if let Some(anchor) = self.two_cell_anchor.as_mut() {
anchor.adjustment_insert_coordinate(
root_col_num,
offset_col_num,
root_row_num,
offset_row_num,
);
}
}
#[inline]
fn adjustment_remove_coordinate(
&mut self,
root_col_num: u32,
offset_col_num: u32,
root_row_num: u32,
offset_row_num: u32,
) {
if let Some(anchor) = self.one_cell_anchor.as_mut() {
anchor.adjustment_remove_coordinate(
root_col_num,
offset_col_num,
root_row_num,
offset_row_num,
);
}
if let Some(anchor) = self.two_cell_anchor.as_mut() {
anchor.adjustment_remove_coordinate(
root_col_num,
offset_col_num,
root_row_num,
offset_row_num,
);
}
}
#[inline]
fn is_remove_coordinate(
&self,
root_col_num: u32,
offset_col_num: u32,
root_row_num: u32,
offset_row_num: u32,
) -> bool {
if let Some(anchor) = self.one_cell_anchor.as_ref() {
return anchor.is_remove_coordinate(
root_col_num,
offset_col_num,
root_row_num,
offset_row_num,
);
}
if let Some(anchor) = self.two_cell_anchor.as_ref() {
return anchor.is_remove_coordinate(
root_col_num,
offset_col_num,
root_row_num,
offset_row_num,
);
}
false
}
}