Repository: igumnoff/shiva (language: rust)

Issue:
Add width, height and align to Image
1. core.rs change Image:

 width, height should be Optional
 
 align should be Enum (left, right, center)
 
 2. add implementation for HTML, PDF

 3. Tests requered


Discussion / hints:
I would like to work on this one.
ok

Fix patch:
diff --git a/lib/src/core.rs b/lib/src/core.rs
index fc4849e..ed87223 100644
--- a/lib/src/core.rs
+++ b/lib/src/core.rs
@@ -3,6 +3,7 @@ use bytes::Bytes;
 use serde::{Deserialize, Serialize};
 use wasm_bindgen::prelude::wasm_bindgen;
 use std::fmt::Debug;
+use std::str::FromStr;
 use thiserror::Error;
 use strum::{VariantArray, EnumString, Display, IntoStaticStr, EnumCount};
 
@@ -119,13 +120,7 @@ pub enum Element {
         elements: Vec<ListItem>,
         numbered: bool,
     },
-    Image {
-        #[cfg_attr(feature = "json", serde(skip))]
-        bytes: Bytes,
-        title: String,
-        alt: String,
-        image_type: ImageType,
-    },
+    Image(ImageData),
     Hyperlink {
         title: String,
         url: String,
@@ -157,11 +152,153 @@ pub struct TableCell {
     pub element: Element,
 }
 
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, PartialEq, Default)]
+#[cfg_attr(feature = "json", derive(Serialize, Deserialize))]
+pub struct ImageData {
+    #[cfg_attr(feature = "json", serde(skip))]
+    bytes: Bytes,
+    title: String,
+    alt: String,
+    image_type: ImageType,
+    align: ImageAlignment,
+    size: ImageDimension
+}
+
+/**
+ * ImageData methods
+ */
+impl ImageData {
+    pub fn new(
+        bytes: Bytes,
+        title: String,
+        alt: String,
+        src_or_type: String,
+        alignment: String,
+        size: ImageDimension,
+    ) -> ImageData {
+        let mut image_data = ImageData {
+            bytes,
+            title,
+            alt,
+            image_type: ImageType::default(),
+            align: ImageAlignment::default(),
+            size
+        };
+        image_data.set_image_type(&src_or_type);
+        image_data.set_image_alignment(&alignment);
+        image_data
+    }
+
+    pub fn set_image_type(&mut self, image_type_str: &str) {
+        let image_type_str = image_type_str
+            .split('.')
+            .last()
+            .unwrap_or("")
+            .trim()
+            .to_lowercase();
+
+        if image_type_str.trim().is_empty() {
+            self.image_type = ImageType::default();
+            return;
+        }
+
+        match ImageType::from_str(&image_type_str) {
+            Ok(image_type) => self.image_type = image_type,
+            Err(_) => panic!("Invalid image type: {}", image_type_str),
+        }
+    }
+
+    pub fn set_image_alignment(&mut self, alignment_str: &str) {
+        if alignment_str.trim().is_empty() {
+            self.align = ImageAlignment::default();
+            return;
+        }
+        match ImageAlignment::from_str(alignment_str) {
+            Ok(alignment) => self.align = alignment,
+            Err(_) => panic!("Invalid image alignment: {}", alignment_str),
+        }
+    }
+
+    pub fn set_image_bytes(&mut self, bytes: Bytes) {
+        self.bytes = bytes;
+    }
+
+    pub fn set_image_alt(&mut self, alt: &str) {
+        self.alt = alt.to_string();
+    }
+
+    pub fn set_image_title(&mut self, title: &str) {
+        self.title = title.to_string();
+    }
+
+    pub fn set_image_size(&mut self, size: ImageDimension) {
+        self.size = size;
+    }
+
+    pub fn bytes(&self) -> &Bytes {
+        &self.bytes
+    }
+
+    pub fn title(&self) -> &str {
+        &self.title
+    }
+
+    pub fn alt(&self) -> &str {
+        &self.alt
+    }
+
+    pub fn image_type(&self) -> &ImageType {
+        &self.image_type
+    }
+
+    pub fn align(&self) -> &ImageAlignment {
+        &self.align
+    }
+
+    pub fn size(&self) -> &ImageDimension{
+        &self.size
+    }
+
+}
+
+#[derive(Debug, Clone, PartialEq, Default, Display, EnumString, VariantArray)]
 #[cfg_attr(feature = "json", derive(Serialize, Deserialize))]
