texture_packer/exporter/
image_exporter.rs

1use crate::{
2    exporter::{ExportResult, Exporter},
3    texture::Texture,
4};
5use image::{DynamicImage, ImageBuffer, Rgba};
6use std::marker::PhantomData;
7use crate::exporter::BackgroundColorSettings;
8
9/// Exporter type for images.
10#[derive(Copy, Clone)]
11pub struct ImageExporter<T>(PhantomData<T>);
12
13impl<T: Texture<Pixel = Rgba<u8>>> ImageExporter<T> {
14    /// Export a texture to an image type.
15    ///
16    /// [background_color]: Background color settings for sections containing no image regions.
17    /// See [BackgroundColorSettings] for more information.
18    pub fn export(texture: &T, background_color: Option<BackgroundColorSettings>) -> ExportResult<DynamicImage> {
19        <Self as Exporter<T>>::export(texture, background_color)
20    }
21}
22
23impl<T: Texture<Pixel = Rgba<u8>>> Exporter<T> for ImageExporter<T> {
24    type Output = DynamicImage;
25
26    fn export(texture: &T, background_color: Option<BackgroundColorSettings>) -> ExportResult<DynamicImage> {
27        let width = texture.width();
28        let height = texture.height();
29
30        if width == 0 || height == 0 {
31            return Err("Width or height of this texture is zero".to_string());
32        }
33
34        let mut pixels = Vec::with_capacity((width * height * 4) as usize);
35
36        match background_color {
37            None => {
38                for row in 0..height {
39                    for col in 0..width {
40                        if let Some(pixel) = texture.get(col, row) {
41                            pixels.push(pixel[0]);
42                            pixels.push(pixel[1]);
43                            pixels.push(pixel[2]);
44                            pixels.push(pixel[3]);
45                        } else {
46                            pixels.push(0);
47                            pixels.push(0);
48                            pixels.push(0);
49                            pixels.push(0);
50                        }
51                    }
52                }
53            }
54            Some(bg) => {
55                let bg_r = bg.color.0[0];
56                let bg_g = bg.color.0[1];
57                let bg_b = bg.color.0[2];
58                let bg_a = bg.color.0[3];
59                for row in 0..height {
60                    for col in 0..width {
61                        if let Some(pixel) = texture.get(col, row) {
62                            let region_r = pixel[0];
63                            let region_g = pixel[1];
64                            let region_b = pixel[2];
65                            let region_a = pixel[3];
66                            if let Some(rthresh) = bg.region_transparency_threshold {
67                                if region_a <= rthresh {
68                                    // override region's own color with background color:
69                                    pixels.push(bg_r);
70                                    pixels.push(bg_g);
71                                    pixels.push(bg_b);
72                                    pixels.push(bg_a);
73                                    continue;
74                                }
75
76                                // the threshold test failed, but we don't want the image region to have
77                                // any transparent pixels regardless:
78                                if bg.discard_own_alpha_on_threshold_test {
79                                    pixels.push(region_r);
80                                    pixels.push(region_g);
81                                    pixels.push(region_b);
82                                    pixels.push(255);
83                                    continue;
84                                }
85                            }
86                            // apply region's own color:
87                            pixels.push(region_r);
88                            pixels.push(region_g);
89                            pixels.push(region_b);
90                            pixels.push(region_a);
91                            continue;
92                        }
93                        // apply background color:
94                        pixels.push(bg_r);
95                        pixels.push(bg_g);
96                        pixels.push(bg_b);
97                        pixels.push(bg_a);
98                    }
99                }
100            }
101        }
102
103        if let Some(image_buffer) =
104            ImageBuffer::<Rgba<u8>, Vec<u8>>::from_raw(width, height, pixels)
105        {
106            Ok(DynamicImage::ImageRgba8(image_buffer))
107        } else {
108            Err("Can't export texture".to_string())
109        }
110    }
111}