use crate::{ensure_element, ensure_tag_name, get_attribute}; use anyhow::anyhow; use rgb::RGB8; #[derive(Debug, PartialEq)] pub enum ImageSource { External { /// The reference to the tileset image file (Tiled supports most common image formats). Only used if the image is not embedded. source: String, }, /// Embedded images with a data child element /// /// Note that it is not currently possible to use Tiled to create maps with embedded image data, even though the TMX format supports this Embedded { /// . Valid values are file extensions like png, gif, jpg, bmp, etc. format: String, data: super::data::EncodedData, }, } #[derive(Debug, PartialEq)] pub struct Image { pub source: ImageSource, /// Defines a specific color that is treated as transparent (example value: “#FF00FF” for magenta). /// Including the “#” is optional and Tiled leaves it out for compatibility reasons. (optional) pub transparent_color: Option, /// The image width in pixels (optional, used for tile index correction when the image changes) pub width: Option, /// The image height in pixels (optional) pub height: Option, } impl Image { pub fn from_xml(node: roxmltree::Node) -> anyhow::Result { ensure_element!(node); ensure_tag_name!(node, "image"); let width: Option = match node.attribute("width") { Some(s) => Some(s.parse()?), None => None, }; let height: Option = match node.attribute("height") { Some(s) => Some(s.parse()?), None => None, }; let transparent_color: Option = if let Some(s) = node.attribute("trans") { { let mut c = s.trim_start_matches('#').chars(); if let Some(color) = read_color::rgb(&mut c) { Ok(Some(RGB8 { r: color[0], g: color[1], b: color[2], })) } else { Err(anyhow!("could not parse color")) } }? } else { None }; let image_source = match node.attribute("source") { Some(s) => Ok(ImageSource::External { source: s.to_owned(), }), None => { // embedded let _format = get_attribute!(node, "format")?; // let xmldata_node = match node.children().find(|&c| c.has_tag_name("data")) { // Some(node) => super::data::EncodedData::from_xml(node)?, // None => Err(anyhow!("data element of embeded image not found")), // }; // TODO Err(anyhow!("embeded images are not implemented yet")) } }?; Ok(Image { source: image_source, transparent_color, width, height, }) } } #[cfg(test)] mod parse_image { use crate::lowlevel::image::*; use crate::parse_property_test; #[test] fn image_with_dimensions() { parse_property_test!( Image, r##""##, Image { source: ImageSource::External { source: "beach_tileset.png".to_owned() }, transparent_color: None, width: Some(576), height: Some(416) } ); } #[test] fn image_without_dimensions() { parse_property_test!( Image, r##""##, Image { source: ImageSource::External { source: "perspective_walls.png".to_owned() }, transparent_color: None, width: None, height: None } ); } #[test] fn image_with_transparency_color() { parse_property_test!( Image, r##""##, Image { source: ImageSource::External { source: "sewer_tileset.png".to_owned() }, transparent_color: Some(RGB8 { r: 255, g: 0, b: 255 }), width: Some(192), height: Some(217) } ); parse_property_test!( Image, r##""##, Image { source: ImageSource::External { source: "sewer_tileset.png".to_owned() }, transparent_color: Some(RGB8 { r: 255, g: 0, b: 255 }), width: Some(192), height: Some(217) } ); } // TODO test embeded image }