@@ -253,6 +253,7 @@ gdip_load_png_image_from_file_or_stream (FILE *fp, GetBytesDelegate getBytesFunc
253
253
int bit_depth ;
254
254
int channels ;
255
255
BYTE color_type ;
256
+ BYTE original_color_type ;
256
257
int num_palette = 0 ;
257
258
png_colorp png_palette = NULL ;
258
259
@@ -283,21 +284,51 @@ gdip_load_png_image_from_file_or_stream (FILE *fp, GetBytesDelegate getBytesFunc
283
284
png_set_read_fn (png_ptr , (void * ) getBytesFunc , _gdip_png_stream_read_data );
284
285
}
285
286
286
- /* Pass PNG_TRANSFORM_STRIP_16, which basically reduces the color palette from 16-bits to 8-bits
287
+ png_read_info (png_ptr , info_ptr );
288
+
289
+ bit_depth = png_get_bit_depth (png_ptr , info_ptr );
290
+ original_color_type = png_get_color_type (png_ptr , info_ptr );
291
+ channels = png_get_channels (png_ptr , info_ptr );
292
+
293
+ /* Apply png_set_strip_16, which basically reduces the color palette from 16-bits to 8-bits
287
294
* for 16-bit color depths. The current implementation of libgdiplus doesn't handle bit depths > 8,
288
295
* so this acts as a workaround. Net impact is that the quality of the image is slightly reduced instead
289
296
* of refusing to process the image (and potentially crashing the application) altogether;
290
297
* proper support would mean supporting 16-bit color channels.
291
298
* Partially fixes http://bugzilla.ximian.com/show_bug.cgi?id=80693 */
292
- png_read_png (png_ptr , info_ptr , PNG_TRANSFORM_STRIP_16 , NULL );
299
+ if (bit_depth == 16 ) {
300
+ png_set_strip_16 (png_ptr );
301
+ png_set_gray_to_rgb (png_ptr );
302
+ png_set_bgr (png_ptr );
303
+ png_set_add_alpha (png_ptr , 0xFF , PNG_FILLER_AFTER );
304
+ channels = 4 ;
305
+ }
306
+
307
+ if (bit_depth == 2
308
+ || (bit_depth == 4 && original_color_type != PNG_COLOR_TYPE_PALETTE )
309
+ || (bit_depth == 8 && original_color_type != PNG_COLOR_TYPE_PALETTE )) {
310
+ png_set_expand (png_ptr );
311
+ png_set_gray_to_rgb (png_ptr );
312
+ png_set_bgr (png_ptr );
313
+ png_set_add_alpha (png_ptr , 0xFF , PNG_FILLER_AFTER );
314
+ }
315
+
316
+ if (bit_depth == 8 && !(channels == 1 && (original_color_type == PNG_COLOR_TYPE_PALETTE || original_color_type == PNG_COLOR_TYPE_GRAY ))) {
317
+ png_set_bgr (png_ptr );
318
+ png_set_add_alpha (png_ptr , 0xFF , PNG_FILLER_AFTER );
319
+ }
320
+
321
+ // Update the image properties after the transformations have been applied.
322
+ // The channels property is not refreshed; the original value will be used
323
+ // later to set the pixel format.
324
+ png_read_update_info (png_ptr , info_ptr );
293
325
294
326
bit_depth = png_get_bit_depth (png_ptr , info_ptr );
295
- channels = png_get_channels (png_ptr , info_ptr );
296
327
color_type = png_get_color_type (png_ptr , info_ptr );
297
328
png_get_PLTE ( png_ptr , info_ptr , & png_palette , & num_palette );
298
329
299
330
/* 2bpp is a special case (promoted to 32bpp ARGB by MS GDI+) */
300
- if ((bit_depth <= 8 ) && (bit_depth != 2 ) && (channels == 1 ) &&
331
+ if ((bit_depth <= 8 ) && (bit_depth != 2 ) && (channels == 1 ) &&
301
332
((color_type == PNG_COLOR_TYPE_PALETTE ) || (color_type == PNG_COLOR_TYPE_GRAY ))) {
302
333
int width ;
303
334
int height ;
@@ -318,24 +349,32 @@ gdip_load_png_image_from_file_or_stream (FILE *fp, GetBytesDelegate getBytesFunc
318
349
gdip_align_stride (dest_stride );
319
350
320
351
/* Copy image data. */
321
- row_pointers = png_get_rows (png_ptr , info_ptr );
322
-
323
352
unsigned long long int size = (unsigned long long int )dest_stride * height ;
324
353
if (size > G_MAXINT32 ) {
325
354
status = OutOfMemory ;
326
355
goto error ;
327
356
}
328
357
329
- rawdata = GdipAlloc (size );
358
+ row_pointers = (png_bytep * )malloc (sizeof (png_bytep ) * height );
359
+ if (!row_pointers ) {
360
+ status = OutOfMemory ;
361
+ goto error ;
362
+ }
363
+
364
+ rawdata = GdipAlloc (dest_stride * height );
330
365
if (!rawdata ) {
331
366
status = OutOfMemory ;
367
+ free (row_pointers );
332
368
goto error ;
333
369
}
334
370
335
371
for (i = 0 ; i < height ; i ++ ) {
336
- memcpy ( rawdata + i * dest_stride , row_pointers [ i ], source_stride ) ;
372
+ row_pointers [ i ] = rawdata + i * dest_stride ;
337
373
}
338
374
375
+ png_read_image (png_ptr , row_pointers );
376
+ free (row_pointers );
377
+
339
378
/* Copy palette. */
340
379
num_colours = 1 << bit_depth ;
341
380
@@ -443,18 +482,13 @@ gdip_load_png_image_from_file_or_stream (FILE *fp, GetBytesDelegate getBytesFunc
443
482
result -> active_bitmap -> dpi_horz = 0 ;
444
483
result -> active_bitmap -> dpi_vert = 0 ;
445
484
result -> active_bitmap -> palette = palette ;
446
- }
447
-
448
- /* 2bpp needs to enter here too */
449
- if (!result ) {
485
+ } else if (bit_depth == 8 && (color_type == PNG_COLOR_TYPE_RGBA || color_type == PNG_COLOR_TYPE_RGB )) {
450
486
int width ;
451
487
int height ;
452
488
BYTE bit_depth ;
453
489
int stride ;
454
490
png_bytep * row_pointers ;
455
- BYTE * rawptr ;
456
- int i , j ;
457
- BYTE alpha [4 ] = {0xFF , 0xFF , 0xFF , 0xFF }; /* Transparency values for 2bpp - default to fully opaque. */
491
+ int i ;
458
492
459
493
width = png_get_image_width (png_ptr , info_ptr );
460
494
height = png_get_image_height (png_ptr , info_ptr );
@@ -470,7 +504,12 @@ gdip_load_png_image_from_file_or_stream (FILE *fp, GetBytesDelegate getBytesFunc
470
504
stride = (width * 4 );
471
505
gdip_align_stride (stride );
472
506
473
- row_pointers = png_get_rows (png_ptr , info_ptr );
507
+ /* Copy image data. */
508
+ row_pointers = (png_bytep * )malloc (sizeof (png_bytep ) * height );
509
+ if (!row_pointers ) {
510
+ status = OutOfMemory ;
511
+ goto error ;
512
+ }
474
513
475
514
unsigned long long int size = (unsigned long long int )stride * height ;
476
515
if (size > G_MAXINT32 ) {
@@ -481,118 +520,17 @@ gdip_load_png_image_from_file_or_stream (FILE *fp, GetBytesDelegate getBytesFunc
481
520
rawdata = GdipAlloc (size );
482
521
if (!rawdata ) {
483
522
status = OutOfMemory ;
523
+ free (row_pointers );
484
524
goto error ;
485
525
}
486
526
487
- rawptr = rawdata ;
488
- switch (channels ) {
489
- case 4 : {
490
- for (i = 0 ; i < height ; i ++ ) {
491
- png_bytep rowp = row_pointers [i ];
492
- for (j = 0 ; j < width ; j ++ ) {
493
- BYTE b = rowp [2 ];
494
- BYTE g = rowp [1 ];
495
- BYTE r = rowp [0 ];
496
- BYTE a = rowp [3 ];
497
-
498
- set_pixel_bgra (rawptr , 0 , b , g , r , a );
499
- rowp += 4 ;
500
- rawptr += 4 ;
501
- }
502
- }
503
- break ;
504
- }
505
-
506
- case 3 : {
507
- for (i = 0 ; i < height ; i ++ ) {
508
- png_bytep rowp = row_pointers [i ];
509
- for (j = 0 ; j < width ; j ++ ) {
510
- set_pixel_bgra (rawptr , 0 , rowp [2 ], rowp [1 ], rowp [0 ], 0xff );
511
- rowp += 3 ;
512
- rawptr += 4 ;
513
- }
514
- }
515
- break ;
516
- }
527
+ for (i = 0 ; i < height ; i ++ ) {
528
+ row_pointers [i ] = rawdata + i * stride ;
529
+ }
517
530
518
- case 2 : {
519
- for (i = 0 ; i < height ; i ++ ) {
520
- png_bytep rowp = row_pointers [i ];
521
- for (j = 0 ; j < width ; j ++ ) {
522
- set_pixel_bgra (rawptr , 0 , rowp [0 ], rowp [0 ], rowp [0 ], rowp [1 ]);
523
- rowp += 2 ;
524
- rawptr += 4 ;
525
- }
526
- }
527
- break ;
528
- }
531
+ png_read_image (png_ptr , row_pointers );
529
532
530
- case 1 :
531
- if (bit_depth == 2 ) {
532
- /* Make sure transparency is respected for 2bpp images. */
533
- int num_trans = 0 ;
534
- BYTE * trans = NULL ;
535
- png_color_16p dummy = NULL ;
536
- if (png_get_tRNS (png_ptr , info_ptr , & trans , & num_trans , & dummy )) {
537
- if (num_trans > 0 && trans != NULL ) {
538
- memcpy (alpha , trans , MIN (num_trans , 4 ));
539
- }
540
- }
541
- }
542
- for (i = 0 ; i < height ; i ++ ) {
543
- png_bytep rowp = row_pointers [i ];
544
- rawptr = rawdata + i * stride ; /* Ensure each output row starts at the right place. */
545
- if (bit_depth == 2 ) {
546
- // 4 pixels for each byte
547
- for (j = 0 ; j < width ; j ++ ) {
548
- png_byte palette = 0 ;
549
- png_byte pix = * rowp ++ ;
550
-
551
- palette = (pix >> 6 ) & 0x03 ;
552
- set_pixel_bgra (rawptr , 0 ,
553
- png_palette [palette ].blue ,
554
- png_palette [palette ].green ,
555
- png_palette [palette ].red ,
556
- alpha [palette ]);
557
- if (++ j >= width )
558
- break ;
559
-
560
- palette = (pix >> 4 ) & 0x03 ;
561
- set_pixel_bgra (rawptr , 4 ,
562
- png_palette [palette ].blue ,
563
- png_palette [palette ].green ,
564
- png_palette [palette ].red ,
565
- alpha [palette ]);
566
- if (++ j >= width )
567
- break ;
568
-
569
- palette = (pix >> 2 ) & 0x03 ;
570
- set_pixel_bgra (rawptr , 8 ,
571
- png_palette [palette ].blue ,
572
- png_palette [palette ].green ,
573
- png_palette [palette ].red ,
574
- alpha [palette ]);
575
- if (++ j >= width )
576
- break ;
577
-
578
- palette = pix & 0x03 ;
579
- set_pixel_bgra (rawptr , 12 ,
580
- png_palette [palette ].blue ,
581
- png_palette [palette ].green ,
582
- png_palette [palette ].red ,
583
- alpha [palette ]);
584
- rawptr += 16 ;
585
- }
586
- } else {
587
- for (j = 0 ; j < width ; j ++ ) {
588
- png_byte pix = * rowp ++ ;
589
- set_pixel_bgra (rawptr , 0 , pix , pix , pix , 0xff );
590
- rawptr += 4 ;
591
- }
592
- }
593
- }
594
- break ;
595
- }
533
+ free (row_pointers );
596
534
597
535
result = gdip_bitmap_new_with_frame (& gdip_image_frameDimension_page_guid , TRUE);
598
536
if (!result ) {
@@ -626,12 +564,15 @@ gdip_load_png_image_from_file_or_stream (FILE *fp, GetBytesDelegate getBytesFunc
626
564
result -> active_bitmap -> image_flags |= ImageFlagsHasAlpha ;
627
565
}
628
566
629
- if (color_type & PNG_COLOR_MASK_ALPHA )
567
+ if (original_color_type & PNG_COLOR_MASK_ALPHA )
630
568
result -> active_bitmap -> image_flags |= ImageFlagsHasAlpha ;
631
569
632
570
result -> active_bitmap -> image_flags |= ImageFlagsReadOnly | ImageFlagsHasRealPixelSize ;
633
571
result -> active_bitmap -> dpi_horz = 0 ;
634
572
result -> active_bitmap -> dpi_vert = 0 ;
573
+ } else {
574
+ status = InvalidParameter ;
575
+ goto error ;
635
576
}
636
577
637
578
status = gdip_load_png_properties (png_ptr , info_ptr , end_info_ptr , result -> active_bitmap );
0 commit comments