+#[strum(serialize_all = "lowercase")]
 pub enum ImageType {
+    #[default]
     Png,
     Jpeg,
+    Gif,
+    SVG
+}
+
+impl ImageType {
+    pub fn to_extension(&self) -> &str {
+        match self {
+            ImageType::Png => ".png",
+            ImageType::Jpeg => ".jpeg",
+            ImageType::Gif => ".gif",
+            ImageType::SVG => ".svg",
+        }
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Default, EnumString, Display, VariantArray)]
+#[cfg_attr(feature = "json", derive(Serialize, Deserialize))]
+#[strum(serialize_all = "lowercase")]
+pub enum ImageAlignment {
+    Left,
+    Center,
+    Right,
+    #[default]
+    None,
+}
+
+#[derive(Debug, Clone, PartialEq, Default)]
+#[cfg_attr(feature = "json", derive(Serialize, Deserialize))]
+pub struct ImageDimension {
+    pub width: Option<String>,
+    pub height: Option<String>,
 }
 
 
@@ -263,4 +400,47 @@ mod tests {
         assert_eq!(DocumentType::XLSX as u8, 10);
     }
 
+    #[test]
+    fn test_image_type_from_str() {
+        assert_eq!(ImageType::from_str("png").unwrap(), ImageType::Png);
+        assert_eq!(ImageType::from_str("jpeg").unwrap(), ImageType::Jpeg);
+        assert_eq!(ImageType::from_str("gif").unwrap(), ImageType::Gif);
+    }
+
+    #[test]
+    fn test_image_new() {
+        let bytes = Bytes::from("image".as_bytes());
+        let image = ImageData::new(bytes.clone(), "title".to_string(), "alt".to_string(), "/name/image.png".to_string(), "center".to_string(), ImageDimension { width: Some("50%".to_string()), height: Some("200".to_string())});
+        assert_eq!(image.bytes(), &bytes);
+        assert_eq!(image.title(), "title");
+        assert_eq!(image.alt(), "alt");
+        assert_eq!(image.image_type(), &ImageType::Png);
+    }
+
+    #[test]
+    fn test_image_type_extension() {
+        assert_eq!(ImageType::Png.to_extension(), ".png");
+        assert_eq!(ImageType::Jpeg.to_extension(), ".jpeg");
+    }
+
+    #[test]
+    fn test_image_type_defaut() {
+        assert_eq!(ImageType::Png, ImageType::default());
+    }
+
+    #[test]
+    fn test_image_type_display() {
+        assert_eq!("png", ImageType::Png.to_string());
+        assert_eq!("jpeg", ImageType::Jpeg.to_string());
+    }
+
+    #[test]
+    fn test_image_alignment() {
+        assert_eq!(ImageAlignment::Left, ImageAlignment::from_str("left").unwrap());
+        assert_eq!(ImageAlignment::Center, ImageAlignment::from_str("center").unwrap());
+        assert_eq!(ImageAlignment::Right, ImageAlignment::from_str("right").unwrap());
+    }
+
+
+
 }
