1use image::{DynamicImage, ImageBuffer, Rgba};
25use std::io::Cursor;
26use std::fmt;
27use std::error::Error as StdError;
28
29#[derive(Debug)]
34pub enum TextureError {
35 ImageError(image::ImageError),
36 IoError(std::io::Error),
37}
38
39impl fmt::Display for TextureError {
40 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41 match self {
42 TextureError::ImageError(err) => write!(f, "Image error: {}", err),
43 TextureError::IoError(err) => write!(f, "IO error: {}", err),
44 }
45 }
46}
47
48impl StdError for TextureError {
49 fn source(&self) -> Option<&(dyn StdError + 'static)> {
50 match self {
51 TextureError::ImageError(err) => Some(err),
52 TextureError::IoError(err) => Some(err),
53 }
54 }
55}
56
57impl From<image::ImageError> for TextureError {
58 fn from(err: image::ImageError) -> Self {
59 TextureError::ImageError(err)
60 }
61}
62
63impl From<std::io::Error> for TextureError {
64 fn from(err: std::io::Error) -> Self {
65 TextureError::IoError(err)
66 }
67}
68
69pub type Result<T> = std::result::Result<T, TextureError>;
71
72#[derive(Debug, Clone, Copy, PartialEq)]
74pub enum TextureFormat {
75 PNG,
76 JPEG,
77}
78
79impl TextureFormat {
80 pub fn mime_type(&self) -> &'static str {
82 match self {
83 TextureFormat::PNG => "image/png",
84 TextureFormat::JPEG => "image/jpeg",
85 }
86 }
87}
88
89pub fn generate_checkerboard(
91 width: u32,
92 height: u32,
93 cell_size: u32,
94 color1: Rgba<u8>,
95 color2: Rgba<u8>,
96) -> DynamicImage {
97 let mut img = ImageBuffer::new(width, height);
98
99 for y in 0..height {
100 for x in 0..width {
101 let cell_x = x / cell_size;
102 let cell_y = y / cell_size;
103
104 let color = if (cell_x + cell_y) % 2 == 0 {
106 color1
107 } else {
108 color2
109 };
110
111 img.put_pixel(x, y, color);
112 }
113 }
114
115 DynamicImage::ImageRgba8(img)
116}
117
118pub fn image_to_png_bytes(image: &DynamicImage) -> Result<Vec<u8>> {
120 let mut bytes: Vec<u8> = Vec::new();
121 let mut cursor = Cursor::new(&mut bytes);
122 image.write_to(&mut cursor, image::ImageOutputFormat::Png)?;
123 Ok(bytes)
124}
125
126pub fn image_to_jpeg_bytes(image: &DynamicImage, quality: u8) -> Result<Vec<u8>> {
128 let mut bytes: Vec<u8> = Vec::new();
129 let mut cursor = Cursor::new(&mut bytes);
130 image.write_to(&mut cursor, image::ImageOutputFormat::Jpeg(quality))?;
131 Ok(bytes)
132}
133
134pub fn image_to_bytes(image: &DynamicImage, format: TextureFormat) -> Result<Vec<u8>> {
136 match format {
137 TextureFormat::PNG => image_to_png_bytes(image),
138 TextureFormat::JPEG => image_to_jpeg_bytes(image, 90), }
140}
141
142pub fn create_uv_test_pattern(width: u32, height: u32) -> DynamicImage {
144 generate_checkerboard(
145 width,
146 height,
147 width / 8, Rgba([255, 255, 255, 255]), Rgba([0, 0, 0, 255]), )
151}
152
153pub fn create_colored_checkerboard(
155 width: u32,
156 height: u32,
157 cell_size: u32,
158 color1: [u8; 3],
159 color2: [u8; 3],
160) -> DynamicImage {
161 generate_checkerboard(
162 width,
163 height,
164 cell_size,
165 Rgba([color1[0], color1[1], color1[2], 255]),
166 Rgba([color2[0], color2[1], color2[2], 255]),
167 )
168}