1
1
use crate :: drawing:: backend:: { BackendCoord , BackendStyle , DrawingBackend , DrawingErrorKind } ;
2
2
use crate :: style:: { Color , RGBAColor } ;
3
3
4
- use image:: { ImageBuffer , ImageError , Rgb , RgbImage } ;
4
+ use image:: { ImageBuffer , ImageError , Rgb } ;
5
5
6
6
use std:: path:: Path ;
7
7
@@ -11,35 +11,6 @@ fn blend(prev: &mut u8, new: u8, a: f64) {
11
11
* prev = ( ( f64:: from ( * prev) ) * ( 1.0 - a) + a * f64:: from ( new) ) . min ( 255.0 ) as u8 ;
12
12
}
13
13
14
- /// Macro implementation for drawing pixels, since a generic implementation would have been
15
- /// much more unwieldy.
16
- macro_rules! draw_pixel {
17
- ( $img: expr, $point: expr, $color: expr) => { {
18
- if $point. 0 as u32 >= $img. width( )
19
- || $point. 0 < 0
20
- || $point. 1 as u32 >= $img. height( )
21
- || $point. 1 < 0
22
- {
23
- return Ok ( ( ) ) ;
24
- }
25
-
26
- let alpha = $color. alpha( ) ;
27
- let rgb = $color. rgb( ) ;
28
-
29
- if alpha >= 1.0 {
30
- $img. put_pixel( $point. 0 as u32 , $point. 1 as u32 , Rgb ( [ rgb. 0 , rgb. 1 , rgb. 2 ] ) ) ;
31
- } else {
32
- let pixel = $img. get_pixel_mut( $point. 0 as u32 , $point. 1 as u32 ) ;
33
- let new_color = [ rgb. 0 , rgb. 1 , rgb. 2 ] ;
34
-
35
- pixel. 0 . iter_mut( ) . zip( & new_color) . for_each( |( old, new) | {
36
- * old = ( f64 :: from( * old) * ( 1.0 - alpha) + f64 :: from( * new) * alpha) . min( 255.0 ) as u8 ;
37
- } ) ;
38
- }
39
- Ok ( ( ) )
40
- } } ;
41
- }
42
-
43
14
#[ cfg( feature = "gif" ) ]
44
15
mod gif_support {
45
16
use super :: * ;
@@ -76,16 +47,9 @@ mod gif_support {
76
47
} )
77
48
}
78
49
79
- pub ( super ) fn flush_frame ( & mut self , img : & mut RgbImage ) -> Result < ( ) , ImageError > {
80
- let mut new_img = RgbImage :: new ( self . width , self . height ) ;
81
- std:: mem:: swap ( & mut new_img, img) ;
82
-
83
- let mut frame = GifFrame :: from_rgb_speed (
84
- self . width as u16 ,
85
- self . height as u16 ,
86
- & new_img. into_raw ( ) ,
87
- 10 ,
88
- ) ;
50
+ pub ( super ) fn flush_frame ( & mut self , buffer : & [ u8 ] ) -> Result < ( ) , ImageError > {
51
+ let mut frame =
52
+ GifFrame :: from_rgb_speed ( self . width as u16 , self . height as u16 , buffer, 10 ) ;
89
53
90
54
frame. delay = self . delay as u16 ;
91
55
@@ -97,26 +61,48 @@ mod gif_support {
97
61
}
98
62
99
63
enum Target < ' a > {
100
- File ( & ' a Path , RgbImage ) ,
101
- Buffer ( BorrowedImage < ' a > ) ,
64
+ File ( & ' a Path ) ,
65
+ Buffer ,
102
66
#[ cfg( feature = "gif" ) ]
103
- Gif ( Box < gif_support:: GifFile > , RgbImage ) ,
67
+ Gif ( Box < gif_support:: GifFile > ) ,
68
+ }
69
+
70
+ enum Buffer < ' a > {
71
+ Owned ( Vec < u8 > ) ,
72
+ Borrowed ( & ' a mut [ u8 ] ) ,
73
+ }
74
+
75
+ impl < ' a > Buffer < ' a > {
76
+ fn borrow_buffer ( & mut self ) -> & mut [ u8 ] {
77
+ match self {
78
+ Buffer :: Owned ( buf) => & mut buf[ ..] ,
79
+ Buffer :: Borrowed ( buf) => * buf,
80
+ }
81
+ }
104
82
}
105
83
106
84
/// The backend that drawing a bitmap
107
85
pub struct BitMapBackend < ' a > {
108
86
/// The path to the image
109
87
target : Target < ' a > ,
110
88
89
+ /// The size of the image
90
+ size : ( u32 , u32 ) ,
91
+
92
+ /// The data buffer of the image
93
+ buffer : Buffer < ' a > ,
94
+
111
95
/// Flag indicates if the bitmap has been saved
112
96
saved : bool ,
113
97
}
114
98
115
99
impl < ' a > BitMapBackend < ' a > {
116
100
/// Create a new bitmap backend
117
- pub fn new < T : AsRef < Path > + ?Sized > ( path : & ' a T , dimension : ( u32 , u32 ) ) -> Self {
101
+ pub fn new < T : AsRef < Path > + ?Sized > ( path : & ' a T , ( w , h ) : ( u32 , u32 ) ) -> Self {
118
102
Self {
119
- target : Target :: File ( path. as_ref ( ) , RgbImage :: new ( dimension. 0 , dimension. 1 ) ) ,
103
+ target : Target :: File ( path. as_ref ( ) ) ,
104
+ size : ( w, h) ,
105
+ buffer : Buffer :: Owned ( vec ! [ 0 ; ( 3 * w * h) as usize ] ) ,
120
106
saved : false ,
121
107
}
122
108
}
@@ -133,14 +119,17 @@ impl<'a> BitMapBackend<'a> {
133
119
#[ cfg( feature = "gif" ) ]
134
120
pub fn gif < T : AsRef < Path > > (
135
121
path : T ,
136
- dimension : ( u32 , u32 ) ,
122
+ ( w , h ) : ( u32 , u32 ) ,
137
123
frame_delay : u32 ,
138
124
) -> Result < Self , ImageError > {
139
125
Ok ( Self {
140
- target : Target :: Gif (
141
- Box :: new ( gif_support:: GifFile :: new ( path, dimension, frame_delay) ?) ,
142
- RgbImage :: new ( dimension. 0 , dimension. 1 ) ,
143
- ) ,
126
+ target : Target :: Gif ( Box :: new ( gif_support:: GifFile :: new (
127
+ path,
128
+ ( w, h) ,
129
+ frame_delay,
130
+ ) ?) ) ,
131
+ size : ( w, h) ,
132
+ buffer : Buffer :: Owned ( vec ! [ 0 ; ( 3 * w * h) as usize ] ) ,
144
133
saved : false ,
145
134
} )
146
135
}
@@ -152,23 +141,27 @@ impl<'a> BitMapBackend<'a> {
152
141
///
153
142
/// - `buf`: The buffer to operate
154
143
/// - `dimension`: The size of the image in pixels
155
- pub fn with_buffer ( buf : & ' a mut [ u8 ] , dimension : ( u32 , u32 ) ) -> Self {
144
+ pub fn with_buffer ( buf : & ' a mut [ u8 ] , ( w, h) : ( u32 , u32 ) ) -> Self {
145
+ if ( w * h * 3 ) as usize > buf. len ( ) {
146
+ // TODO: This doesn't deserve a panic.
147
+ panic ! (
148
+ "Wrong image size: H = {}, W = {}, BufSize = {}" ,
149
+ w,
150
+ h,
151
+ buf. len( )
152
+ ) ;
153
+ }
154
+
156
155
Self {
157
- target : Target :: Buffer (
158
- BorrowedImage :: from_raw ( dimension. 0 , dimension. 1 , buf)
159
- . expect ( "Buffer size must match dimensions (w * h * 3)." ) ,
160
- ) ,
156
+ target : Target :: Buffer ,
157
+ size : ( w, h) ,
158
+ buffer : Buffer :: Borrowed ( buf) ,
161
159
saved : false ,
162
160
}
163
161
}
164
162
165
163
fn get_raw_pixel_buffer ( & mut self ) -> & mut [ u8 ] {
166
- match & mut self . target {
167
- Target :: File ( _, img) => & mut ( * * img) [ ..] ,
168
- Target :: Buffer ( img) => & mut ( * * img) [ ..] ,
169
- #[ cfg( feature = "gif" ) ]
170
- Target :: Gif ( _, img) => & mut ( * * img) [ ..] ,
171
- }
164
+ self . buffer . borrow_buffer ( )
172
165
}
173
166
174
167
/// Split a bitmap backend vertically into several sub drawing area which allows
@@ -341,12 +334,7 @@ impl<'a> DrawingBackend for BitMapBackend<'a> {
341
334
type ErrorType = ImageError ;
342
335
343
336
fn get_size ( & self ) -> ( u32 , u32 ) {
344
- match & self . target {
345
- Target :: Buffer ( img) => ( img. width ( ) , img. height ( ) ) ,
346
- Target :: File ( _, img) => ( img. width ( ) , img. height ( ) ) ,
347
- #[ cfg( feature = "gif" ) ]
348
- Target :: Gif ( _, img) => ( img. width ( ) , img. height ( ) ) ,
349
- }
337
+ self . size
350
338
}
351
339
352
340
fn ensure_prepared ( & mut self ) -> Result < ( ) , DrawingErrorKind < ImageError > > {
@@ -355,19 +343,24 @@ impl<'a> DrawingBackend for BitMapBackend<'a> {
355
343
}
356
344
357
345
fn present ( & mut self ) -> Result < ( ) , DrawingErrorKind < ImageError > > {
346
+ let ( w, h) = self . get_size ( ) ;
358
347
match & mut self . target {
359
- Target :: File ( path, img) => {
360
- img. save ( & path)
361
- . map_err ( |x| DrawingErrorKind :: DrawingError ( ImageError :: IoError ( x) ) ) ?;
362
- self . saved = true ;
363
- Ok ( ( ) )
348
+ Target :: File ( path) => {
349
+ if let Some ( img) = BorrowedImage :: from_raw ( w, h, self . buffer . borrow_buffer ( ) ) {
350
+ img. save ( & path)
351
+ . map_err ( |x| DrawingErrorKind :: DrawingError ( ImageError :: IoError ( x) ) ) ?;
352
+ self . saved = true ;
353
+ Ok ( ( ) )
354
+ } else {
355
+ Err ( DrawingErrorKind :: DrawingError ( ImageError :: DimensionError ) )
356
+ }
364
357
}
365
- Target :: Buffer ( _ ) => Ok ( ( ) ) ,
358
+ Target :: Buffer => Ok ( ( ) ) ,
366
359
367
360
#[ cfg( feature = "gif" ) ]
368
- Target :: Gif ( target, img ) => {
361
+ Target :: Gif ( target) => {
369
362
target
370
- . flush_frame ( img )
363
+ . flush_frame ( self . buffer . borrow_buffer ( ) )
371
364
. map_err ( DrawingErrorKind :: DrawingError ) ?;
372
365
self . saved = true ;
373
366
Ok ( ( ) )
@@ -380,12 +373,35 @@ impl<'a> DrawingBackend for BitMapBackend<'a> {
380
373
point : BackendCoord ,
381
374
color : & RGBAColor ,
382
375
) -> Result < ( ) , DrawingErrorKind < ImageError > > {
383
- match & mut self . target {
384
- Target :: Buffer ( img) => draw_pixel ! ( img, point, color) ,
385
- Target :: File ( _, img) => draw_pixel ! ( img, point, color) ,
386
- #[ cfg( feature = "gif" ) ]
387
- Target :: Gif ( _, img) => draw_pixel ! ( img, point, color) ,
376
+ if point. 0 < 0 || point. 1 < 0 {
377
+ return Ok ( ( ) ) ;
388
378
}
379
+
380
+ let ( w, _) = self . get_size ( ) ;
381
+ let alpha = color. alpha ( ) ;
382
+ let rgb = color. rgb ( ) ;
383
+
384
+ let buf = self . get_raw_pixel_buffer ( ) ;
385
+
386
+ let ( x, y) = ( point. 0 as usize , point. 1 as usize ) ;
387
+ let w = w as usize ;
388
+
389
+ let base = ( y * w + x) * 3 ;
390
+
391
+ if base < buf. len ( ) {
392
+ unsafe {
393
+ if alpha >= 1.0 {
394
+ * buf. get_unchecked_mut ( base) = rgb. 0 ;
395
+ * buf. get_unchecked_mut ( base + 1 ) = rgb. 1 ;
396
+ * buf. get_unchecked_mut ( base + 2 ) = rgb. 2 ;
397
+ } else {
398
+ blend ( buf. get_unchecked_mut ( base) , rgb. 0 , alpha) ;
399
+ blend ( buf. get_unchecked_mut ( base + 1 ) , rgb. 1 , alpha) ;
400
+ blend ( buf. get_unchecked_mut ( base + 2 ) , rgb. 2 , alpha) ;
401
+ }
402
+ }
403
+ }
404
+ Ok ( ( ) )
389
405
}
390
406
391
407
fn draw_line < S : BackendStyle > (
0 commit comments