\ No newline at end of file
diff --git a/lib/src/docx.rs b/lib/src/docx.rs
index 5c67f8c..91207e3 100644
--- a/lib/src/docx.rs
+++ b/lib/src/docx.rs
@@ -1,4 +1,4 @@
-use crate::core::{Document, Element, ListItem, TableCell, TableRow, TransformerTrait};
+use crate::core::{Document, Element, ImageDimension, ListItem, TableCell, TableRow, TransformerTrait};
 
 use bytes::Bytes;
 use docx_rs::{read_docx, Docx, Hyperlink, HyperlinkType, Paragraph, ParagraphStyle,
@@ -414,8 +414,19 @@ impl TransformerTrait for Transformer {
                     doc = doc.add_paragraph(Paragraph::add_hyperlink(paragraph, hyperlink));
                 }
 
-                Element::Image { bytes, title: _, alt: _, image_type: _, } => {
-                    let mut pic = Pic::new(&bytes);
+                Element::Image(image) => {
+                    let mut pic = Pic::new(&image.bytes());
+
+                    match &image.size() {
+                        &ImageDimension { width: Some(width), height: Some(height) } => {
+                            let width = width.parse().unwrap_or(0);
+                            let height =  height.parse().unwrap_or(0);
+                            if width > 0 && height > 0 {
+                                pic = pic.size(width, height);
+                            }
+                        },
+                        _ => {}
+                    }
 
                     pic = re_size_picture(pic);
 
diff --git a/lib/src/html.rs b/lib/src/html.rs
index bc48b45..be93496 100644
--- a/lib/src/html.rs
+++ b/lib/src/html.rs
@@ -240,13 +240,18 @@ where F: Fn(&str) -> anyhow::Result<Bytes>
                     let src = element.attr("src").unwrap_or_default();
                     let title = element.attr("title").unwrap_or_default();
                     let alt = element.attr("alt").unwrap_or_default();
+                    let align = element.attr("align").unwrap_or_default();
+                    let width = element.attr("width").and_then(|s| s.parse().ok());
+                    let height = element.attr("height").and_then(|s| s.parse().ok());
                     let image_bytes = (image_loader.function)(src)?;
-                    elements.push(Image {
-                        bytes: image_bytes,
-                        title: title.to_string(),
-                        alt: alt.to_string(),
-                        image_type: ImageType::Png,
-                    });
+                    elements.push(Image(ImageData::new(
+                        image_bytes,
+                        title.to_string(),
+                        alt.to_string(),
+                        src.to_string(),
+                        align.to_string(),
+                        ImageDimension {width,height}
+                    )));
                 }
                 "ul" | "ol" => {
                     let mut list_items: Vec<ListItem> = Vec::new();
@@ -346,19 +351,29 @@ fn generate_html_for_element(
             list_html.push('\n');
             Ok(list_html)
         }
-        Image {
-            bytes,
-            title,
-            alt,
-            image_type: _,
-        } => {
+        Image(image) => {
             let image_path = format!("image{}.png", image_num);
             // images.insert(image_path.to_string(), bytes.clone());
-            (image_saver.function)(bytes, &image_path)?;
+            (image_saver.function)(image.bytes(), &image_path)?;
             *image_num += 1;
+
+            let align_str = match image.align() {
+                ImageAlignment::None => String::new(),
+                _ => format!(" align=\"{}\"", image.align()),
+            };
+
+            let width_str = match &image.size().width {
+                Some(width) => format!(" width=\"{}\"", width),
+                None => String::new(),
+            };
+
+            let height_str = match &image.size().height {
+                Some(height) => format!(" height=\"{}\"", height),
+                None => String::new(),
+            };
             Ok(format!(
-                "<img src=\"{}\" alt=\"{}\" title=\"{}\" />",
-                image_path, alt, title
+                "<img src=\"{}\" alt=\"{}\" title=\"{}\"{}{}{} />",
+                image_path, image.alt(), image.title(), align_str, width_str, height_str
             ))
         }
         Hyperlink {
@@ -404,7 +419,7 @@ mod tests {
         let document_html = r#"
         <html>
         <body>
-        <p>123<img src="small.png"></p>
+        <p>123<img alt="smal image" align="left" src="small.png" width="100" height="99" title="image"></p>
         </body>
         </html>
         "#;
diff --git a/lib/src/markdown.rs b/lib/src/markdown.rs
index 446dfcf..5972989 100644
--- a/lib/src/markdown.rs
+++ b/lib/src/markdown.rs
@@ -151,20 +151,15 @@ impl TransformerWithImageLoaderSaverTrait for Transformer {
                             dest_url, title, ..
                         } => {
                             let img_type = dest_url.to_string();
-                            let img_type = img_type.split('.').last().unwrap();
-                            let image_type = match img_type {
-                                "png" => ImageType::Png,
-                                "jpeg" => ImageType::Jpeg,
-                                _ => ImageType::Png,
-                            };
-
                             let bytes = image_loader(&dest_url)?;
-                            let img_el = Element::Image {
+                            let img_el = Element::Image(ImageData::new(
                                 bytes,
-                                title: title.to_string(),
-                                alt: title.to_string(),
-                                image_type,
-                            };
+                                title.to_string(),
+                                title.to_string(),
+                                img_type,
+                                "".to_string(),
+                                ImageDimension::default()
+                            ));
                             // Before image there is paragraph tag (likely because alt text is in paragraph )
                             current_element = None;
                             process_element_creation(&mut current_element, img_el, list_depth);
@@ -237,11 +232,8 @@ impl TransformerWithImageLoaderSaverTrait for Transformer {
                                     _ => {}
                                 }
                             }
-                            Element::Image {
-                                alt,
-                                ..
-                            } => {
-                                *alt = text.to_string();
+                            Element::Image(image) => {
+                                image.set_image_alt(&text)
                             }
                             Element::Hyperlink {
                                 alt,
@@ -455,16 +447,11 @@ impl TransformerWithImageLoaderSaverTrait for Transformer {
                         markdown.push_str(&format!("[{}]({} \"{}\")", title, url, alt));
                     }
                 }
-                Image {
-                    bytes,
-                    title,
-                    alt,
-                    image_type: _,
-                } => {
-                    let image_path = format!("image{}.png", image_num);
-                    markdown.push_str(&format!("![{}]({} \"{}\")", alt, image_path, title));
+                Image(image) => {
+                    let image_path = format!("image{}.{}", image_num, image.image_type());
+                    markdown.push_str(&format!("![{}]({} \"{}\")", image.alt(), image_path, image.title()));
                     markdown.push('\n');
-                    (saver.function)(&bytes, &image_path)?;
+                    (saver.function)(&image.bytes(), &image_path)?;
                     *image_num += 1;
                 }
                 Table { headers, rows } => {
diff --git a/lib/src/text.rs b/lib/src/text.rs
index 01f51fb..bb2d127 100644
--- a/lib/src/text.rs
+++ b/lib/src/text.rs
@@ -142,15 +142,10 @@ impl TransformerTrait for Transformer {
                         markdown.push_str(&format!("[{}]({} \"{}\")", title, url, alt));
                     }
                 }
-                Image {
-                    bytes,
-                    title,
-                    alt,
-                    image_type: _,
-                } => {
+                Image(image) => {
                     let image_path = format!("image{}.png", image_num);
-                    markdown.push_str(&format!("![{}]({} \"{}\")", alt, image_path, title));
-                    images.insert(image_path.to_string(), bytes.clone());
+                    markdown.push_str(&format!("![{}]({} \"{}\")", image.alt(), image_path, image.title()));
+                    images.insert(image_path.to_string(), image.bytes().clone());
                     *image_num += 1;
                 }
                 Table { headers, rows } => {
diff --git a/lib/src/typst.rs b/lib/src/typst.rs
index 9e79ef6..b75632e 100644
--- a/lib/src/typst.rs
+++ b/lib/src/typst.rs
@@ -4,7 +4,7 @@ use bytes::Bytes;
 use anyhow;
 use std::{collections::HashMap, io::Cursor};
 use crate::core::{
-    Document, Element, ImageType, ListItem, TableHeader, TableRow, TransformerTrait,
+    Document, Element, ListItem, TableHeader, TableRow, TransformerTrait,
 };
 use time::{OffsetDateTime, UtcOffset};
 use std::path::Path;
@@ -381,19 +381,10 @@ pub fn generate_document(document: &Document) -> anyhow::Result<(TypstString, Ha
                 process_table(source, headers, rows)?;
                 Ok(())
             }
-            Image {
-                bytes,
-                title,
-                alt,
-                image_type,
-            } => {
-                let image_type = match image_type {
-                    ImageType::Jpeg => ".jpeg",
-                    ImageType::Png => ".png",
-                };
-                let key = format!("{title}{image_type}");
-                img_map.insert(key, typst::foundations::Bytes::from(bytes.to_vec()));
-                process_image(source, bytes, title, alt, image_type)?;
+            Image(image) => {
+                let key = format!("{}{}",image.title(),image.image_type());
+                img_map.insert(key, typst::foundations::Bytes::from(image.bytes().to_vec()));
+                process_image(source, image.bytes(), image.title(), image.alt(), &image.image_type().to_string())?;
                 source.push('\n');
                 Ok(())
             }
@@ -458,4 +449,15 @@ mod test {
 
         Ok(())
     }
+
+    #[test]
+    fn test_generate_from_xml() -> anyhow::Result<()> {
+        let document = std::fs::read("test/data/document.xml")?;
+        let documents_bytes = Bytes::from(document);
+        let parsed = crate::xml::Transformer::parse(&documents_bytes)?;
+        let generated_result = crate::typst::Transformer::generate(&parsed)?;
+        std::fs::write("test/data/document_from_xml.typ", generated_result)?;
+
+        Ok(())
+    }
 }
\ No newline at end of file
diff --git a/lib/src/xml.rs b/lib/src/xml.rs
index 69567a1..f7e8e45 100644
--- a/lib/src/xml.rs
+++ b/lib/src/xml.rs
@@ -1,17 +1,10 @@
 use anyhow::Result;
 use bytes::Bytes;
 use quick_xml::{ events::{ BytesDecl, BytesEnd, BytesStart, BytesText, Event }, Reader, Writer };
-use std::str::from_utf8;
+use std::str::{from_utf8};
 
 use crate::core::{
-    Document,
-    Element,
-    TransformerTrait,
-    ListItem,
-    TableHeader,
-    TableRow,
-    ImageType,
-    TableCell,
+    ImageDimension, Document, Element, ImageAlignment, ImageData, ImageType, ListItem, TableCell, TableHeader, TableRow, TransformerTrait
 };
 
 use serde::{ Deserialize, Serialize };
@@ -182,20 +175,15 @@ impl TransformerTrait for Transformer {
                         let mut image_bytes = Bytes::new();
                         let mut alt = "_";
                         let mut title = "_";
-                        let mut image_type = ImageType::Png;
+                        let mut image_type = ImageType::default().to_string();
+                        let mut align = ImageAlignment::default().to_string();
+                        let mut width = None;
+                        let mut height = None;
                         for child in element.children.iter() {
                             match child.name.as_str() {
                                 "image_type" => {
                                     if let Some(value) = &child.text {
-                                        match value.as_str() {
-                                            "Png" | "PNG" | "png" => {
-                                                image_type = ImageType::Png;
-                                            }
-                                            "Jpeg" | "JPEG" | "jpeg" => {
-                                                image_type = ImageType::Jpeg;
-                                            }
-                                            _ => {}
-                                        }
+                                        image_type = value.to_string();
                                     } else {
                                         println!("Error: No value");
                                     }
@@ -220,16 +208,39 @@ impl TransformerTrait for Transformer {
                                     } else {
                                         println!("Error: No value");
                                     }
-                                }
+                                },
+                                "align" => {
+                                    if let Some(value) = &child.text {
+                                        align = value.to_string();
+                                    } else {
+                                        println!("Error: No value");
+                                    }
+                                },
+                                "width" => {
+                                    if let Some(value) = &child.text {
+                                        width = Some(value.parse()?);
+                                    } else {
+                                        println!("Error: No value");
+                                    }
+                                },
+                                "height" => {
+                                    if let Some(value) = &child.text {
+                                        height = Some(value.parse()?);
+                                    } else {
+                                        println!("Error: No value");
+                                    }
+                                },
                                 _ => {}
                             }
                         }
-                        elements.push(Element::Image {
-                            bytes: image_bytes,
-                            title: title.to_string(),
-                            alt: alt.to_string(),
-                            image_type: image_type,
-                        });
+                        elements.push(Element::Image(ImageData::new(
+                            image_bytes,
+                            title.to_string(),
+                            alt.to_string(),
+                            image_type,
+                            align,
+                            ImageDimension {width,height},
+                        )));
                     }
                     "Hyperlink" => {
                         let mut url = "_";
@@ -729,30 +740,23 @@ impl TransformerTrait for Transformer {
                     writer.write_event(Event::End(BytesEnd::new("size")))?;
                     writer.write_event(Event::End(BytesEnd::new("Text")))?;
                 }
-                Element::Image { bytes, title, alt, image_type } => {
+                Element::Image(image) => {
                     writer.write_event(Event::Start(BytesStart::new("Image")))?;
                     writer.write_event(Event::Start(BytesStart::new("title")))?;
-                    writer.write_event(Event::Text(BytesText::new(title)))?;
+                    writer.write_event(Event::Text(BytesText::new(image.title())))?;
                     writer.write_event(Event::End(BytesEnd::new("title")))?;
                     writer.write_event(Event::Start(BytesStart::new("alt")))?;
-                    writer.write_event(Event::Text(BytesText::new(alt)))?;
+                    writer.write_event(Event::Text(BytesText::new(image.alt())))?;
                     writer.write_event(Event::End(BytesEnd::new("alt")))?;
                     writer.write_event(Event::Start(BytesStart::new("bytes")))?;
                     writer.write_event(
                         Event::Text(
-                            BytesText::new(&String::from_utf8(bytes.to_vec()).unwrap().to_string())
+                            BytesText::new(&String::from_utf8(image.bytes().to_vec()).unwrap().to_string())
                         )
                     )?;
                     writer.write_event(Event::End(BytesEnd::new("bytes")))?;
                     writer.write_event(Event::Start(BytesStart::new("image_type")))?;
-                    match image_type {
-                        ImageType::Png => {
-                            writer.write_event(Event::Text(BytesText::new("Png")))?;
-                        }
-                        ImageType::Jpeg => {
-                            writer.write_event(Event::Text(BytesText::new("Jpeg")))?;
-                        }
-                    }
+                    writer.write_event(Event::Text(BytesText::new(&image.image_type().to_string())))?;
                     writer.write_event(Event::End(BytesEnd::new("image_type")))?;
                     writer.write_event(Event::End(BytesEnd::new("Image")))?;
                 }


Test patch:
diff --git a/lib/test/data/document.xml b/lib/test/data/document.xml
index 1f19979..644b5d2 100644
--- a/lib/test/data/document.xml
+++ b/lib/test/data/document.xml
@@ -16,6 +16,9 @@
                <alt>Some alt</alt>
                <bytes>base64==</bytes>
                <image_type>Png</image_type>
+               <width>100</width>
+               <height>100</height>
+               <align>center</align>
             </Image>
             <Hyperlink>
                <url>http://example.com</url>
diff --git a/lib/test/data/document_from_md.docx b/lib/test/data/document_from_md.docx
new file mode 100644
index 0000000..683eeb6
Binary files /dev/null and b/lib/test/data/document_from_md.docx differ
diff --git a/lib/test/data/document_from_xml.docx b/lib/test/data/document_from_xml.docx
new file mode 100644
index 0000000..f93ff71
Binary files /dev/null and b/lib/test/data/document_from_xml.docx differ
diff --git a/lib/test/data/document_from_xml.typ b/lib/test/data/document_from_xml.typ
new file mode 100644
index 0000000..1500210
--- /dev/null
+++ b/lib/test/data/document_from_xml.typ
@@ -0,0 +1,23 @@
+#set page(
+        header: "Page Headerheader end",
+        footer: "Page Footerfooter end",
+    )
+= 123
+Hello, world!
+
+            #image("Some titlepng", alt: "Some alt")
+            
+#link("http://example.com")
++ Item 1
++ Item 2
+ - Item 2.1
+- Item 2.2
+
+        #table(
+            columns:2,
+            [*Name*],[*Salary*],
+            [John Doe],[2000$],
+[Marry Doe],[1000$],
+
+        )
+        
\ No newline at end of file
diff --git a/lib/test/data/image2.png b/lib/test/data/image2.png
new file mode 100644
index 0000000..50b67f8
Binary files /dev/null and b/lib/test/data/image2.png differ
diff --git a/test/src/html.rs b/test/src/html.rs
index 1309427..f956a97 100644
--- a/test/src/html.rs
+++ b/test/src/html.rs
@@ -3,10 +3,9 @@ mod tests {
     use bytes::Bytes;
     use shiva::core::Element::{Header, Hyperlink, Image, List, Paragraph, Table, Text};
     use shiva::core::{
-        Document, Element, ImageType, ListItem, TableCell, TableHeader, TableRow, TransformerTrait,
+        Document, Element, ImageAlignment, ImageData, ImageDimension, ImageType, ListItem, TableCell, TableHeader, TableRow, TransformerTrait
     };
     use shiva::html::Transformer;
-    use std::collections::HashMap;
 
     #[test]
     fn test_html_header_parse() -> anyhow::Result<()> {
@@ -495,13 +494,8 @@ mod tests {
         let elements: Vec<Element> = parsed.elements;
         match &elements[0] {
             Paragraph { elements } => match &elements[0] {
-                Image {
-                    title,
-                    alt: _,
-                    image_type: _,
-                    bytes: _,
-                } => {
-                    assert_eq!(title, "Picture title2");
+                Image(image) => {
+                    assert_eq!(image.title(), "Picture title2");
                 }
                 _ => panic!("Expected Paragraph"),
             },
@@ -532,12 +526,14 @@ mod tests {
                         }
                     },
                     {
-                        Image {
-                            alt: "Picture alt2".to_string(),
-                            image_type: ImageType::Png,
-                            title: "Picture title2".to_string(),
-                            bytes: Bytes::from(image_bytes),
-                        }
+                        Image(ImageData::new(
+                            Bytes::from(image_bytes),
+                            "Picture title2".to_string(),
+                            "Picture alt2".to_string(),
+                            ImageType::default().to_string(),
+                            ImageAlignment::default().to_string(),
+                            ImageDimension::default(),
+                        ))
                     },
                     {
                         Text {