use std::{collections::BTreeMap, path::PathBuf, str::FromStr};
use crate::{
common_types::HexColor,
packaging::relationship::{zip_path_for_id, XlsxRelationships, EXTERNAL_TARGET_MODE},
processed::drawing::effect::effect_container::EffectContainer,
raw::drawing::{image::blip::XlsxBlip, scheme::color_scheme::XlsxColorScheme},
};
#[cfg(feature = "serde")]
use serde::Serialize;
#[cfg_attr(feature = "serde", derive(Serialize))]
#[derive(Debug, PartialEq, Clone)]
pub struct Blip {
pub source: BlipSourceType,
pub compression_state: BlipCompressionStateType,
pub effects: Box<EffectContainer>,
}
impl Blip {
pub(crate) fn from_raw(
raw: Option<XlsxBlip>,
drawing_relationship: XlsxRelationships,
image_bytes: BTreeMap<String, Vec<u8>>,
color_scheme: Option<XlsxColorScheme>,
ref_color: Option<HexColor>,
) -> Option<Self> {
let Some(raw) = raw else { return None };
let Some(source) = BlipSourceType::from_raw(
Some(raw.clone()),
drawing_relationship.clone(),
image_bytes.clone(),
) else {
return None;
};
return Some(Self {
effects: EffectContainer::from_raw_blip(
raw.clone(),
drawing_relationship.clone(),
image_bytes.clone(),
color_scheme.clone(),
ref_color.clone(),
),
source,
compression_state: BlipCompressionStateType::from_string(raw.cstate),
});
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
pub enum BlipSourceType {
Internal(InternalSource),
External(String),
}
impl BlipSourceType {
pub(crate) fn from_raw(
raw_blip: Option<XlsxBlip>,
drawing_relationship: XlsxRelationships,
image_bytes: BTreeMap<String, Vec<u8>>,
) -> Option<Self> {
let Some(raw_blip) = raw_blip else {
return None;
};
if let Some(embed) = raw_blip.clone().embed {
return Self::parse_rel_helper(&embed, drawing_relationship.clone(), image_bytes);
}
if let Some(link) = raw_blip.clone().link {
if let Some(source) =
Self::parse_rel_helper(&link, drawing_relationship.clone(), image_bytes)
{
return Some(source);
} else {
return Some(Self::External(link));
}
}
return None;
}
fn parse_rel_helper(
r_id: &str,
drawing_relationships: XlsxRelationships,
image_bytes: BTreeMap<String, Vec<u8>>,
) -> Option<Self> {
let rel: XlsxRelationships = drawing_relationships
.clone()
.into_iter()
.filter(|r| r.id == r_id.to_string())
.collect();
if let Some(first) = rel.first() {
if first.target_mode == Some(EXTERNAL_TARGET_MODE.to_string()) {
return Some(Self::External(first.target.clone()));
}
if let (Some(path), Some(bytes)) = (
zip_path_for_id(&drawing_relationships, &first.id),
image_bytes.get(&first.id),
) {
let mut name = path.clone();
match PathBuf::from_str(&path) {
Ok(file_path) => {
if let Some(n) = file_path.file_name() {
if let Some(s) = n.to_str() {
name = s.to_owned();
}
}
}
_ => (),
};
return Some(Self::Internal(InternalSource {
name,
bytes: bytes.to_owned(),
}));
}
}
return None;
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
pub enum BlipCompressionStateType {
Email,
HighQualityPrint,
None,
Print,
Screen,
}
impl BlipCompressionStateType {
pub(crate) fn from_string(s: Option<String>) -> Self {
let Some(s) = s else { return Self::None };
return match s.as_ref() {
"email" => Self::Email,
"hqprint" => Self::HighQualityPrint,
"none" => Self::None,
"print" => Self::Print,
"screen" => Self::Screen,
_ => Self::None,
};
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct InternalSource {
pub name: String,
#[cfg_attr(feature = "serde", serde(skip_serializing))]
pub bytes: Vec<u8>,
}