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<RGB8>,
/// The image width in pixels (optional, used for tile index correction when the image changes)
pub width: Option<usize>,
/// The image height in pixels (optional)
pub height: Option<usize>,
}
impl Image {
pub fn from_xml(node: roxmltree::Node) -> anyhow::Result<Image> {
ensure_element!(node);
ensure_tag_name!(node, "image");
let width: Option<usize> = match node.attribute("width") {
Some(s) => Some(s.parse()?),
None => None,
};
let height: Option<usize> = match node.attribute("height") {
Some(s) => Some(s.parse()?),
None => None,
};
let transparent_color: Option<RGB8> = 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="beach_tileset.png" width="576" height="416"/>"##,
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="perspective_walls.png"/>"##,
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="sewer_tileset.png" trans="ff00ff" width="192" height="217"/>"##,
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="sewer_tileset.png" trans="#ff00ff" width="192" height="217"/>"##,
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
}