@@ -50,7 +50,9 @@ static struct {
50
50
uint8_t * (* WebPDecodeRGBInto ) (const uint8_t * data , size_t data_size , uint8_t * output_buffer , size_t output_buffer_size , int output_stride );
51
51
uint8_t * (* WebPDecodeRGBAInto ) (const uint8_t * data , size_t data_size , uint8_t * output_buffer , size_t output_buffer_size , int output_stride );
52
52
WebPDemuxer * (* WebPDemuxInternal )(const WebPData * data , int allow_partial , WebPDemuxState * state , int version );
53
- int (* WebPDemuxGetFrame )(const WebPDemuxer * dmux , int frame_number , WebPIterator * iter );
53
+ int (* WebPDemuxGetFrame )(const WebPDemuxer * dmux , int frame_number , WebPIterator * iter );
54
+ int (* WebPDemuxNextFrame )(WebPIterator * iter );
55
+ void (* WebPDemuxReleaseIterator )(WebPIterator * iter );
54
56
uint32_t (* WebPDemuxGetI )(const WebPDemuxer * dmux , WebPFormatFeature feature );
55
57
void (* WebPDemuxDelete )(WebPDemuxer * dmux );
56
58
} lib ;
@@ -92,7 +94,9 @@ static bool IMG_InitWEBP(void)
92
94
FUNCTION_LOADER_LIBWEBP (WebPDecodeRGBInto , uint8_t * (* ) (const uint8_t * data , size_t data_size , uint8_t * output_buffer , size_t output_buffer_size , int output_stride ))
93
95
FUNCTION_LOADER_LIBWEBP (WebPDecodeRGBAInto , uint8_t * (* ) (const uint8_t * data , size_t data_size , uint8_t * output_buffer , size_t output_buffer_size , int output_stride ))
94
96
FUNCTION_LOADER_LIBWEBPDEMUX (WebPDemuxInternal , WebPDemuxer * (* )(const WebPData * , int , WebPDemuxState * , int ))
95
- FUNCTION_LOADER_LIBWEBPDEMUX (WebPDemuxGetFrame , int (* )(const WebPDemuxer * dmux , int frame_number , WebPIterator * iter ))
97
+ FUNCTION_LOADER_LIBWEBPDEMUX (WebPDemuxGetFrame , int (* )(const WebPDemuxer * dmux , int frame_number , WebPIterator * iter ))
98
+ FUNCTION_LOADER_LIBWEBPDEMUX (WebPDemuxNextFrame , int (* )(WebPIterator * iter ))
99
+ FUNCTION_LOADER_LIBWEBPDEMUX (WebPDemuxReleaseIterator , void (* )(WebPIterator * iter ))
96
100
FUNCTION_LOADER_LIBWEBPDEMUX (WebPDemuxGetI , uint32_t (* )(const WebPDemuxer * dmux , WebPFormatFeature feature ))
97
101
FUNCTION_LOADER_LIBWEBPDEMUX (WebPDemuxDelete , void (* )(WebPDemuxer * dmux ))
98
102
}
@@ -266,16 +270,16 @@ IMG_Animation *IMG_LoadWEBPAnimation_IO(SDL_IOStream *src)
266
270
{
267
271
Sint64 start ;
268
272
const char * error = NULL ;
269
- Uint32 format ;
270
273
WebPBitstreamFeatures features ;
271
- struct WebPDemuxer * dmuxer = NULL ;
274
+ struct WebPDemuxer * demuxer = NULL ;
272
275
WebPIterator iter ;
273
276
IMG_Animation * anim = NULL ;
274
277
size_t raw_data_size ;
275
278
uint8_t * raw_data = NULL ;
276
- uint8_t * ret ;
277
- int frame_idx ;
278
279
WebPData wd ;
280
+ uint32_t bgcolor ;
281
+ SDL_Surface * canvas = NULL ;
282
+ WebPMuxAnimDispose dispose_method = WEBP_MUX_DISPOSE_BACKGROUND ;
279
283
280
284
if (!src ) {
281
285
/* The error message has been set in SDL_IOFromFile */
@@ -296,79 +300,119 @@ IMG_Animation *IMG_LoadWEBPAnimation_IO(SDL_IOStream *src)
296
300
297
301
raw_data = (uint8_t * ) SDL_malloc (raw_data_size );
298
302
if (raw_data == NULL ) {
299
- error = "Failed to allocate enough buffer for WEBP Animation" ;
300
303
goto error ;
301
304
}
302
305
303
306
if (SDL_ReadIO (src , raw_data , raw_data_size ) != raw_data_size ) {
304
- error = "Failed to read WEBP Animation" ;
305
307
goto error ;
306
308
}
307
309
308
310
if (lib .WebPGetFeaturesInternal (raw_data , raw_data_size , & features , WEBP_DECODER_ABI_VERSION ) != VP8_STATUS_OK ) {
309
- error = "WebPGetFeatures has failed" ;
311
+ error = "WebPGetFeatures() failed" ;
310
312
goto error ;
311
313
}
312
314
313
- if (features .has_alpha ) {
314
- format = SDL_PIXELFORMAT_RGBA32 ;
315
- } else {
316
- format = SDL_PIXELFORMAT_RGB24 ;
317
- }
318
-
319
315
wd .size = raw_data_size ;
320
316
wd .bytes = raw_data ;
321
- dmuxer = lib .WebPDemuxInternal (& wd , 0 , NULL , WEBP_DEMUX_ABI_VERSION );
322
- anim = (IMG_Animation * )SDL_malloc (sizeof (IMG_Animation ));
317
+ demuxer = lib .WebPDemuxInternal (& wd , 0 , NULL , WEBP_DEMUX_ABI_VERSION );
318
+ if (!demuxer ) {
319
+ error = "WebPDemux() failed" ;
320
+ goto error ;
321
+ }
322
+
323
+ anim = (IMG_Animation * )SDL_calloc (1 , sizeof (* anim ));
324
+ if (!anim ) {
325
+ goto error ;
326
+ }
323
327
anim -> w = features .width ;
324
328
anim -> h = features .height ;
325
- anim -> count = lib .WebPDemuxGetI (dmuxer , WEBP_FF_FRAME_COUNT );
329
+ anim -> count = lib .WebPDemuxGetI (demuxer , WEBP_FF_FRAME_COUNT );
326
330
anim -> frames = (SDL_Surface * * )SDL_calloc (anim -> count , sizeof (* anim -> frames ));
327
331
anim -> delays = (int * )SDL_calloc (anim -> count , sizeof (* anim -> delays ));
328
- for (frame_idx = 0 ; frame_idx < (anim -> count ); frame_idx ++ ) {
329
- SDL_Surface * curr ;
330
- if (lib .WebPDemuxGetFrame (dmuxer , frame_idx , & iter ) == 0 ) {
331
- break ;
332
- }
333
- curr = SDL_CreateSurface (features .width , features .height , format );
334
- if (curr == NULL ) {
335
- error = "Failed to allocate SDL_Surface" ;
336
- goto error ;
337
- }
338
- anim -> frames [frame_idx ] = curr ;
339
- anim -> delays [frame_idx ] = iter .duration ;
340
- if (features .has_alpha ) {
341
- ret = lib .WebPDecodeRGBAInto (
342
- iter .fragment .bytes ,
343
- iter .fragment .size ,
344
- (uint8_t * )curr -> pixels ,
345
- curr -> pitch * curr -> h ,
346
- curr -> pitch );
347
- } else {
348
- ret = lib .WebPDecodeRGBInto (
349
- iter .fragment .bytes , iter .fragment .size ,
350
- (uint8_t * )curr -> pixels ,
351
- curr -> pitch * curr -> h ,
352
- curr -> pitch );
353
- }
354
- if (ret == NULL ) {
355
- break ;
356
- }
357
- }
358
- if (dmuxer ) {
359
- lib .WebPDemuxDelete (dmuxer );
332
+
333
+ canvas = SDL_CreateSurface (anim -> w , anim -> h , features .has_alpha ? SDL_PIXELFORMAT_RGBA32 : SDL_PIXELFORMAT_RGBX32 );
334
+ if (!canvas ) {
335
+ goto error ;
360
336
}
361
337
362
- if (raw_data ) {
363
- SDL_free (raw_data );
338
+ /* Background color is BGRA byte order according to the spec */
339
+ bgcolor = lib .WebPDemuxGetI (demuxer , WEBP_FF_BACKGROUND_COLOR );
340
+ #if SDL_BYTEORDER == SDL_BIG_ENDIAN
341
+ bgcolor = SDL_MapSurfaceRGBA (canvas ,
342
+ (bgcolor >> 8 ) & 0xFF ,
343
+ (bgcolor >> 16 ) & 0xFF ,
344
+ (bgcolor >> 24 ) & 0xFF ,
345
+ (bgcolor >> 0 ) & 0xFF );
346
+ #else
347
+ bgcolor = SDL_MapSurfaceRGBA (canvas ,
348
+ (bgcolor >> 16 ) & 0xFF ,
349
+ (bgcolor >> 8 ) & 0xFF ,
350
+ (bgcolor >> 0 ) & 0xFF ,
351
+ (bgcolor >> 24 ) & 0xFF );
352
+ #endif
353
+
354
+ SDL_zero (iter );
355
+ if (lib .WebPDemuxGetFrame (demuxer , 1 , & iter )) {
356
+ do {
357
+ int frame_idx = (iter .frame_num - 1 );
358
+ if (frame_idx < 0 || frame_idx >= anim -> count ) {
359
+ continue ;
360
+ }
361
+
362
+ if (dispose_method == WEBP_MUX_DISPOSE_BACKGROUND ) {
363
+ SDL_FillSurfaceRect (canvas , NULL , bgcolor );
364
+ }
365
+
366
+ SDL_Surface * curr = SDL_CreateSurface (iter .width , iter .height , SDL_PIXELFORMAT_RGBA32 );
367
+ if (!curr ) {
368
+ goto error ;
369
+ }
370
+
371
+ if (!lib .WebPDecodeRGBAInto (iter .fragment .bytes ,
372
+ iter .fragment .size ,
373
+ (uint8_t * )curr -> pixels ,
374
+ curr -> pitch * curr -> h ,
375
+ curr -> pitch )) {
376
+ error = "WebPDecodeRGBAInto() failed" ;
377
+ SDL_DestroySurface (curr );
378
+ goto error ;
379
+ }
380
+
381
+ SDL_Rect dst = { iter .x_offset , iter .y_offset , iter .width , iter .height };
382
+ if (iter .blend_method == WEBP_MUX_BLEND ) {
383
+ SDL_SetSurfaceBlendMode (curr , SDL_BLENDMODE_BLEND );
384
+ } else {
385
+ SDL_SetSurfaceBlendMode (curr , SDL_BLENDMODE_NONE );
386
+ }
387
+ SDL_BlitSurface (curr , NULL , canvas , & dst );
388
+ SDL_DestroySurface (curr );
389
+
390
+ anim -> frames [frame_idx ] = SDL_DuplicateSurface (canvas );
391
+ anim -> delays [frame_idx ] = iter .duration ;
392
+ dispose_method = iter .dispose_method ;
393
+
394
+ } while (lib .WebPDemuxNextFrame (& iter ));
395
+
396
+ lib .WebPDemuxReleaseIterator (& iter );
364
397
}
398
+
399
+ SDL_DestroySurface (canvas );
400
+
401
+ lib .WebPDemuxDelete (demuxer );
402
+
403
+ SDL_free (raw_data );
404
+
365
405
return anim ;
406
+
366
407
error :
408
+ if (canvas ) {
409
+ SDL_DestroySurface (canvas );
410
+ }
367
411
if (anim ) {
368
412
IMG_FreeAnimation (anim );
369
413
}
370
- if (dmuxer ) {
371
- lib .WebPDemuxDelete (dmuxer );
414
+ if (demuxer ) {
415
+ lib .WebPDemuxDelete (demuxer );
372
416
}
373
417
if (raw_data ) {
374
418
SDL_free (raw_data );
0 commit comments