use anyhow::bail;
use quick_xml::events::{BytesStart, Event};
use std::io::Read;
use super::fill_rectangle::{XlsxFillRectangle, XlsxSourceRectangle};
use crate::excel::XmlReader;
use crate::helper::{string_to_bool, string_to_int, string_to_unsignedint};
use crate::raw::drawing::image::blip::XlsxBlip;
#[derive(Debug, Clone, PartialEq)]
pub struct XlsxBlipFill {
pub blip: Option<XlsxBlip>,
pub source_rect: Option<XlsxSourceRectangle>,
pub stretch: Option<XlsxStretch>,
pub tile: Option<XlsxTile>,
pub dpi: Option<u64>,
pub rot_with_shape: Option<bool>,
}
impl XlsxBlipFill {
pub(crate) fn load(reader: &mut XmlReader<impl Read>, e: &BytesStart) -> anyhow::Result<Self> {
let attributes = e.attributes();
let mut fill = Self {
blip: None,
source_rect: None,
stretch: None,
tile: None,
dpi: None,
rot_with_shape: None,
};
for a in attributes {
match a {
Ok(a) => {
let string_value = String::from_utf8(a.value.to_vec())?;
match a.key.local_name().as_ref() {
b"dpi" => {
fill.dpi = string_to_unsignedint(&string_value);
}
b"rotWithShape" => {
fill.rot_with_shape = string_to_bool(&string_value);
}
_ => {}
}
}
Err(error) => {
bail!(error.to_string())
}
}
}
let mut buf = Vec::new();
loop {
buf.clear();
match reader.read_event_into(&mut buf) {
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"blip" => {
fill.blip = Some(XlsxBlip::load(reader, e)?);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"srcRect" => {
fill.source_rect = Some(XlsxSourceRectangle::load(e)?);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"stretch" => {
fill.stretch = Some(XlsxStretch::load(reader)?);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"tile" => {
fill.tile = Some(XlsxTile::load(e)?);
}
Ok(Event::End(ref e)) if e.local_name().as_ref() == b"blipFill" => break,
Ok(Event::Eof) => bail!("unexpected end of file."),
Err(e) => bail!(e.to_string()),
_ => (),
}
}
Ok(fill)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct XlsxStretch {
pub fill_rectangle: Option<XlsxFillRectangle>,
}
impl XlsxStretch {
pub(crate) fn load(reader: &mut XmlReader<impl Read>) -> anyhow::Result<Self> {
let mut stretch = Self {
fill_rectangle: None,
};
let mut buf = Vec::new();
loop {
buf.clear();
match reader.read_event_into(&mut buf) {
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"fillRect" => {
stretch.fill_rectangle = Some(XlsxFillRectangle::load(e)?);
}
Ok(Event::End(ref e)) if e.local_name().as_ref() == b"stretch" => break,
Ok(Event::Eof) => bail!("unexpected end of file."),
Err(e) => bail!(e.to_string()),
_ => (),
}
}
Ok(stretch)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct XlsxTile {
pub alignment: Option<String>,
pub flip: Option<String>,
pub sx: Option<i64>,
pub sy: Option<i64>,
pub tx: Option<i64>,
pub ty: Option<i64>,
}
impl XlsxTile {
pub(crate) fn load(e: &BytesStart) -> anyhow::Result<Self> {
let attributes = e.attributes();
let mut tile = Self {
alignment: None,
flip: None,
sx: None,
sy: None,
tx: None,
ty: None,
};
for a in attributes {
match a {
Ok(a) => {
let string_value = String::from_utf8(a.value.to_vec())?;
match a.key.local_name().as_ref() {
b"algn" => {
tile.alignment = Some(string_value);
}
b"flip" => {
tile.flip = Some(string_value);
}
b"sx" => {
tile.sx = string_to_int(&string_value);
}
b"sy" => {
tile.sy = string_to_int(&string_value);
}
b"tx" => {
tile.tx = string_to_int(&string_value);
}
b"ty" => {
tile.ty = string_to_int(&string_value);
}
_ => {}
}
}
Err(error) => {
bail!(error.to_string())
}
}
}
Ok(tile)
}
}