@@ -94,51 +94,61 @@ impl<'a, R: 'a + Read> ImageDecoder<'a> for GifDecoder<R> {
94
94
fn read_image ( mut self , buf : & mut [ u8 ] ) -> ImageResult < ( ) > {
95
95
assert_eq ! ( u64 :: try_from( buf. len( ) ) , Ok ( self . total_bytes( ) ) ) ;
96
96
97
- let ( f_width, f_height, left, top) ;
97
+ let frame = match self . reader . next_frame_info ( )
98
+ . map_err ( ImageError :: from_decoding) ? {
99
+ Some ( frame) => FrameInfo :: new_from_frame ( frame) ,
100
+ None => {
101
+ return Err ( ImageError :: Parameter ( ParameterError :: from_kind (
102
+ ParameterErrorKind :: NoMoreData ,
103
+ ) ) )
104
+ }
105
+ } ;
98
106
99
- if let Some ( frame) = self . reader . next_frame_info ( ) . map_err ( ImageError :: from_decoding) ? {
100
- left = u32:: from ( frame. left ) ;
101
- top = u32:: from ( frame. top ) ;
102
- f_width = u32:: from ( frame. width ) ;
103
- f_height = u32:: from ( frame. height ) ;
104
- } else {
105
- return Err ( ImageError :: Parameter (
106
- ParameterError :: from_kind ( ParameterErrorKind :: NoMoreData )
107
- ) ) ;
108
- }
107
+ let ( width, height) = self . dimensions ( ) ;
109
108
110
- self . reader . read_into_buffer ( buf) . map_err ( ImageError :: from_decoding) ?;
111
-
112
- let ( width, height) = ( u32:: from ( self . reader . width ( ) ) , u32:: from ( self . reader . height ( ) ) ) ;
113
- if ( left, top) != ( 0 , 0 ) || ( width, height) != ( f_width, f_height) {
114
- // This is somewhat of an annoying case. The image we read into `buf` doesn't take up
115
- // the whole buffer and now we need to properly insert borders. For simplicity this code
116
- // currently takes advantage of the `ImageBuffer::from_fn` function to make a second
117
- // ImageBuffer that is properly positioned, and then copies it back into `buf`.
118
- //
119
- // TODO: Implement this without any allocation.
120
-
121
- // Recover the full image
122
- let image_buffer = {
123
- // See the comments inside `<GifFrameIterator as Iterator>::next` about
124
- // the error handling of `from_raw`.
125
- let image = ImageBuffer :: from_raw ( f_width, f_height, & mut * buf) . ok_or_else (
126
- || ImageError :: Unsupported ( UnsupportedError :: from_format_and_kind (
109
+ if ( frame. left , frame. top ) == ( 0 , 0 ) && ( frame. width , frame. height ) != self . dimensions ( ) {
110
+ // If the frame matches the logical screen, directly read into it
111
+ self . reader . read_into_buffer ( buf) . map_err ( ImageError :: from_decoding) ?;
112
+ } else {
113
+ // If the frame does not match the logical screen, read into an extra buffer
114
+ // and 'insert' the frame from left/top to logical screen width/height.
115
+ let mut frame_buffer = vec ! [ 0 ; self . reader. buffer_size( ) ] ;
116
+ self . reader . read_into_buffer ( & mut frame_buffer[ ..] ) . map_err ( ImageError :: from_decoding) ?;
117
+
118
+ let frame_buffer = ImageBuffer :: from_raw ( frame. width , frame. height , frame_buffer) ;
119
+ let image_buffer = ImageBuffer :: from_raw ( width, height, buf) ;
120
+
121
+ // `buffer_size` uses wrapping arithmetics, thus might not report the
122
+ // correct storage requirement if the result does not fit in `usize`.
123
+ // `ImageBuffer::from_raw` detects overflow and reports by returning `None`.
124
+ if frame_buffer. is_none ( ) || image_buffer. is_none ( ) {
125
+ return Err ( ImageError :: Unsupported (
126
+ UnsupportedError :: from_format_and_kind (
127
127
ImageFormat :: Gif . into ( ) ,
128
- UnsupportedErrorKind :: GenericFeature ( format ! ( "Image dimensions ({}, {}) are too large" , f_width, f_height) ) ) ) ) ?;
129
-
130
- ImageBuffer :: from_fn ( width, height, |x, y| {
131
- let x = x. wrapping_sub ( left) ;
132
- let y = y. wrapping_sub ( top) ;
133
- if x < image. width ( ) && y < image. height ( ) {
134
- * image. get_pixel ( x, y)
135
- } else {
136
- Rgba ( [ 0 , 0 , 0 , 0 ] )
137
- }
138
- } )
139
- } ;
140
- buf. copy_from_slice ( & image_buffer. into_raw ( ) ) ;
128
+ UnsupportedErrorKind :: GenericFeature ( format ! (
129
+ "Image dimensions ({}, {}) are too large" ,
130
+ frame. width, frame. height
131
+ ) ) ,
132
+ ) ,
133
+ ) ) ;
134
+ }
135
+
136
+ let frame_buffer = frame_buffer. unwrap ( ) ;
137
+ let mut image_buffer = image_buffer. unwrap ( ) ;
138
+
139
+ for ( x, y, pixel) in image_buffer. enumerate_pixels_mut ( ) {
140
+ let frame_x = x. wrapping_sub ( frame. left ) ;
141
+ let frame_y = y. wrapping_sub ( frame. top ) ;
142
+
143
+ if frame_x < frame. width && frame_y < frame. height {
144
+ * pixel = * frame_buffer. get_pixel ( frame_x, frame_y) ;
145
+ } else {
146
+ // this is only necessary in case the buffer is not zeroed
147
+ * pixel = Rgba ( [ 0 , 0 , 0 , 0 ] ) ;
148
+ }
149
+ }
141
150
}
151
+
142
152
Ok ( ( ) )
143
153
}
144
154
}
@@ -152,7 +162,6 @@ struct GifFrameIterator<R: Read> {
152
162
non_disposed_frame : ImageBuffer < Rgba < u8 > , Vec < u8 > > ,
153
163
}
154
164
155
-
156
165
impl < R : Read > GifFrameIterator < R > {
157
166
fn new ( decoder : GifDecoder < R > ) -> GifFrameIterator < R > {
158
167
let ( width, height) = decoder. dimensions ( ) ;
@@ -174,32 +183,23 @@ impl<R: Read> GifFrameIterator<R> {
174
183
}
175
184
}
176
185
177
-
178
186
impl < R : Read > Iterator for GifFrameIterator < R > {
179
187
type Item = ImageResult < animation:: Frame > ;
180
188
181
189
fn next ( & mut self ) -> Option < ImageResult < animation:: Frame > > {
182
190
// begin looping over each frame
183
- let ( left, top, delay, dispose, f_width, f_height) ;
184
191
185
- match self . reader . next_frame_info ( ) {
192
+ let frame = match self . reader . next_frame_info ( ) {
186
193
Ok ( frame_info) => {
187
194
if let Some ( frame) = frame_info {
188
- left = u32:: from ( frame. left ) ;
189
- top = u32:: from ( frame. top ) ;
190
- f_width = u32:: from ( frame. width ) ;
191
- f_height = u32:: from ( frame. height ) ;
192
-
193
- // frame.delay is in units of 10ms so frame.delay*10 is in ms
194
- delay = Ratio :: new ( u32:: from ( frame. delay ) * 10 , 1 ) ;
195
- dispose = frame. dispose ;
195
+ FrameInfo :: new_from_frame ( frame)
196
196
} else {
197
197
// no more frames
198
198
return None ;
199
199
}
200
- } ,
200
+ }
201
201
Err ( err) => return Some ( Err ( ImageError :: from_decoding ( err) ) ) ,
202
- }
202
+ } ;
203
203
204
204
let mut vec = vec ! [ 0 ; self . reader. buffer_size( ) ] ;
205
205
if let Err ( err) = self . reader . read_into_buffer ( & mut vec) {
@@ -211,13 +211,18 @@ impl<R: Read> Iterator for GifFrameIterator<R> {
211
211
// correct storage requirement if the result does not fit in `usize`.
212
212
// on the other hand, `ImageBuffer::from_raw` detects overflow and
213
213
// reports by returning `None`.
214
- let mut frame_buffer = match ImageBuffer :: from_raw ( f_width , f_height , vec) {
214
+ let mut frame_buffer = match ImageBuffer :: from_raw ( frame . width , frame . height , vec) {
215
215
Some ( frame_buffer) => frame_buffer,
216
216
None => {
217
- return Some ( Err ( ImageError :: Unsupported ( UnsupportedError :: from_format_and_kind (
218
- ImageFormat :: Gif . into ( ) ,
219
- UnsupportedErrorKind :: GenericFeature ( format ! ( "Image dimensions ({}, {}) are too large" , f_width, f_height) ) ,
220
- ) ) ) )
217
+ return Some ( Err ( ImageError :: Unsupported (
218
+ UnsupportedError :: from_format_and_kind (
219
+ ImageFormat :: Gif . into ( ) ,
220
+ UnsupportedErrorKind :: GenericFeature ( format ! (
221
+ "Image dimensions ({}, {}) are too large" ,
222
+ frame. width, frame. height
223
+ ) ) ,
224
+ ) ,
225
+ ) ) )
221
226
}
222
227
} ;
223
228
@@ -253,22 +258,22 @@ impl<R: Read> Iterator for GifFrameIterator<R> {
253
258
// if `frame_buffer`'s frame exactly matches the entire image, then
254
259
// use it directly, else create a new buffer to hold the composited
255
260
// image.
256
- let image_buffer = if ( left, top) == ( 0 , 0 )
261
+ let image_buffer = if ( frame . left , frame . top ) == ( 0 , 0 )
257
262
&& ( self . width , self . height ) == frame_buffer. dimensions ( ) {
258
263
for ( x, y, pixel) in frame_buffer. enumerate_pixels_mut ( ) {
259
264
let previous_pixel = self . non_disposed_frame . get_pixel_mut ( x, y) ;
260
- blend_and_dispose_pixel ( dispose , previous_pixel, pixel) ;
265
+ blend_and_dispose_pixel ( frame . disposal_method , previous_pixel, pixel) ;
261
266
}
262
267
frame_buffer
263
268
} else {
264
269
ImageBuffer :: from_fn ( self . width , self . height , |x, y| {
265
- let frame_x = x. wrapping_sub ( left) ;
266
- let frame_y = y. wrapping_sub ( top) ;
270
+ let frame_x = x. wrapping_sub ( frame . left ) ;
271
+ let frame_y = y. wrapping_sub ( frame . top ) ;
267
272
let previous_pixel = self . non_disposed_frame . get_pixel_mut ( x, y) ;
268
273
269
274
if frame_x < frame_buffer. width ( ) && frame_y < frame_buffer. height ( ) {
270
275
let mut pixel = * frame_buffer. get_pixel ( frame_x, frame_y) ;
271
- blend_and_dispose_pixel ( dispose , previous_pixel, & mut pixel) ;
276
+ blend_and_dispose_pixel ( frame . disposal_method , previous_pixel, & mut pixel) ;
272
277
pixel
273
278
} else {
274
279
// out of bounds, return pixel from previous frame
@@ -278,7 +283,7 @@ impl<R: Read> Iterator for GifFrameIterator<R> {
278
283
} ;
279
284
280
285
Some ( Ok ( animation:: Frame :: from_parts (
281
- image_buffer, 0 , 0 , animation :: Delay :: from_ratio ( delay) ,
286
+ image_buffer, 0 , 0 , frame . delay ,
282
287
) ) )
283
288
}
284
289
}
@@ -289,6 +294,29 @@ impl<'a, R: Read + 'a> AnimationDecoder<'a> for GifDecoder<R> {
289
294
}
290
295
}
291
296
297
+ struct FrameInfo {
298
+ left : u32 ,
299
+ top : u32 ,
300
+ width : u32 ,
301
+ height : u32 ,
302
+ disposal_method : DisposalMethod ,
303
+ delay : animation:: Delay ,
304
+ }
305
+
306
+ impl FrameInfo {
307
+ fn new_from_frame ( frame : & Frame ) -> FrameInfo {
308
+ FrameInfo {
309
+ left : u32:: from ( frame. left ) ,
310
+ top : u32:: from ( frame. top ) ,
311
+ width : u32:: from ( frame. width ) ,
312
+ height : u32:: from ( frame. height ) ,
313
+ disposal_method : frame. dispose ,
314
+ // frame.delay is in units of 10ms so frame.delay*10 is in ms
315
+ delay : animation:: Delay :: from_ratio ( Ratio :: new ( u32:: from ( frame. delay ) * 10 , 1 ) ) ,
316
+ }
317
+ }
318
+ }
319
+
292
320
/// Number of repetitions for a GIF animation
293
321
#[ derive( Clone , Copy ) ]
294
322
pub enum Repeat {
@@ -477,3 +505,26 @@ impl ImageError {
477
505
}
478
506
}
479
507
}
508
+
509
+ #[ cfg( test) ]
510
+ mod test {
511
+ use super :: * ;
512
+
513
+ #[ test]
514
+ fn frames_exceeding_logical_screen_size ( ) {
515
+ // This is a gif with 10x10 logical screen, but a 16x16 frame + 6px offset inside.
516
+ let data = vec ! [
517
+ 0x47 , 0x49 , 0x46 , 0x38 , 0x39 , 0x61 , 0x0A , 0x00 , 0x0A , 0x00 , 0xF0 , 0x00 , 0x00 , 0x00 ,
518
+ 0x00 , 0x00 , 0x0E , 0xFF , 0x1F , 0x21 , 0xF9 , 0x04 , 0x09 , 0x64 , 0x00 , 0x00 , 0x00 , 0x2C ,
519
+ 0x06 , 0x00 , 0x06 , 0x00 , 0x10 , 0x00 , 0x10 , 0x00 , 0x00 , 0x02 , 0x23 , 0x84 , 0x8F , 0xA9 ,
520
+ 0xBB , 0xE1 , 0xE8 , 0x42 , 0x8A , 0x0F , 0x50 , 0x79 , 0xAE , 0xD1 , 0xF9 , 0x7A , 0xE8 , 0x71 ,
521
+ 0x5B , 0x48 , 0x81 , 0x64 , 0xD5 , 0x91 , 0xCA , 0x89 , 0x4D , 0x21 , 0x63 , 0x89 , 0x4C , 0x09 ,
522
+ 0x77 , 0xF5 , 0x6D , 0x14 , 0x00 , 0x3B ,
523
+ ] ;
524
+
525
+ let decoder = GifDecoder :: new ( Cursor :: new ( data) ) . unwrap ( ) ;
526
+ let mut buf = vec ! [ 0u8 ; decoder. total_bytes( ) as usize ] ;
527
+
528
+ assert ! ( decoder. read_image( & mut buf) . is_ok( ) ) ;
529
+ }
530
+ }
0 commit comments