ovtile/open/
image_layer.rs

1use alloc::{fmt, str::FromStr, string::String, vec::Vec};
2
3use pbf::{BitCast, ProtoRead, ProtoWrite, Protobuf};
4
5// TODO: This could be faster if we don't read in the grid data on parsing but only if the user needs it
6
7/// Track the image type
8#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
9pub enum ImageType {
10    /// PNG
11    #[default]
12    PNG = 0,
13    /// JPEG
14    JPG = 1,
15    /// WebP
16    WEBP = 2,
17    /// GIF
18    GIF = 3,
19    /// AVIF
20    AVIF = 4,
21    /// SVG
22    SVG = 5,
23    /// BMP
24    BMP = 6,
25    /// RAW
26    RAW = 7,
27    /// Unknown
28    UNKNOWN = 8,
29}
30impl BitCast for ImageType {
31    fn to_u64(&self) -> u64 {
32        (*self) as u64
33    }
34    fn from_u64(value: u64) -> Self {
35        match value {
36            0 => ImageType::PNG,
37            1 => ImageType::JPG,
38            2 => ImageType::WEBP,
39            3 => ImageType::GIF,
40            4 => ImageType::AVIF,
41            5 => ImageType::SVG,
42            6 => ImageType::BMP,
43            7 => ImageType::RAW,
44            8 => ImageType::UNKNOWN,
45            _ => panic!("unknown value: {}", value),
46        }
47    }
48}
49impl FromStr for ImageType {
50    type Err = &'static str;
51
52    fn from_str(s: &str) -> Result<Self, Self::Err> {
53        match s.to_uppercase().as_str() {
54            "PNG" => Ok(ImageType::PNG),
55            "JPG" | "JPEG" => Ok(ImageType::JPG),
56            "WEBP" => Ok(ImageType::WEBP),
57            "GIF" => Ok(ImageType::GIF),
58            "AVIF" => Ok(ImageType::AVIF),
59            "SVG" => Ok(ImageType::SVG),
60            "BMP" => Ok(ImageType::BMP),
61            "RAW" => Ok(ImageType::RAW),
62            "UNKNOWN" => Ok(ImageType::UNKNOWN),
63            #[tarpaulin::skip]
64            _ => Err("Unknown image type"),
65        }
66    }
67}
68impl From<&str> for ImageType {
69    fn from(s: &str) -> Self {
70        ImageType::from_str(s.to_uppercase().as_str()).unwrap_or(ImageType::PNG)
71    }
72}
73impl fmt::Display for ImageType {
74    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75        let name = match self {
76            ImageType::PNG => "PNG",
77            ImageType::JPG => "JPG",
78            ImageType::WEBP => "WEBP",
79            ImageType::GIF => "GIF",
80            ImageType::AVIF => "AVIF",
81            ImageType::SVG => "SVG",
82            ImageType::BMP => "BMP",
83            ImageType::RAW => "RAW",
84            ImageType::UNKNOWN => "UNKNOWN",
85        };
86        write!(f, "{}", name)
87    }
88}
89
90/// Elevation object to read from
91#[derive(Debug, Default, Clone, PartialEq)]
92pub struct ImageData {
93    /// The name of the image
94    pub name: String,
95    /// The image type
96    pub image_type: ImageType,
97    /// The image width
98    pub width: u32,
99    /// The image height
100    pub height: u32,
101    /// The image data
102    pub image: Vec<u8>,
103}
104impl ImageData {
105    /// Create a new ImageData
106    pub fn new(
107        name: String,
108        image_type: ImageType,
109        width: u32,
110        height: u32,
111        image: Vec<u8>,
112    ) -> Self {
113        Self { name, image_type, width, height, image }
114    }
115}
116impl ProtoRead for ImageData {
117    fn read(&mut self, tag: u64, pb: &mut Protobuf) {
118        match tag {
119            0 => self.image_type = pb.read_varint::<ImageType>(),
120            1 => self.width = pb.read_varint(),
121            2 => self.height = pb.read_varint(),
122            3 => self.image = pb.read_bytes(),
123            4 => self.name = pb.read_string(),
124            #[tarpaulin::skip]
125            _ => panic!("unknown tag: {}", tag),
126        }
127    }
128}
129impl ProtoWrite for ImageData {
130    fn write(&self, pb: &mut Protobuf) {
131        pb.write_varint_field(0, self.image_type);
132        pb.write_varint_field(1, self.width);
133        pb.write_varint_field(2, self.height);
134        pb.write_bytes_field(3, &self.image);
135        pb.write_string_field(4, &self.name);
136    }
137}