use anyhow::anyhow;
use bit_vec::BitVec;
+use cairo::ImageSurface;
use clap::{ArgAction, ArgMatches, Args, FromArgMatches, value_parser};
use enum_map::EnumMap;
use enumset::{EnumSet, EnumSetType};
#[derive(Clone, Debug, Serialize)]
pub enum Details {
Chart,
- Image,
+ Image(#[serde(skip_serializing)] ImageSurface),
Heading(Heading),
Message(Box<Diagnostic>),
PageBreak,
}
}
+ pub fn as_image(&self) -> Option<&ImageSurface> {
+ match self {
+ Self::Image(image_surface) => Some(image_surface),
+ _ => None,
+ }
+ }
+
pub fn command_name(&self) -> Option<&String> {
match self {
Details::Chart
- | Details::Image
+ | Details::Image(_)
| Details::Heading(_)
| Details::Message(_)
| Details::PageBreak
pub fn label(&self) -> Cow<'static, str> {
match self {
Details::Chart => Cow::from("chart"),
- Details::Image => Cow::from("Image"),
+ Details::Image(_) => Cow::from("Image"),
Details::Heading(_) => Cow::from("Group"),
Details::Message(diagnostic) => Cow::from(diagnostic.severity.as_title_str()),
Details::PageBreak => Cow::from("Page Break"),
pub fn kind(&self) -> ItemKind {
match self {
Details::Chart => ItemKind::Chart,
- Details::Image => ItemKind::Image,
+ Details::Image(_) => ItemKind::Image,
Details::Heading(_) => ItemKind::Heading,
Details::Message(_) => ItemKind::Message,
Details::PageBreak => ItemKind::PageBreak,
let label = self.label.as_ref().map(|s| s.as_str());
match &self.details {
Details::Chart => Class::Charts,
- Details::Image => Class::Other,
+ Details::Image(_) => Class::Other,
Details::Heading(_) => Class::OutlineHeaders,
Details::Message(diagnostic) => match diagnostic.severity {
Severity::Note => Class::Notes,
fn write(&mut self, item: &Arc<Item>) {
// todo: error handling (should not unwrap)
match &item.details {
- Details::Chart | Details::Image | Details::Heading(_) => (),
+ Details::Chart | Details::Image(_) | Details::Heading(_) => (),
Details::Message(diagnostic) => {
self.start_item();
let text = diagnostic.to_string();
fn write(&mut self, item: &Arc<Item>) {
match &item.details {
- Details::Chart | Details::Image | Details::Heading(_) => todo!(),
+ Details::Chart | Details::Image(_) | Details::Heading(_) => todo!(),
Details::Message(_diagnostic) => todo!(),
Details::PageBreak => (),
Details::Table(pivot_table) => {
X: Write,
{
match &item.details {
- Details::Chart | Details::Image => todo!(),
+ Details::Chart | Details::Image(_) => todo!(),
Details::Heading(children) => {
let mut attributes = Vec::<Attribute>::new();
if let Some(command_name) = &item.command_name {
W: FmtWrite,
{
match &item.details {
- Details::Chart | Details::Image => todo!(),
+ Details::Chart | Details::Image(_) => todo!(),
Details::Heading(children) => {
for (index, child) in children.0.iter().enumerate() {
if index > 0 {
use anyhow::Context;
use binrw::{BinRead, error::ContextExt};
+use cairo::ImageSurface;
use displaydoc::Display;
use serde::Deserialize;
use zip::{ZipArchive, result::ZipError};
/// {0}
LightError(#[from] LightError),
+
+ /// {0}
+ CairoError(#[from] cairo::IoError),
}
impl Item {
.into_item()
.with_command_name(container_text.command_name)
.with_spv_info(SpvInfo::new(structure_member)),
+ ContainerContent::Image(image) => {
+ image.decode(archive, structure_member).unwrap()
+ } /*XXX*/,
+ ContainerContent::Object(object) => {
+ object.decode(archive, structure_member).unwrap()
+ } /*XXX*/,
ContainerContent::Model => new_error_item("models not yet implemented")
.with_spv_info(SpvInfo::new(structure_member).with_error()),
- ContainerContent::Object => new_error_item("objects not yet implemented")
- .with_spv_info(SpvInfo::new(structure_member).with_error()),
- ContainerContent::Image => new_error_item("images not yet implemented")
- .with_spv_info(SpvInfo::new(structure_member).with_error()),
ContainerContent::Tree => new_error_item("trees not yet implemented")
.with_spv_info(SpvInfo::new(structure_member).with_error()),
};
Text(ContainerText),
Graph(Graph),
Model,
- Object,
- Image,
+ Object(Object),
+ Image(Image),
Tree,
}
}
}
+fn decode_image<R>(
+ archive: &mut ZipArchive<R>,
+ structure_member: &str,
+ command_name: &Option<String>,
+ image_name: &str,
+) -> Result<Item, Error>
+where
+ R: Read + Seek,
+{
+ let mut png = archive.by_name(image_name)?;
+ let image = ImageSurface::create_from_png(&mut png)?;
+ Ok(Details::Image(image)
+ .into_item()
+ .with_command_name(command_name.clone())
+ .with_spv_info(
+ SpvInfo::new(structure_member).with_members(SpvMembers::Image(image_name.into())),
+ ))
+}
+
+#[derive(Deserialize, Debug)]
+#[serde(rename_all = "camelCase")]
+struct Image {
+ #[serde(rename = "@commandName")]
+ command_name: Option<String>,
+ data_path: String,
+}
+
+impl Image {
+ fn decode<R>(&self, archive: &mut ZipArchive<R>, structure_member: &str) -> Result<Item, Error>
+ where
+ R: Read + Seek,
+ {
+ decode_image(
+ archive,
+ structure_member,
+ &self.command_name,
+ &self.data_path,
+ )
+ }
+}
+
+#[derive(Deserialize, Debug)]
+#[serde(rename_all = "camelCase")]
+struct Object {
+ #[serde(rename = "@commandName")]
+ command_name: Option<String>,
+ #[serde(rename = "@uri")]
+ uri: String,
+}
+
+impl Object {
+ fn decode<R>(&self, archive: &mut ZipArchive<R>, structure_member: &str) -> Result<Item, Error>
+ where
+ R: Read + Seek,
+ {
+ decode_image(archive, structure_member, &self.command_name, &self.uri)
+ }
+}
+
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
struct Table {