1use lazy_static::lazy_static;
14use pathfinder_geometry::rect::RectI;
15use pathfinder_geometry::vector::Vector2I;
16use std::cmp;
17use std::fmt;
18
19use crate::utils;
20
21lazy_static! {
22 static ref BITMAP_1BPP_TO_8BPP_LUT: [[u8; 8]; 256] = {
23 let mut lut = [[0; 8]; 256];
24 for byte in 0..0x100 {
25 let mut value = [0; 8];
26 for bit in 0..8 {
27 if (byte & (0x80 >> bit)) != 0 {
28 value[bit] = 0xff;
29 }
30 }
31 lut[byte] = value
32 }
33 lut
34 };
35}
36
37pub struct Canvas {
39 pub pixels: Vec<u8>,
41 pub size: Vector2I,
43 pub stride: usize,
45 pub format: Format,
47}
48
49impl Canvas {
50 #[inline]
56 pub fn new(size: Vector2I, format: Format) -> Canvas {
57 Canvas::with_stride(
58 size,
59 size.x() as usize * format.bytes_per_pixel() as usize,
60 format,
61 )
62 }
63
64 pub fn with_stride(size: Vector2I, stride: usize, format: Format) -> Canvas {
69 Canvas {
70 pixels: vec![0; stride * size.y() as usize],
71 size,
72 stride,
73 format,
74 }
75 }
76
77 #[allow(dead_code)]
78 pub(crate) fn blit_from_canvas(&mut self, src: &Canvas) {
79 self.blit_from(
80 Vector2I::default(),
81 &src.pixels,
82 src.size,
83 src.stride,
84 src.format,
85 )
86 }
87
88 #[allow(dead_code)]
93 pub(crate) fn blit_from(
94 &mut self,
95 dst_point: Vector2I,
96 src_bytes: &[u8],
97 src_size: Vector2I,
98 src_stride: usize,
99 src_format: Format,
100 ) {
101 assert_eq!(
102 src_stride * src_size.y() as usize,
103 src_bytes.len(),
104 "Number of pixels in src_bytes does not match stride and size."
105 );
106 assert!(
107 src_stride >= src_size.x() as usize * src_format.bytes_per_pixel() as usize,
108 "src_stride must be >= than src_size.x()"
109 );
110
111 let dst_rect = RectI::new(dst_point, src_size);
112 let dst_rect = dst_rect.intersection(RectI::new(Vector2I::default(), self.size));
113 let dst_rect = match dst_rect {
114 Some(dst_rect) => dst_rect,
115 None => return,
116 };
117
118 match (self.format, src_format) {
119 (Format::A8, Format::A8)
120 | (Format::Rgb24, Format::Rgb24)
121 | (Format::Rgba32, Format::Rgba32) => {
122 self.blit_from_with::<BlitMemcpy>(dst_rect, src_bytes, src_stride, src_format)
123 }
124 (Format::A8, Format::Rgb24) => {
125 self.blit_from_with::<BlitRgb24ToA8>(dst_rect, src_bytes, src_stride, src_format)
126 }
127 (Format::Rgb24, Format::A8) => {
128 self.blit_from_with::<BlitA8ToRgb24>(dst_rect, src_bytes, src_stride, src_format)
129 }
130 (Format::Rgb24, Format::Rgba32) => self
131 .blit_from_with::<BlitRgba32ToRgb24>(dst_rect, src_bytes, src_stride, src_format),
132 (Format::Rgba32, Format::Rgb24) => self
133 .blit_from_with::<BlitRgb24ToRgba32>(dst_rect, src_bytes, src_stride, src_format),
134 (Format::Rgba32, Format::A8) | (Format::A8, Format::Rgba32) => unimplemented!(),
135 }
136 }
137
138 #[allow(dead_code)]
139 pub(crate) fn blit_from_bitmap_1bpp(
140 &mut self,
141 dst_point: Vector2I,
142 src_bytes: &[u8],
143 src_size: Vector2I,
144 src_stride: usize,
145 ) {
146 if self.format != Format::A8 {
147 unimplemented!()
148 }
149
150 let dst_rect = RectI::new(dst_point, src_size);
151 let dst_rect = dst_rect.intersection(RectI::new(Vector2I::default(), self.size));
152 let dst_rect = match dst_rect {
153 Some(dst_rect) => dst_rect,
154 None => return,
155 };
156
157 let size = dst_rect.size();
158
159 let dest_bytes_per_pixel = self.format.bytes_per_pixel() as usize;
160 let dest_row_stride = size.x() as usize * dest_bytes_per_pixel;
161 let src_row_stride = utils::div_round_up(size.x() as usize, 8);
162
163 for y in 0..size.y() {
164 let (dest_row_start, src_row_start) = (
165 (y + dst_rect.origin_y()) as usize * self.stride
166 + dst_rect.origin_x() as usize * dest_bytes_per_pixel,
167 y as usize * src_stride,
168 );
169 let dest_row_end = dest_row_start + dest_row_stride;
170 let src_row_end = src_row_start + src_row_stride;
171 let dest_row_pixels = &mut self.pixels[dest_row_start..dest_row_end];
172 let src_row_pixels = &src_bytes[src_row_start..src_row_end];
173 for x in 0..src_row_stride {
174 let pattern = &BITMAP_1BPP_TO_8BPP_LUT[src_row_pixels[x] as usize];
175 let dest_start = x * 8;
176 let dest_end = cmp::min(dest_start + 8, dest_row_stride);
177 let src = &pattern[0..(dest_end - dest_start)];
178 dest_row_pixels[dest_start..dest_end].clone_from_slice(src);
179 }
180 }
181 }
182
183 fn blit_from_with<B: Blit>(
187 &mut self,
188 rect: RectI,
189 src_bytes: &[u8],
190 src_stride: usize,
191 src_format: Format,
192 ) {
193 let src_bytes_per_pixel = src_format.bytes_per_pixel() as usize;
194 let dest_bytes_per_pixel = self.format.bytes_per_pixel() as usize;
195
196 for y in 0..rect.height() {
197 let (dest_row_start, src_row_start) = (
198 (y + rect.origin_y()) as usize * self.stride
199 + rect.origin_x() as usize * dest_bytes_per_pixel,
200 y as usize * src_stride,
201 );
202 let dest_row_end = dest_row_start + rect.width() as usize * dest_bytes_per_pixel;
203 let src_row_end = src_row_start + rect.width() as usize * src_bytes_per_pixel;
204 let dest_row_pixels = &mut self.pixels[dest_row_start..dest_row_end];
205 let src_row_pixels = &src_bytes[src_row_start..src_row_end];
206 B::blit(dest_row_pixels, src_row_pixels)
207 }
208 }
209}
210
211impl fmt::Debug for Canvas {
212 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
213 f.debug_struct("Canvas")
214 .field("pixels", &self.pixels.len()) .field("size", &self.size)
216 .field("stride", &self.stride)
217 .field("format", &self.format)
218 .finish()
219 }
220}
221
222#[derive(Clone, Copy, Debug, PartialEq)]
224pub enum Format {
225 Rgba32,
227 Rgb24,
229 A8,
231}
232
233impl Format {
234 #[inline]
236 pub fn bits_per_pixel(self) -> u8 {
237 match self {
238 Format::Rgba32 => 32,
239 Format::Rgb24 => 24,
240 Format::A8 => 8,
241 }
242 }
243
244 #[inline]
246 pub fn components_per_pixel(self) -> u8 {
247 match self {
248 Format::Rgba32 => 4,
249 Format::Rgb24 => 3,
250 Format::A8 => 1,
251 }
252 }
253
254 #[inline]
256 pub fn bits_per_component(self) -> u8 {
257 self.bits_per_pixel() / self.components_per_pixel()
258 }
259
260 #[inline]
262 pub fn bytes_per_pixel(self) -> u8 {
263 self.bits_per_pixel() / 8
264 }
265}
266
267#[derive(Clone, Copy, Debug, PartialEq)]
269pub enum RasterizationOptions {
270 Bilevel,
272 GrayscaleAa,
274 SubpixelAa,
276}
277
278trait Blit {
279 fn blit(dest: &mut [u8], src: &[u8]);
280}
281
282struct BlitMemcpy;
283
284impl Blit for BlitMemcpy {
285 #[inline]
286 fn blit(dest: &mut [u8], src: &[u8]) {
287 dest.clone_from_slice(src)
288 }
289}
290
291struct BlitRgb24ToA8;
292
293impl Blit for BlitRgb24ToA8 {
294 #[inline]
295 fn blit(dest: &mut [u8], src: &[u8]) {
296 for (dest, src) in dest.iter_mut().zip(src.chunks(3)) {
298 *dest = src[1]
299 }
300 }
301}
302
303struct BlitA8ToRgb24;
304
305impl Blit for BlitA8ToRgb24 {
306 #[inline]
307 fn blit(dest: &mut [u8], src: &[u8]) {
308 for (dest, src) in dest.chunks_mut(3).zip(src.iter()) {
309 dest[0] = *src;
310 dest[1] = *src;
311 dest[2] = *src;
312 }
313 }
314}
315
316struct BlitRgba32ToRgb24;
317
318impl Blit for BlitRgba32ToRgb24 {
319 #[inline]
320 fn blit(dest: &mut [u8], src: &[u8]) {
321 for (dest, src) in dest.chunks_mut(3).zip(src.chunks(4)) {
323 dest.copy_from_slice(&src[0..3])
324 }
325 }
326}
327
328struct BlitRgb24ToRgba32;
329
330impl Blit for BlitRgb24ToRgba32 {
331 fn blit(dest: &mut [u8], src: &[u8]) {
332 for (dest, src) in dest.chunks_mut(4).zip(src.chunks(3)) {
333 dest[0] = src[0];
334 dest[1] = src[1];
335 dest[2] = src[2];
336 dest[3] = 255;
337 }
338 }
339}