plotchart/drawing/backend_impl/
bitmap.rs

1use crate::drawing::backend::{BackendCoord, BackendStyle, DrawingBackend, DrawingErrorKind};
2use crate::style::{Color, RGBAColor};
3use std::marker::PhantomData;
4
5#[cfg(all(not(target_arch = "wasm32"), feature = "image"))]
6mod image_encoding_support {
7    pub(super) use image::{ImageBuffer, ImageError, Rgb};
8    pub(super) use std::path::Path;
9    pub(super) type BorrowedImage<'a> = ImageBuffer<Rgb<u8>, &'a mut [u8]>;
10}
11
12#[cfg(all(not(target_arch = "wasm32"), feature = "image"))]
13use image_encoding_support::*;
14
15#[derive(Debug)]
16/// Indicates some error occurs within the bitmap backend
17pub enum BitMapBackendError {
18    /// The buffer provided is invalid, for example, wrong pixel buffer size
19    InvalidBuffer,
20    /// Some IO error occurs while the bitmap maniuplation
21    IOError(std::io::Error),
22    #[cfg(all(not(target_arch = "wasm32"), feature = "image"))]
23    /// Image encoding error
24    ImageError(ImageError),
25}
26
27impl std::fmt::Display for BitMapBackendError {
28    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
29        write!(f, "{:?}", self)
30    }
31}
32
33impl std::error::Error for BitMapBackendError {}
34
35#[inline(always)]
36fn blend(prev: &mut u8, new: u8, a: u64) {
37    if new > *prev {
38        *prev += (u64::from(new - *prev) * a / 256) as u8
39    } else {
40        *prev -= (u64::from(*prev - new) * a / 256) as u8
41    }
42}
43
44#[cfg(all(feature = "gif", not(target_arch = "wasm32"), feature = "image"))]
45mod gif_support {
46    use super::*;
47    use gif::{Encoder as GifEncoder, Frame as GifFrame, Repeat, SetParameter};
48    use std::fs::File;
49
50    pub(super) struct GifFile {
51        encoder: GifEncoder<File>,
52        height: u32,
53        width: u32,
54        delay: u32,
55    }
56
57    impl GifFile {
58        pub(super) fn new<T: AsRef<Path>>(
59            path: T,
60            dim: (u32, u32),
61            delay: u32,
62        ) -> Result<Self, BitMapBackendError> {
63            let mut encoder = GifEncoder::new(
64                File::create(path.as_ref()).map_err(BitMapBackendError::IOError)?,
65                dim.0 as u16,
66                dim.1 as u16,
67                &[],
68            )
69            .map_err(BitMapBackendError::IOError)?;
70
71            encoder
72                .set(Repeat::Infinite)
73                .map_err(BitMapBackendError::IOError)?;
74
75            Ok(Self {
76                encoder,
77                width: dim.0,
78                height: dim.1,
79                delay: (delay + 5) / 10,
80            })
81        }
82
83        pub(super) fn flush_frame(&mut self, buffer: &[u8]) -> Result<(), BitMapBackendError> {
84            let mut frame =
85                GifFrame::from_rgb_speed(self.width as u16, self.height as u16, buffer, 10);
86
87            frame.delay = self.delay as u16;
88
89            self.encoder
90                .write_frame(&frame)
91                .map_err(BitMapBackendError::IOError)?;
92
93            Ok(())
94        }
95    }
96}
97
98enum Target<'a> {
99    #[cfg(all(not(target_arch = "wasm32"), feature = "image"))]
100    File(&'a Path),
101    Buffer(PhantomData<&'a u32>),
102    #[cfg(all(feature = "gif", not(target_arch = "wasm32"), feature = "image"))]
103    Gif(Box<gif_support::GifFile>),
104}
105
106enum Buffer<'a> {
107    #[cfg(all(not(target_arch = "wasm32"), feature = "image"))]
108    Owned(Vec<u8>),
109    Borrowed(&'a mut [u8]),
110}
111
112impl<'a> Buffer<'a> {
113    #[inline(always)]
114    fn borrow_buffer(&mut self) -> &mut [u8] {
115        match self {
116            #[cfg(all(not(target_arch = "wasm32"), feature = "image"))]
117            Buffer::Owned(buf) => &mut buf[..],
118            Buffer::Borrowed(buf) => *buf,
119        }
120    }
121}
122
123/// The trait that describes some details about a particular pixel format
124pub trait PixelFormat: Sized {
125    /// Number of bytes per pixel
126    const PIXEL_SIZE: usize;
127
128    /// Number of effective bytes per pixel, e.g. for BGRX pixel format, the size of pixel
129    /// is 4 but the effective size is 3, since the 4th byte isn't used
130    const EFFECTIVE_PIXEL_SIZE: usize;
131
132    /// Encoding a pixel and returns the idx-th byte for the pixel
133    fn byte_at(r: u8, g: u8, b: u8, a: u64, idx: usize) -> u8;
134
135    /// Decode a pixel at the given location
136    fn decode_pixel(data: &[u8]) -> (u8, u8, u8, u64);
137
138    /// The fast alpha blending algorithm for this pixel format
139    ///
140    /// - `target`: The target bitmap backend
141    /// - `upper_left`: The upper-left coord for the rect
142    /// - `bottom_right`: The bottom-right coord for the rect
143    /// - `r`, `g`, `b`, `a`: The blending color and alpha value
144    fn blend_rect_fast(
145        target: &mut BitMapBackend<'_, Self>,
146        upper_left: (i32, i32),
147        bottom_right: (i32, i32),
148        r: u8,
149        g: u8,
150        b: u8,
151        a: f64,
152    );
153
154    /// The fast vertical line filling algorithm
155    ///
156    /// - `target`: The target bitmap backend
157    /// - `x`: the X coordinate for the entire line
158    /// - `ys`: The range of y coord
159    /// - `r`, `g`, `b`: The blending color and alpha value
160    fn fill_vertical_line_fast(
161        target: &mut BitMapBackend<'_, Self>,
162        x: i32,
163        ys: (i32, i32),
164        r: u8,
165        g: u8,
166        b: u8,
167    ) {
168        let (w, h) = target.get_size();
169        let w = w as i32;
170        let h = h as i32;
171
172        // Make sure we are in the range
173        if x < 0 || x >= w {
174            return;
175        }
176
177        let dst = target.get_raw_pixel_buffer();
178        let (mut y0, mut y1) = ys;
179        if y0 > y1 {
180            std::mem::swap(&mut y0, &mut y1);
181        }
182        // And check the y axis isn't out of bound
183        y0 = y0.max(0);
184        y1 = y1.min(h - 1);
185        // This is ok because once y0 > y1, there won't be any iteration anymore
186        for y in y0..=y1 {
187            for idx in 0..Self::EFFECTIVE_PIXEL_SIZE {
188                dst[(y * w + x) as usize * Self::PIXEL_SIZE + idx] = Self::byte_at(r, g, b, 0, idx);
189            }
190        }
191    }
192
193    /// The fast rectangle filling algorithm
194    ///
195    /// - `target`: The target bitmap backend
196    /// - `upper_left`: The upper-left coord for the rect
197    /// - `bottom_right`: The bottom-right coord for the rect
198    /// - `r`, `g`, `b`: The filling color
199    fn fill_rect_fast(
200        target: &mut BitMapBackend<'_, Self>,
201        upper_left: (i32, i32),
202        bottom_right: (i32, i32),
203        r: u8,
204        g: u8,
205        b: u8,
206    );
207
208    #[inline(always)]
209    /// Drawing a single pixel in this format
210    ///
211    /// - `target`: The target bitmap backend
212    /// - `point`: The coord of the point
213    /// - `r`, `g`, `b`: The filling color
214    /// - `alpha`: The alpha value
215    fn draw_pixel(
216        target: &mut BitMapBackend<'_, Self>,
217        point: (i32, i32),
218        (r, g, b): (u8, u8, u8),
219        alpha: f64,
220    ) {
221        let (x, y) = (point.0 as usize, point.1 as usize);
222        let (w, _) = target.get_size();
223        let buf = target.get_raw_pixel_buffer();
224        let w = w as usize;
225        let base = (y * w + x) * Self::PIXEL_SIZE;
226
227        if base < buf.len() {
228            unsafe {
229                if alpha >= 1.0 - 1.0 / 256.0 {
230                    for idx in 0..Self::EFFECTIVE_PIXEL_SIZE {
231                        *buf.get_unchecked_mut(base + idx) = Self::byte_at(r, g, b, 0, idx);
232                    }
233                } else {
234                    if alpha <= 0.0 {
235                        return;
236                    }
237
238                    let alpha = (alpha * 256.0).floor() as u64;
239                    for idx in 0..Self::EFFECTIVE_PIXEL_SIZE {
240                        blend(
241                            buf.get_unchecked_mut(base + idx),
242                            Self::byte_at(r, g, b, 0, idx),
243                            alpha,
244                        );
245                    }
246                }
247            }
248        }
249    }
250
251    /// Indicates if this pixel format can be saved as image.
252    /// Note: Currently we only using RGB pixel format in the image crate, but later we may lift
253    /// this restriction
254    ///
255    /// - `returns`: If the image can be saved as image file
256    fn can_be_saved() -> bool {
257        false
258    }
259}
260
261/// The marker type that indicates we are currently using a RGB888 pixel format
262pub struct RGBPixel;
263
264/// The marker type that indicates we are currently using a BGRX8888 pixel format
265pub struct BGRXPixel;
266
267impl PixelFormat for RGBPixel {
268    const PIXEL_SIZE: usize = 3;
269    const EFFECTIVE_PIXEL_SIZE: usize = 3;
270
271    #[inline(always)]
272    fn byte_at(r: u8, g: u8, b: u8, _a: u64, idx: usize) -> u8 {
273        match idx {
274            0 => r,
275            1 => g,
276            2 => b,
277            _ => 0xff,
278        }
279    }
280
281    #[inline(always)]
282    fn decode_pixel(data: &[u8]) -> (u8, u8, u8, u64) {
283        (data[0], data[1], data[2], 0x255)
284    }
285
286    fn can_be_saved() -> bool {
287        true
288    }
289
290    #[allow(clippy::many_single_char_names, clippy::cast_ptr_alignment)]
291    fn blend_rect_fast(
292        target: &mut BitMapBackend<'_, Self>,
293        upper_left: (i32, i32),
294        bottom_right: (i32, i32),
295        r: u8,
296        g: u8,
297        b: u8,
298        a: f64,
299    ) {
300        let (w, h) = target.get_size();
301        let a = a.min(1.0).max(0.0);
302        if a == 0.0 {
303            return;
304        }
305
306        let (x0, y0) = (
307            upper_left.0.min(bottom_right.0).max(0),
308            upper_left.1.min(bottom_right.1).max(0),
309        );
310        let (x1, y1) = (
311            upper_left.0.max(bottom_right.0).min(w as i32 - 1),
312            upper_left.1.max(bottom_right.1).min(h as i32 - 1),
313        );
314
315        // This may happen when the minimal value is larger than the limit.
316        // Thus we just have something that is completely out-of-range
317        if x0 > x1 || y0 > y1 {
318            return;
319        }
320
321        let dst = target.get_raw_pixel_buffer();
322
323        let a = (256.0 * a).floor() as u64;
324
325        // Since we should always make sure the RGB payload occupies the logic lower bits
326        // thus, this type purning should work for both LE and BE CPUs
327        #[rustfmt::skip]
328        let (p1, p2, p3): (u64, u64, u64) = unsafe {
329            std::mem::transmute([
330                u16::from(r), u16::from(b), u16::from(g), u16::from(r), // QW1
331                u16::from(b), u16::from(g), u16::from(r), u16::from(b), // QW2
332                u16::from(g), u16::from(r), u16::from(b), u16::from(g), // QW3
333            ])
334        };
335
336        #[rustfmt::skip]
337        let (q1, q2, q3): (u64, u64, u64) = unsafe {
338            std::mem::transmute([
339                u16::from(g), u16::from(r), u16::from(b), u16::from(g), // QW1
340                u16::from(r), u16::from(b), u16::from(g), u16::from(r), // QW2
341                u16::from(b), u16::from(g), u16::from(r), u16::from(b), // QW3
342            ])
343        };
344
345        const N: u64 = 0xff00_ff00_ff00_ff00;
346        const M: u64 = 0x00ff_00ff_00ff_00ff;
347
348        for y in y0..=y1 {
349            let start = (y * w as i32 + x0) as usize;
350            let count = (x1 - x0 + 1) as usize;
351
352            let start_ptr = &mut dst[start * Self::PIXEL_SIZE] as *mut u8 as *mut [u8; 24];
353            let slice = unsafe { std::slice::from_raw_parts_mut(start_ptr, (count - 1) / 8) };
354            for p in slice.iter_mut() {
355                let ptr = p as *mut [u8; 24] as *mut (u64, u64, u64);
356                let (d1, d2, d3) = unsafe { *ptr };
357                let (mut h1, mut h2, mut h3) = ((d1 >> 8) & M, (d2 >> 8) & M, (d3 >> 8) & M);
358                let (mut l1, mut l2, mut l3) = (d1 & M, d2 & M, d3 & M);
359
360                #[cfg(target_endian = "little")]
361                {
362                    h1 = (h1 * (256 - a) + q1 * a) & N;
363                    h2 = (h2 * (256 - a) + q2 * a) & N;
364                    h3 = (h3 * (256 - a) + q3 * a) & N;
365                    l1 = ((l1 * (256 - a) + p1 * a) & N) >> 8;
366                    l2 = ((l2 * (256 - a) + p2 * a) & N) >> 8;
367                    l3 = ((l3 * (256 - a) + p3 * a) & N) >> 8;
368                }
369
370                #[cfg(target_endian = "big")]
371                {
372                    h1 = (h1 * (256 - a) + p1 * a) & N;
373                    h2 = (h2 * (256 - a) + p2 * a) & N;
374                    h3 = (h3 * (256 - a) + p3 * a) & N;
375                    l1 = ((l1 * (256 - a) + q1 * a) & N) >> 8;
376                    l2 = ((l2 * (256 - a) + q2 * a) & N) >> 8;
377                    l3 = ((l3 * (256 - a) + q3 * a) & N) >> 8;
378                }
379
380                unsafe {
381                    *ptr = (h1 | l1, h2 | l2, h3 | l3);
382                }
383            }
384
385            let mut iter = dst[((start + slice.len() * 8) * Self::PIXEL_SIZE)
386                ..((start + count) * Self::PIXEL_SIZE)]
387                .iter_mut();
388            for _ in (slice.len() * 8)..count {
389                blend(iter.next().unwrap(), r, a);
390                blend(iter.next().unwrap(), g, a);
391                blend(iter.next().unwrap(), b, a);
392            }
393        }
394    }
395
396    #[allow(clippy::many_single_char_names, clippy::cast_ptr_alignment)]
397    fn fill_rect_fast(
398        target: &mut BitMapBackend<'_, Self>,
399        upper_left: (i32, i32),
400        bottom_right: (i32, i32),
401        r: u8,
402        g: u8,
403        b: u8,
404    ) {
405        let (w, h) = target.get_size();
406        let (x0, y0) = (
407            upper_left.0.min(bottom_right.0).max(0),
408            upper_left.1.min(bottom_right.1).max(0),
409        );
410        let (x1, y1) = (
411            upper_left.0.max(bottom_right.0).min(w as i32 - 1),
412            upper_left.1.max(bottom_right.1).min(h as i32 - 1),
413        );
414
415        // This may happen when the minimal value is larger than the limit.
416        // Thus we just have something that is completely out-of-range
417        if x0 > x1 || y0 > y1 {
418            return;
419        }
420
421        let dst = target.get_raw_pixel_buffer();
422
423        if r == g && g == b {
424            // If r == g == b, then we can use memset
425            if x0 != 0 || x1 != w as i32 - 1 {
426                // If it's not the entire row is filled, we can only do
427                // memset per row
428                for y in y0..=y1 {
429                    let start = (y * w as i32 + x0) as usize;
430                    let count = (x1 - x0 + 1) as usize;
431                    dst[(start * Self::PIXEL_SIZE)..((start + count) * Self::PIXEL_SIZE)]
432                        .iter_mut()
433                        .for_each(|e| *e = r);
434                }
435            } else {
436                // If the entire memory block is going to be filled, just use single memset
437                dst[Self::PIXEL_SIZE * (y0 * w as i32) as usize
438                    ..((y1 + 1) * w as i32) as usize * Self::PIXEL_SIZE]
439                    .iter_mut()
440                    .for_each(|e| *e = r);
441            }
442        } else {
443            let count = (x1 - x0 + 1) as usize;
444            if count < 8 {
445                for y in y0..=y1 {
446                    let start = (y * w as i32 + x0) as usize;
447                    let mut iter = dst
448                        [(start * Self::PIXEL_SIZE)..((start + count) * Self::PIXEL_SIZE)]
449                        .iter_mut();
450                    for _ in 0..=(x1 - x0) {
451                        *iter.next().unwrap() = r;
452                        *iter.next().unwrap() = g;
453                        *iter.next().unwrap() = b;
454                    }
455                }
456            } else {
457                for y in y0..=y1 {
458                    let start = (y * w as i32 + x0) as usize;
459                    let start_ptr = &mut dst[start * Self::PIXEL_SIZE] as *mut u8 as *mut [u8; 24];
460                    let slice =
461                        unsafe { std::slice::from_raw_parts_mut(start_ptr, (count - 1) / 8) };
462                    for p in slice.iter_mut() {
463                        // In this case, we can actually fill 8 pixels in one iteration with
464                        // only 3 movq instructions.
465                        // TODO: Consider using AVX instructions when possible
466                        let ptr = p as *mut [u8; 24] as *mut u64;
467                        unsafe {
468                            let (d1, d2, d3): (u64, u64, u64) = std::mem::transmute([
469                                r, g, b, r, g, b, r, g, // QW1
470                                b, r, g, b, r, g, b, r, // QW2
471                                g, b, r, g, b, r, g, b, // QW3
472                            ]);
473                            *ptr = d1;
474                            *ptr.offset(1) = d2;
475                            *ptr.offset(2) = d3;
476                        }
477                    }
478
479                    for idx in (slice.len() * 8)..count {
480                        dst[start * Self::PIXEL_SIZE + idx * Self::PIXEL_SIZE] = r;
481                        dst[start * Self::PIXEL_SIZE + idx * Self::PIXEL_SIZE + 1] = g;
482                        dst[start * Self::PIXEL_SIZE + idx * Self::PIXEL_SIZE + 2] = b;
483                    }
484                }
485            }
486        }
487    }
488}
489
490impl PixelFormat for BGRXPixel {
491    const PIXEL_SIZE: usize = 4;
492    const EFFECTIVE_PIXEL_SIZE: usize = 3;
493
494    #[inline(always)]
495    fn byte_at(r: u8, g: u8, b: u8, _a: u64, idx: usize) -> u8 {
496        match idx {
497            0 => b,
498            1 => g,
499            2 => r,
500            _ => 0xff,
501        }
502    }
503
504    #[inline(always)]
505    fn decode_pixel(data: &[u8]) -> (u8, u8, u8, u64) {
506        (data[2], data[1], data[0], 0x255)
507    }
508
509    #[allow(clippy::many_single_char_names, clippy::cast_ptr_alignment)]
510    fn blend_rect_fast(
511        target: &mut BitMapBackend<'_, Self>,
512        upper_left: (i32, i32),
513        bottom_right: (i32, i32),
514        r: u8,
515        g: u8,
516        b: u8,
517        a: f64,
518    ) {
519        let (w, h) = target.get_size();
520        let a = a.min(1.0).max(0.0);
521        if a == 0.0 {
522            return;
523        }
524
525        let (x0, y0) = (
526            upper_left.0.min(bottom_right.0).max(0),
527            upper_left.1.min(bottom_right.1).max(0),
528        );
529        let (x1, y1) = (
530            upper_left.0.max(bottom_right.0).min(w as i32 - 1),
531            upper_left.1.max(bottom_right.1).min(h as i32 - 1),
532        );
533
534        // This may happen when the minimal value is larger than the limit.
535        // Thus we just have something that is completely out-of-range
536        if x0 > x1 || y0 > y1 {
537            return;
538        }
539
540        let dst = target.get_raw_pixel_buffer();
541
542        let a = (256.0 * a).floor() as u64;
543
544        // Since we should always make sure the RGB payload occupies the logic lower bits
545        // thus, this type purning should work for both LE and BE CPUs
546        #[rustfmt::skip]
547        let p: u64 = unsafe {
548            std::mem::transmute([
549                u16::from(b), u16::from(r), u16::from(b), u16::from(r), // QW1
550            ])
551        };
552
553        #[rustfmt::skip]
554        let q: u64 = unsafe {
555            std::mem::transmute([
556                u16::from(g), 0u16, u16::from(g), 0u16, // QW1
557            ])
558        };
559
560        const N: u64 = 0xff00_ff00_ff00_ff00;
561        const M: u64 = 0x00ff_00ff_00ff_00ff;
562
563        for y in y0..=y1 {
564            let start = (y * w as i32 + x0) as usize;
565            let count = (x1 - x0 + 1) as usize;
566
567            let start_ptr = &mut dst[start * Self::PIXEL_SIZE] as *mut u8 as *mut [u8; 8];
568            let slice = unsafe { std::slice::from_raw_parts_mut(start_ptr, (count - 1) / 2) };
569            for rp in slice.iter_mut() {
570                let ptr = rp as *mut [u8; 8] as *mut u64;
571                let d1 = unsafe { *ptr };
572                let mut h = (d1 >> 8) & M;
573                let mut l = d1 & M;
574
575                #[cfg(target_endian = "little")]
576                {
577                    h = (h * (256 - a) + q * a) & N;
578                    l = ((l * (256 - a) + p * a) & N) >> 8;
579                }
580
581                #[cfg(target_endian = "big")]
582                {
583                    h = (h * (256 - a) + p * a) & N;
584                    l = ((l * (256 - a) + q * a) & N) >> 8;
585                }
586
587                unsafe {
588                    *ptr = h | l;
589                }
590            }
591
592            let mut iter = dst[((start + slice.len() * 2) * Self::PIXEL_SIZE)
593                ..((start + count) * Self::PIXEL_SIZE)]
594                .iter_mut();
595            for _ in (slice.len() * 2)..count {
596                blend(iter.next().unwrap(), b, a);
597                blend(iter.next().unwrap(), g, a);
598                blend(iter.next().unwrap(), r, a);
599                iter.next();
600            }
601        }
602    }
603
604    #[allow(clippy::many_single_char_names, clippy::cast_ptr_alignment)]
605    fn fill_rect_fast(
606        target: &mut BitMapBackend<'_, Self>,
607        upper_left: (i32, i32),
608        bottom_right: (i32, i32),
609        r: u8,
610        g: u8,
611        b: u8,
612    ) {
613        let (w, h) = target.get_size();
614        let (x0, y0) = (
615            upper_left.0.min(bottom_right.0).max(0),
616            upper_left.1.min(bottom_right.1).max(0),
617        );
618        let (x1, y1) = (
619            upper_left.0.max(bottom_right.0).min(w as i32 - 1),
620            upper_left.1.max(bottom_right.1).min(h as i32 - 1),
621        );
622
623        // This may happen when the minimal value is larger than the limit.
624        // Thus we just have something that is completely out-of-range
625        if x0 > x1 || y0 > y1 {
626            return;
627        }
628
629        let dst = target.get_raw_pixel_buffer();
630
631        if r == g && g == b {
632            // If r == g == b, then we can use memset
633            if x0 != 0 || x1 != w as i32 - 1 {
634                // If it's not the entire row is filled, we can only do
635                // memset per row
636                for y in y0..=y1 {
637                    let start = (y * w as i32 + x0) as usize;
638                    let count = (x1 - x0 + 1) as usize;
639                    dst[(start * Self::PIXEL_SIZE)..((start + count) * Self::PIXEL_SIZE)]
640                        .iter_mut()
641                        .for_each(|e| *e = r);
642                }
643            } else {
644                // If the entire memory block is going to be filled, just use single memset
645                dst[Self::PIXEL_SIZE * (y0 * w as i32) as usize
646                    ..((y1 + 1) * w as i32) as usize * Self::PIXEL_SIZE]
647                    .iter_mut()
648                    .for_each(|e| *e = r);
649            }
650        } else {
651            let count = (x1 - x0 + 1) as usize;
652            if count < 8 {
653                for y in y0..=y1 {
654                    let start = (y * w as i32 + x0) as usize;
655                    let mut iter = dst
656                        [(start * Self::PIXEL_SIZE)..((start + count) * Self::PIXEL_SIZE)]
657                        .iter_mut();
658                    for _ in 0..=(x1 - x0) {
659                        *iter.next().unwrap() = b;
660                        *iter.next().unwrap() = g;
661                        *iter.next().unwrap() = r;
662                        iter.next();
663                    }
664                }
665            } else {
666                for y in y0..=y1 {
667                    let start = (y * w as i32 + x0) as usize;
668                    let start_ptr = &mut dst[start * Self::PIXEL_SIZE] as *mut u8 as *mut [u8; 8];
669                    let slice =
670                        unsafe { std::slice::from_raw_parts_mut(start_ptr, (count - 1) / 2) };
671                    for p in slice.iter_mut() {
672                        // In this case, we can actually fill 8 pixels in one iteration with
673                        // only 3 movq instructions.
674                        // TODO: Consider using AVX instructions when possible
675                        let ptr = p as *mut [u8; 8] as *mut u64;
676                        unsafe {
677                            let d: u64 = std::mem::transmute([
678                                b, g, r, 0, b, g, r, 0, // QW1
679                            ]);
680                            *ptr = d;
681                        }
682                    }
683
684                    for idx in (slice.len() * 2)..count {
685                        dst[start * Self::PIXEL_SIZE + idx * Self::PIXEL_SIZE] = b;
686                        dst[start * Self::PIXEL_SIZE + idx * Self::PIXEL_SIZE + 1] = g;
687                        dst[start * Self::PIXEL_SIZE + idx * Self::PIXEL_SIZE + 2] = r;
688                    }
689                }
690            }
691        }
692    }
693}
694
695/// The backend that drawing a bitmap
696pub struct BitMapBackend<'a, P: PixelFormat = RGBPixel> {
697    /// The path to the image
698    #[allow(dead_code)]
699    target: Target<'a>,
700    /// The size of the image
701    size: (u32, u32),
702    /// The data buffer of the image
703    buffer: Buffer<'a>,
704    /// Flag indicates if the bitmap has been saved
705    saved: bool,
706    _pantomdata: PhantomData<P>,
707}
708
709impl<'a, P: PixelFormat> BitMapBackend<'a, P> {
710    /// The number of bytes per pixel
711    const PIXEL_SIZE: usize = P::PIXEL_SIZE;
712}
713
714impl<'a> BitMapBackend<'a, RGBPixel> {
715    /// Create a new bitmap backend
716    #[cfg(all(not(target_arch = "wasm32"), feature = "image"))]
717    pub fn new<T: AsRef<Path> + ?Sized>(path: &'a T, (w, h): (u32, u32)) -> Self {
718        Self {
719            target: Target::File(path.as_ref()),
720            size: (w, h),
721            buffer: Buffer::Owned(vec![0; Self::PIXEL_SIZE * (w * h) as usize]),
722            saved: false,
723            _pantomdata: PhantomData,
724        }
725    }
726
727    /// Create a new bitmap backend that generate GIF animation
728    ///
729    /// When this is used, the bitmap backend acts similar to a real-time rendering backend.
730    /// When the program finished drawing one frame, use `present` function to flush the frame
731    /// into the GIF file.
732    ///
733    /// - `path`: The path to the GIF file to create
734    /// - `dimension`: The size of the GIF image
735    /// - `speed`: The amount of time for each frame to display
736    #[cfg(all(feature = "gif", not(target_arch = "wasm32"), feature = "image"))]
737    pub fn gif<T: AsRef<Path>>(
738        path: T,
739        (w, h): (u32, u32),
740        frame_delay: u32,
741    ) -> Result<Self, BitMapBackendError> {
742        Ok(Self {
743            target: Target::Gif(Box::new(gif_support::GifFile::new(
744                path,
745                (w, h),
746                frame_delay,
747            )?)),
748            size: (w, h),
749            buffer: Buffer::Owned(vec![0; Self::PIXEL_SIZE * (w * h) as usize]),
750            saved: false,
751            _pantomdata: PhantomData,
752        })
753    }
754
755    /// Create a new bitmap backend which only lives in-memory
756    ///
757    /// When this is used, the bitmap backend will write to a user provided [u8] array (or Vec<u8>)
758    /// in RGB pixel format.
759    ///
760    /// Note: This function provides backward compatibility for those code that assumes Plotters
761    /// uses RGB pixel format and maniuplates the in-memory framebuffer.
762    /// For more pixel format option, use `with_buffer_and_format` instead.
763    ///
764    /// - `buf`: The buffer to operate
765    /// - `dimension`: The size of the image in pixels
766    /// - **returns**: The newly created bitmap backend
767    pub fn with_buffer(buf: &'a mut [u8], (w, h): (u32, u32)) -> Self {
768        Self::with_buffer_and_format(buf, (w, h)).expect("Wrong buffer size")
769    }
770}
771
772impl<'a, P: PixelFormat> BitMapBackend<'a, P> {
773    /// Create a new bitmap backend with a in-memory buffer with specific pixel format.
774    ///
775    /// Note: This can be used as a way to manipulate framebuffer, `mmap` can be used on the top of this
776    /// as well.
777    ///
778    /// - `buf`: The buffer to operate
779    /// - `dimension`: The size of the image in pixels
780    /// - **returns**: The newly created bitmap backend
781    pub fn with_buffer_and_format(
782        buf: &'a mut [u8],
783        (w, h): (u32, u32),
784    ) -> Result<Self, BitMapBackendError> {
785        if (w * h) as usize * Self::PIXEL_SIZE > buf.len() {
786            return Err(BitMapBackendError::InvalidBuffer);
787        }
788
789        Ok(Self {
790            target: Target::Buffer(PhantomData),
791            size: (w, h),
792            buffer: Buffer::Borrowed(buf),
793            saved: false,
794            _pantomdata: PhantomData,
795        })
796    }
797
798    #[inline(always)]
799    fn get_raw_pixel_buffer(&mut self) -> &mut [u8] {
800        self.buffer.borrow_buffer()
801    }
802
803    /// Split a bitmap backend vertically into several sub drawing area which allows
804    /// multi-threading rendering.
805    ///
806    /// - `area_size`: The size of the area
807    /// - **returns**: The splitted backends that can be rendered in parallel
808    pub fn split(&mut self, area_size: &[u32]) -> Vec<BitMapBackend<P>> {
809        let (w, h) = self.get_size();
810        let buf = self.get_raw_pixel_buffer();
811
812        let base_addr = &mut buf[0] as *mut u8;
813        let mut split_points = vec![0];
814        for size in area_size {
815            let next = split_points.last().unwrap() + size;
816            if next >= h {
817                break;
818            }
819            split_points.push(next);
820        }
821        split_points.push(h);
822
823        split_points
824            .iter()
825            .zip(split_points.iter().skip(1))
826            .map(|(begin, end)| {
827                let actual_buf = unsafe {
828                    std::slice::from_raw_parts_mut(
829                        base_addr.offset((begin * w) as isize * Self::PIXEL_SIZE as isize),
830                        ((end - begin) * w) as usize * Self::PIXEL_SIZE,
831                    )
832                };
833                Self::with_buffer_and_format(actual_buf, (w, end - begin)).unwrap()
834            })
835            .collect()
836    }
837}
838
839impl<'a, P: PixelFormat> DrawingBackend for BitMapBackend<'a, P> {
840    type ErrorType = BitMapBackendError;
841
842    fn get_size(&self) -> (u32, u32) {
843        self.size
844    }
845
846    fn ensure_prepared(&mut self) -> Result<(), DrawingErrorKind<BitMapBackendError>> {
847        self.saved = false;
848        Ok(())
849    }
850
851    #[cfg(any(target_arch = "wasm32", not(feature = "image")))]
852    fn present(&mut self) -> Result<(), DrawingErrorKind<BitMapBackendError>> {
853        Ok(())
854    }
855
856    #[cfg(all(not(target_arch = "wasm32"), feature = "image"))]
857    fn present(&mut self) -> Result<(), DrawingErrorKind<BitMapBackendError>> {
858        if !P::can_be_saved() {
859            return Ok(());
860        }
861        let (w, h) = self.get_size();
862        match &mut self.target {
863            Target::File(path) => {
864                if let Some(img) = BorrowedImage::from_raw(w, h, self.buffer.borrow_buffer()) {
865                    img.save(&path).map_err(|x| {
866                        DrawingErrorKind::DrawingError(BitMapBackendError::IOError(x))
867                    })?;
868                    self.saved = true;
869                    Ok(())
870                } else {
871                    Err(DrawingErrorKind::DrawingError(
872                        BitMapBackendError::InvalidBuffer,
873                    ))
874                }
875            }
876            Target::Buffer(_) => Ok(()),
877
878            #[cfg(all(feature = "gif", not(target_arch = "wasm32"), feature = "image"))]
879            Target::Gif(target) => {
880                target
881                    .flush_frame(self.buffer.borrow_buffer())
882                    .map_err(DrawingErrorKind::DrawingError)?;
883                self.saved = true;
884                Ok(())
885            }
886        }
887    }
888
889    fn draw_pixel(
890        &mut self,
891        point: BackendCoord,
892        color: &RGBAColor,
893    ) -> Result<(), DrawingErrorKind<BitMapBackendError>> {
894        if point.0 < 0 || point.1 < 0 {
895            return Ok(());
896        }
897
898        let alpha = color.alpha();
899        let rgb = color.rgb();
900
901        P::draw_pixel(self, point, rgb, alpha);
902
903        Ok(())
904    }
905
906    fn draw_line<S: BackendStyle>(
907        &mut self,
908        from: (i32, i32),
909        to: (i32, i32),
910        style: &S,
911    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
912        let alpha = style.as_color().alpha();
913        let (r, g, b) = style.as_color().rgb();
914
915        if from.0 == to.0 || from.1 == to.1 {
916            if alpha >= 1.0 {
917                if from.1 == to.1 {
918                    P::fill_rect_fast(self, from, to, r, g, b);
919                } else {
920                    P::fill_vertical_line_fast(self, from.0, (from.1, to.1), r, g, b);
921                }
922            } else {
923                P::blend_rect_fast(self, from, to, r, g, b, alpha);
924            }
925            return Ok(());
926        }
927
928        crate::drawing::rasterizer::draw_line(self, from, to, style)
929    }
930
931    fn draw_rect<S: BackendStyle>(
932        &mut self,
933        upper_left: (i32, i32),
934        bottom_right: (i32, i32),
935        style: &S,
936        fill: bool,
937    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
938        let alpha = style.as_color().alpha();
939        let (r, g, b) = style.as_color().rgb();
940        if fill {
941            if alpha >= 1.0 {
942                P::fill_rect_fast(self, upper_left, bottom_right, r, g, b);
943            } else {
944                P::blend_rect_fast(self, upper_left, bottom_right, r, g, b, alpha);
945            }
946            return Ok(());
947        }
948        crate::drawing::rasterizer::draw_rect(self, upper_left, bottom_right, style, fill)
949    }
950
951    fn blit_bitmap<'b>(
952        &mut self,
953        pos: BackendCoord,
954        (sw, sh): (u32, u32),
955        src: &'b [u8],
956    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
957        let (dw, dh) = self.get_size();
958
959        let (x0, y0) = pos;
960        let (x1, y1) = (x0 + sw as i32, y0 + sh as i32);
961
962        let (x0, y0, x1, y1) = (x0.max(0), y0.max(0), x1.min(dw as i32), y1.min(dh as i32));
963
964        if x0 == x1 || y0 == y1 {
965            return Ok(());
966        }
967
968        let mut chunk_size = (x1 - x0) as usize;
969        let mut num_chunks = (y1 - y0) as usize;
970        let dst_gap = dw as usize - chunk_size;
971        let src_gap = sw as usize - chunk_size;
972
973        let dst_start = Self::PIXEL_SIZE * (y0 as usize * dw as usize + x0 as usize);
974
975        let mut dst = &mut self.get_raw_pixel_buffer()[dst_start..];
976
977        let src_start =
978            Self::PIXEL_SIZE * ((sh as i32 + y0 - y1) * sw as i32 + (sw as i32 + x0 - x1)) as usize;
979        let mut src = &src[src_start..];
980
981        if src_gap == 0 && dst_gap == 0 {
982            chunk_size *= num_chunks;
983            num_chunks = 1;
984        }
985        for i in 0..num_chunks {
986            dst[0..(chunk_size * Self::PIXEL_SIZE)]
987                .copy_from_slice(&src[0..(chunk_size * Self::PIXEL_SIZE)]);
988            if i != num_chunks - 1 {
989                dst = &mut dst[((chunk_size + dst_gap) * Self::PIXEL_SIZE)..];
990                src = &src[((chunk_size + src_gap) * Self::PIXEL_SIZE)..];
991            }
992        }
993
994        Ok(())
995    }
996}
997
998impl<P: PixelFormat> Drop for BitMapBackend<'_, P> {
999    fn drop(&mut self) {
1000        if !self.saved {
1001            self.present().expect("Unable to save the bitmap");
1002        }
1003    }
1004}
1005
1006#[cfg(test)]
1007#[test]
1008fn test_bitmap_backend() {
1009    use crate::prelude::*;
1010    let mut buffer = vec![0; 10 * 10 * 3];
1011
1012    {
1013        let back = BitMapBackend::with_buffer(&mut buffer, (10, 10));
1014
1015        let area = back.into_drawing_area();
1016        area.fill(&WHITE).unwrap();
1017        area.draw(&PathElement::new(vec![(0, 0), (10, 10)], RED.filled()))
1018            .unwrap();
1019        area.present().unwrap();
1020    }
1021
1022    for i in 0..10 {
1023        assert_eq!(buffer[i * 33], 255);
1024        assert_eq!(buffer[i * 33 + 1], 0);
1025        assert_eq!(buffer[i * 33 + 2], 0);
1026        buffer[i * 33] = 255;
1027        buffer[i * 33 + 1] = 255;
1028        buffer[i * 33 + 2] = 255;
1029    }
1030
1031    assert!(buffer.into_iter().all(|x| x == 255));
1032}
1033
1034#[cfg(test)]
1035#[test]
1036fn test_bitmap_backend_fill_half() {
1037    use crate::prelude::*;
1038    let mut buffer = vec![0; 10 * 10 * 3];
1039
1040    {
1041        let back = BitMapBackend::with_buffer(&mut buffer, (10, 10));
1042
1043        let area = back.into_drawing_area();
1044        area.draw(&Rectangle::new([(0, 0), (5, 10)], RED.filled()))
1045            .unwrap();
1046        area.present().unwrap();
1047    }
1048    for x in 0..10 {
1049        for y in 0..10 {
1050            assert_eq!(
1051                buffer[(y * 10 + x) as usize * 3 + 0],
1052                if x <= 5 { 255 } else { 0 }
1053            );
1054            assert_eq!(buffer[(y * 10 + x) as usize * 3 + 1], 0);
1055            assert_eq!(buffer[(y * 10 + x) as usize * 3 + 2], 0);
1056        }
1057    }
1058
1059    let mut buffer = vec![0; 10 * 10 * 3];
1060
1061    {
1062        let back = BitMapBackend::with_buffer(&mut buffer, (10, 10));
1063
1064        let area = back.into_drawing_area();
1065        area.draw(&Rectangle::new([(0, 0), (10, 5)], RED.filled()))
1066            .unwrap();
1067        area.present().unwrap();
1068    }
1069    for x in 0..10 {
1070        for y in 0..10 {
1071            assert_eq!(
1072                buffer[(y * 10 + x) as usize * 3 + 0],
1073                if y <= 5 { 255 } else { 0 }
1074            );
1075            assert_eq!(buffer[(y * 10 + x) as usize * 3 + 1], 0);
1076            assert_eq!(buffer[(y * 10 + x) as usize * 3 + 2], 0);
1077        }
1078    }
1079}
1080
1081#[cfg(test)]
1082#[test]
1083fn test_bitmap_backend_blend() {
1084    use crate::prelude::*;
1085    let mut buffer = vec![255; 10 * 10 * 3];
1086
1087    {
1088        let back = BitMapBackend::with_buffer(&mut buffer, (10, 10));
1089
1090        let area = back.into_drawing_area();
1091        area.draw(&Rectangle::new(
1092            [(0, 0), (5, 10)],
1093            RGBColor(0, 100, 200).mix(0.2).filled(),
1094        ))
1095        .unwrap();
1096        area.present().unwrap();
1097    }
1098
1099    for x in 0..10 {
1100        for y in 0..10 {
1101            let (r, g, b) = if x <= 5 {
1102                (205, 225, 245)
1103            } else {
1104                (255, 255, 255)
1105            };
1106            assert_eq!(buffer[(y * 10 + x) as usize * 3 + 0], r);
1107            assert_eq!(buffer[(y * 10 + x) as usize * 3 + 1], g);
1108            assert_eq!(buffer[(y * 10 + x) as usize * 3 + 2], b);
1109        }
1110    }
1111}
1112
1113#[cfg(test)]
1114#[test]
1115fn test_bitmap_backend_split_and_fill() {
1116    use crate::prelude::*;
1117    let mut buffer = vec![255; 10 * 10 * 3];
1118
1119    {
1120        let mut back = BitMapBackend::with_buffer(&mut buffer, (10, 10));
1121
1122        for (sub_backend, color) in back.split(&[5]).into_iter().zip([&RED, &GREEN].iter()) {
1123            sub_backend.into_drawing_area().fill(*color).unwrap();
1124        }
1125    }
1126
1127    for x in 0..10 {
1128        for y in 0..10 {
1129            let (r, g, b) = if y < 5 { (255, 0, 0) } else { (0, 255, 0) };
1130            assert_eq!(buffer[(y * 10 + x) as usize * 3 + 0], r);
1131            assert_eq!(buffer[(y * 10 + x) as usize * 3 + 1], g);
1132            assert_eq!(buffer[(y * 10 + x) as usize * 3 + 2], b);
1133        }
1134    }
1135}
1136
1137#[cfg(test)]
1138#[test]
1139fn test_draw_rect_out_of_range() {
1140    use crate::prelude::*;
1141    let mut buffer = vec![0; 1099 * 1000 * 3];
1142
1143    {
1144        let mut back = BitMapBackend::with_buffer(&mut buffer, (1000, 1000));
1145
1146        back.draw_line((1100, 0), (1100, 999), &RED.to_rgba())
1147            .unwrap();
1148        back.draw_line((0, 1100), (999, 1100), &RED.to_rgba())
1149            .unwrap();
1150        back.draw_rect((1100, 0), (1100, 999), &RED.to_rgba(), true)
1151            .unwrap();
1152    }
1153
1154    for x in 0..1000 {
1155        for y in 0..1000 {
1156            assert_eq!(buffer[(y * 1000 + x) as usize * 3 + 0], 0);
1157            assert_eq!(buffer[(y * 1000 + x) as usize * 3 + 1], 0);
1158            assert_eq!(buffer[(y * 1000 + x) as usize * 3 + 2], 0);
1159        }
1160    }
1161}
1162
1163#[cfg(test)]
1164#[test]
1165fn test_draw_line_out_of_range() {
1166    use crate::prelude::*;
1167    let mut buffer = vec![0; 1000 * 1000 * 3];
1168
1169    {
1170        let mut back = BitMapBackend::with_buffer(&mut buffer, (1000, 1000));
1171
1172        back.draw_line((-1000, -1000), (2000, 2000), &WHITE.to_rgba())
1173            .unwrap();
1174
1175        back.draw_line((999, -1000), (999, 2000), &WHITE.to_rgba())
1176            .unwrap();
1177    }
1178
1179    for x in 0..1000 {
1180        for y in 0..1000 {
1181            let expected_value = if x == y || x == 999 { 255 } else { 0 };
1182            assert_eq!(buffer[(y * 1000 + x) as usize * 3 + 0], expected_value);
1183            assert_eq!(buffer[(y * 1000 + x) as usize * 3 + 1], expected_value);
1184            assert_eq!(buffer[(y * 1000 + x) as usize * 3 + 2], expected_value);
1185        }
1186    }
1187}
1188
1189#[cfg(test)]
1190#[test]
1191fn test_bitmap_blend_large() {
1192    use crate::prelude::*;
1193    let mut buffer = vec![0; 1000 * 1000 * 3];
1194
1195    for fill_color in [RED, GREEN, BLUE].iter() {
1196        buffer.iter_mut().for_each(|x| *x = 0);
1197
1198        {
1199            let mut back = BitMapBackend::with_buffer(&mut buffer, (1000, 1000));
1200
1201            back.draw_rect((0, 0), (1000, 1000), &WHITE.mix(0.1), true)
1202                .unwrap(); // should be (24, 24, 24)
1203            back.draw_rect((0, 0), (100, 100), &fill_color.mix(0.5), true)
1204                .unwrap(); // should be (139, 24, 24)
1205        }
1206
1207        for x in 0..1000 {
1208            for y in 0..1000 {
1209                let expected_value = if x <= 100 && y <= 100 {
1210                    let (r, g, b) = fill_color.to_rgba().rgb();
1211                    (
1212                        if r > 0 { 139 } else { 12 },
1213                        if g > 0 { 139 } else { 12 },
1214                        if b > 0 { 139 } else { 12 },
1215                    )
1216                } else {
1217                    (24, 24, 24)
1218                };
1219                assert_eq!(buffer[(y * 1000 + x) as usize * 3 + 0], expected_value.0);
1220                assert_eq!(buffer[(y * 1000 + x) as usize * 3 + 1], expected_value.1);
1221                assert_eq!(buffer[(y * 1000 + x) as usize * 3 + 2], expected_value.2);
1222            }
1223        }
1224    }
1225}
1226
1227#[cfg(test)]
1228#[test]
1229fn test_bitmap_bgrx_pixel_format() {
1230    use crate::drawing::bitmap_pixel::BGRXPixel;
1231    use crate::prelude::*;
1232    let mut rgb_buffer = vec![0; 1000 * 1000 * 3];
1233    let mut bgrx_buffer = vec![0; 1000 * 1000 * 4];
1234
1235    {
1236        let mut rgb_back = BitMapBackend::with_buffer(&mut rgb_buffer, (1000, 1000));
1237        let mut bgrx_back =
1238            BitMapBackend::<BGRXPixel>::with_buffer_and_format(&mut bgrx_buffer, (1000, 1000))
1239                .unwrap();
1240
1241        rgb_back
1242            .draw_rect((0, 0), (1000, 1000), &BLACK, true)
1243            .unwrap();
1244        bgrx_back
1245            .draw_rect((0, 0), (1000, 1000), &BLACK, true)
1246            .unwrap();
1247
1248        rgb_back
1249            .draw_rect(
1250                (0, 0),
1251                (1000, 1000),
1252                &RGBColor(0xaa, 0xbb, 0xcc).mix(0.85),
1253                true,
1254            )
1255            .unwrap();
1256        bgrx_back
1257            .draw_rect(
1258                (0, 0),
1259                (1000, 1000),
1260                &RGBColor(0xaa, 0xbb, 0xcc).mix(0.85),
1261                true,
1262            )
1263            .unwrap();
1264
1265        rgb_back
1266            .draw_rect((0, 0), (1000, 1000), &RED.mix(0.85), true)
1267            .unwrap();
1268        bgrx_back
1269            .draw_rect((0, 0), (1000, 1000), &RED.mix(0.85), true)
1270            .unwrap();
1271
1272        rgb_back.draw_circle((300, 300), 100, &GREEN, true).unwrap();
1273        bgrx_back
1274            .draw_circle((300, 300), 100, &GREEN, true)
1275            .unwrap();
1276
1277        rgb_back.draw_rect((10, 10), (50, 50), &BLUE, true).unwrap();
1278        bgrx_back
1279            .draw_rect((10, 10), (50, 50), &BLUE, true)
1280            .unwrap();
1281
1282        rgb_back
1283            .draw_rect((10, 10), (50, 50), &WHITE, true)
1284            .unwrap();
1285        bgrx_back
1286            .draw_rect((10, 10), (50, 50), &WHITE, true)
1287            .unwrap();
1288
1289        rgb_back
1290            .draw_rect((10, 10), (15, 50), &YELLOW, true)
1291            .unwrap();
1292        bgrx_back
1293            .draw_rect((10, 10), (15, 50), &YELLOW, true)
1294            .unwrap();
1295    }
1296
1297    for x in 0..1000 {
1298        for y in 0..1000 {
1299            assert!(
1300                (rgb_buffer[y * 3000 + x * 3 + 0] as i32
1301                    - bgrx_buffer[y * 4000 + x * 4 + 2] as i32)
1302                    .abs()
1303                    <= 1
1304            );
1305            assert!(
1306                (rgb_buffer[y * 3000 + x * 3 + 1] as i32
1307                    - bgrx_buffer[y * 4000 + x * 4 + 1] as i32)
1308                    .abs()
1309                    <= 1
1310            );
1311            assert!(
1312                (rgb_buffer[y * 3000 + x * 3 + 2] as i32
1313                    - bgrx_buffer[y * 4000 + x * 4 + 0] as i32)
1314                    .abs()
1315                    <= 1
1316            );
1317        }
1318    }
1319}
1320
1321#[cfg(test)]
1322#[test]
1323fn test_bitmap_blit() {
1324    let src_bitmap: Vec<u8> = (0..100)
1325        .map(|y| (0..300).map(move |x| ((x * y) % 253) as u8))
1326        .flatten()
1327        .collect();
1328
1329    use crate::prelude::*;
1330    let mut buffer = vec![0; 1000 * 1000 * 3];
1331
1332    {
1333        let mut back = BitMapBackend::with_buffer(&mut buffer, (1000, 1000));
1334        back.blit_bitmap((500, 500), (100, 100), &src_bitmap[..])
1335            .unwrap();
1336    }
1337
1338    for y in 0..1000 {
1339        for x in 0..1000 {
1340            if x >= 500 && x < 600 && y >= 500 && y < 600 {
1341                let lx = x - 500;
1342                let ly = y - 500;
1343                assert_eq!(buffer[y * 3000 + x * 3 + 0] as usize, (ly * lx * 3) % 253);
1344                assert_eq!(
1345                    buffer[y * 3000 + x * 3 + 1] as usize,
1346                    (ly * (lx * 3 + 1)) % 253
1347                );
1348                assert_eq!(
1349                    buffer[y * 3000 + x * 3 + 2] as usize,
1350                    (ly * (lx * 3 + 2)) % 253
1351                );
1352            } else {
1353                assert_eq!(buffer[y * 3000 + x * 3 + 0], 0);
1354                assert_eq!(buffer[y * 3000 + x * 3 + 1], 0);
1355                assert_eq!(buffer[y * 3000 + x * 3 + 2], 0);
1356            }
1357        }
1358    }
1359}
1360
1361#[cfg(all(not(target_arch = "wasm32"), feature = "image"))]
1362#[cfg(test)]
1363mod test {
1364    use crate::prelude::*;
1365    use crate::style::text_anchor::{HPos, Pos, VPos};
1366    use image::{ImageBuffer, Rgb};
1367    use std::fs;
1368    use std::path::Path;
1369
1370    static DST_DIR: &str = "target/test/bitmap";
1371
1372    fn checked_save_file(name: &str, content: &[u8], w: u32, h: u32) {
1373        /*
1374          Please use the PNG file to manually verify the results.
1375        */
1376        assert!(content.iter().any(|x| *x != 0));
1377        fs::create_dir_all(DST_DIR).unwrap();
1378        let file_name = format!("{}.png", name);
1379        let file_path = Path::new(DST_DIR).join(file_name);
1380        println!("{:?} created", file_path);
1381        let img = ImageBuffer::<Rgb<u8>, &[u8]>::from_raw(w, h, content).unwrap();
1382        img.save(&file_path).unwrap();
1383    }
1384
1385    fn draw_mesh_with_custom_ticks(tick_size: i32, test_name: &str) {
1386        let (width, height) = (500, 500);
1387        let mut buffer = vec![0; (width * height * 3) as usize];
1388        {
1389            let root = BitMapBackend::with_buffer(&mut buffer, (width, height)).into_drawing_area();
1390            root.fill(&WHITE).unwrap();
1391
1392            let mut chart = ChartBuilder::on(&root)
1393                .caption("This is a test", ("sans-serif", 20))
1394                .set_all_label_area_size(40)
1395                .build_ranged(0..10, 0..10)
1396                .unwrap();
1397
1398            chart
1399                .configure_mesh()
1400                .set_all_tick_mark_size(tick_size)
1401                .draw()
1402                .unwrap();
1403        }
1404        checked_save_file(test_name, &buffer, width, height);
1405    }
1406
1407    #[test]
1408    fn test_draw_mesh_no_ticks() {
1409        draw_mesh_with_custom_ticks(0, "test_draw_mesh_no_ticks");
1410    }
1411
1412    #[test]
1413    fn test_draw_mesh_negative_ticks() {
1414        draw_mesh_with_custom_ticks(-10, "test_draw_mesh_negative_ticks");
1415    }
1416
1417    #[test]
1418    fn test_text_draw() {
1419        let (width, height) = (1500, 800);
1420        let mut buffer = vec![0; (width * height * 3) as usize];
1421        {
1422            let root = BitMapBackend::with_buffer(&mut buffer, (width, height)).into_drawing_area();
1423            root.fill(&WHITE).unwrap();
1424            let root = root
1425                .titled("Image Title", ("sans-serif", 60).into_font())
1426                .unwrap();
1427
1428            let mut chart = ChartBuilder::on(&root)
1429                .caption("All anchor point positions", ("sans-serif", 20))
1430                .set_all_label_area_size(40)
1431                .build_ranged(0..100, 0..50)
1432                .unwrap();
1433
1434            chart
1435                .configure_mesh()
1436                .disable_x_mesh()
1437                .disable_y_mesh()
1438                .x_desc("X Axis")
1439                .y_desc("Y Axis")
1440                .draw()
1441                .unwrap();
1442
1443            let ((x1, y1), (x2, y2), (x3, y3)) = ((-30, 30), (0, -30), (30, 30));
1444
1445            for (dy, trans) in [
1446                FontTransform::None,
1447                FontTransform::Rotate90,
1448                FontTransform::Rotate180,
1449                FontTransform::Rotate270,
1450            ]
1451            .iter()
1452            .enumerate()
1453            {
1454                for (dx1, h_pos) in [HPos::Left, HPos::Right, HPos::Center].iter().enumerate() {
1455                    for (dx2, v_pos) in [VPos::Top, VPos::Center, VPos::Bottom].iter().enumerate() {
1456                        let x = 150_i32 + (dx1 as i32 * 3 + dx2 as i32) * 150;
1457                        let y = 120 + dy as i32 * 150;
1458                        let draw = |x, y, text| {
1459                            root.draw(&Circle::new((x, y), 3, &BLACK.mix(0.5))).unwrap();
1460                            let style = TextStyle::from(("sans-serif", 20).into_font())
1461                                .pos(Pos::new(*h_pos, *v_pos))
1462                                .transform(trans.clone());
1463                            root.draw_text(text, &style, (x, y)).unwrap();
1464                        };
1465                        draw(x + x1, y + y1, "dood");
1466                        draw(x + x2, y + y2, "dog");
1467                        draw(x + x3, y + y3, "goog");
1468                    }
1469                }
1470            }
1471        }
1472        checked_save_file("test_text_draw", &buffer, width, height);
1473    }
1474
1475    #[test]
1476    fn test_text_clipping() {
1477        let (width, height) = (500_i32, 500_i32);
1478        let mut buffer = vec![0; (width * height * 3) as usize];
1479        {
1480            let root = BitMapBackend::with_buffer(&mut buffer, (width as u32, height as u32))
1481                .into_drawing_area();
1482            root.fill(&WHITE).unwrap();
1483
1484            let style = TextStyle::from(("sans-serif", 20).into_font())
1485                .pos(Pos::new(HPos::Center, VPos::Center));
1486            root.draw_text("TOP LEFT", &style, (0, 0)).unwrap();
1487            root.draw_text("TOP CENTER", &style, (width / 2, 0))
1488                .unwrap();
1489            root.draw_text("TOP RIGHT", &style, (width, 0)).unwrap();
1490
1491            root.draw_text("MIDDLE LEFT", &style, (0, height / 2))
1492                .unwrap();
1493            root.draw_text("MIDDLE RIGHT", &style, (width, height / 2))
1494                .unwrap();
1495
1496            root.draw_text("BOTTOM LEFT", &style, (0, height)).unwrap();
1497            root.draw_text("BOTTOM CENTER", &style, (width / 2, height))
1498                .unwrap();
1499            root.draw_text("BOTTOM RIGHT", &style, (width, height))
1500                .unwrap();
1501        }
1502        checked_save_file("test_text_clipping", &buffer, width as u32, height as u32);
1503    }
1504
1505    #[test]
1506    fn test_series_labels() {
1507        let (width, height) = (500, 500);
1508        let mut buffer = vec![0; (width * height * 3) as usize];
1509        {
1510            let root = BitMapBackend::with_buffer(&mut buffer, (width, height)).into_drawing_area();
1511            root.fill(&WHITE).unwrap();
1512
1513            let mut chart = ChartBuilder::on(&root)
1514                .caption("All series label positions", ("sans-serif", 20))
1515                .set_all_label_area_size(40)
1516                .build_ranged(0..50, 0..50)
1517                .unwrap();
1518
1519            chart
1520                .configure_mesh()
1521                .disable_x_mesh()
1522                .disable_y_mesh()
1523                .draw()
1524                .unwrap();
1525
1526            chart
1527                .draw_series(std::iter::once(Circle::new((5, 15), 5, &RED)))
1528                .expect("Drawing error")
1529                .label("Series 1")
1530                .legend(|(x, y)| Circle::new((x, y), 3, RED.filled()));
1531
1532            chart
1533                .draw_series(std::iter::once(Circle::new((5, 15), 10, &BLUE)))
1534                .expect("Drawing error")
1535                .label("Series 2")
1536                .legend(|(x, y)| Circle::new((x, y), 3, BLUE.filled()));
1537
1538            for pos in vec![
1539                SeriesLabelPosition::UpperLeft,
1540                SeriesLabelPosition::MiddleLeft,
1541                SeriesLabelPosition::LowerLeft,
1542                SeriesLabelPosition::UpperMiddle,
1543                SeriesLabelPosition::MiddleMiddle,
1544                SeriesLabelPosition::LowerMiddle,
1545                SeriesLabelPosition::UpperRight,
1546                SeriesLabelPosition::MiddleRight,
1547                SeriesLabelPosition::LowerRight,
1548                SeriesLabelPosition::Coordinate(70, 70),
1549            ]
1550            .into_iter()
1551            {
1552                chart
1553                    .configure_series_labels()
1554                    .border_style(&BLACK.mix(0.5))
1555                    .position(pos)
1556                    .draw()
1557                    .expect("Drawing error");
1558            }
1559        }
1560        checked_save_file("test_series_labels", &buffer, width, height);
1561    }
1562
1563    #[test]
1564    fn test_draw_pixel_alphas() {
1565        let (width, height) = (100_i32, 100_i32);
1566        let mut buffer = vec![0; (width * height * 3) as usize];
1567        {
1568            let root = BitMapBackend::with_buffer(&mut buffer, (width as u32, height as u32))
1569                .into_drawing_area();
1570            root.fill(&WHITE).unwrap();
1571            for i in -20..20 {
1572                let alpha = i as f64 * 0.1;
1573                root.draw_pixel((50 + i, 50 + i), &BLACK.mix(alpha))
1574                    .unwrap();
1575            }
1576        }
1577        checked_save_file(
1578            "test_draw_pixel_alphas",
1579            &buffer,
1580            width as u32,
1581            height as u32,
1582        );
1583    }
1584}