Skip to main content

agg_rust/
pixfmt_transposer.rs

1//! Pixel format transposer.
2//!
3//! Port of `agg_pixfmt_transposer.h`.
4//! Wraps a `PixelFormat`, swapping x/y coordinates for all operations.
5//! Used by blur for vertical pass.
6
7use crate::basics::CoverType;
8use crate::pixfmt_rgba::PixelFormat;
9
10/// Pixel format wrapper that swaps x and y coordinates.
11///
12/// Port of C++ `pixfmt_transposer<PixFmt>`.
13/// Makes horizontal operations act vertically and vice versa.
14pub struct PixfmtTransposer<PF> {
15    pixf: PF,
16}
17
18impl<PF: PixelFormat> PixfmtTransposer<PF> {
19    pub fn new(pixf: PF) -> Self {
20        Self { pixf }
21    }
22
23    pub fn inner(&self) -> &PF {
24        &self.pixf
25    }
26
27    pub fn inner_mut(&mut self) -> &mut PF {
28        &mut self.pixf
29    }
30}
31
32impl<PF: PixelFormat> PixelFormat for PixfmtTransposer<PF> {
33    type ColorType = PF::ColorType;
34
35    fn width(&self) -> u32 {
36        self.pixf.height()
37    }
38
39    fn height(&self) -> u32 {
40        self.pixf.width()
41    }
42
43    fn pixel(&self, x: i32, y: i32) -> PF::ColorType {
44        self.pixf.pixel(y, x)
45    }
46
47    fn copy_pixel(&mut self, x: i32, y: i32, c: &PF::ColorType) {
48        self.pixf.copy_pixel(y, x, c);
49    }
50
51    fn copy_hline(&mut self, x: i32, y: i32, len: u32, c: &PF::ColorType) {
52        // Transposed: copy_hline becomes a vertical column
53        for i in 0..len as i32 {
54            self.pixf.copy_pixel(y, x + i, c);
55        }
56    }
57
58    fn blend_pixel(&mut self, x: i32, y: i32, c: &PF::ColorType, cover: CoverType) {
59        self.pixf.blend_pixel(y, x, c, cover);
60    }
61
62    fn blend_hline(&mut self, x: i32, y: i32, len: u32, c: &PF::ColorType, cover: CoverType) {
63        for i in 0..len as i32 {
64            self.pixf.blend_pixel(y, x + i, c, cover);
65        }
66    }
67
68    fn blend_solid_hspan(
69        &mut self,
70        x: i32,
71        y: i32,
72        len: u32,
73        c: &PF::ColorType,
74        covers: &[CoverType],
75    ) {
76        for (i, &cov) in covers.iter().enumerate().take(len as usize) {
77            self.pixf.blend_pixel(y, x + i as i32, c, cov);
78        }
79    }
80
81    fn blend_color_hspan(
82        &mut self,
83        x: i32,
84        y: i32,
85        len: u32,
86        colors: &[PF::ColorType],
87        covers: &[CoverType],
88        cover: CoverType,
89    ) {
90        if !covers.is_empty() {
91            for i in 0..len as usize {
92                self.pixf.blend_pixel(y, x + i as i32, &colors[i], covers[i]);
93            }
94        } else {
95            for i in 0..len as usize {
96                self.pixf.blend_pixel(y, x + i as i32, &colors[i], cover);
97            }
98        }
99    }
100}
101
102#[cfg(test)]
103mod tests {
104    use super::*;
105    use crate::color::Rgba8;
106    use crate::pixfmt_rgba::PixfmtRgba32;
107    use crate::rendering_buffer::RowAccessor;
108
109    fn make_buffer(w: u32, h: u32) -> (Vec<u8>, RowAccessor) {
110        let stride = (w * 4) as i32;
111        let buf = vec![0u8; (h * w * 4) as usize];
112        let mut ra = RowAccessor::new();
113        unsafe {
114            ra.attach(buf.as_ptr() as *mut u8, w, h, stride);
115        }
116        (buf, ra)
117    }
118
119    #[test]
120    fn test_transposed_dimensions() {
121        let (_buf, mut ra) = make_buffer(100, 50);
122        let pixf = PixfmtRgba32::new(&mut ra);
123        let trans = PixfmtTransposer::new(pixf);
124        assert_eq!(trans.width(), 50); // height becomes width
125        assert_eq!(trans.height(), 100); // width becomes height
126    }
127
128    #[test]
129    fn test_transposed_pixel() {
130        let (_buf, mut ra) = make_buffer(10, 20);
131        let pixf = PixfmtRgba32::new(&mut ra);
132        let mut trans = PixfmtTransposer::new(pixf);
133
134        let red = Rgba8::new(255, 0, 0, 255);
135        trans.copy_pixel(5, 3, &red); // In transposed space: (5,3) → actual (3,5)
136
137        let p = trans.pixel(5, 3);
138        assert_eq!(p.r, 255);
139
140        // Also check via inner at actual coords (3,5)
141        let p2 = trans.inner().pixel(3, 5);
142        assert_eq!(p2.r, 255);
143    }
144}