459
static int png_to_gdkpixmap(GdkWindow *window, uint8 *data, int len,
460
GdkPixmap **pix, GdkBitmap **mask, GdkColormap *colormap)
462
static uint8 *pixels=NULL;
463
static int pixels_byte=0, rows_byte=0;
464
static png_bytepp rows=NULL;
465
unsigned long width, height;
468
int bit_depth, color_type, interlace_type, compression_type,
469
bpp, x,y,has_alpha,i,alpha;
471
GdkGC *gc, *gc_alpha;
477
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
481
return PNGX_OUTOFMEM;
483
info_ptr = png_create_info_struct (png_ptr);
486
png_destroy_read_struct (&png_ptr, NULL, NULL);
487
return PNGX_OUTOFMEM;
489
if (setjmp (png_ptr->jmpbuf)) {
490
png_destroy_read_struct (&png_ptr, &info_ptr,NULL);
494
png_set_read_fn(png_ptr, NULL, user_read_data);
495
png_read_info (png_ptr, info_ptr);
498
* This seems to bug on at least one system (other than mine)
499
* http://www.metalforge.net/cfmb/viewtopic.php?t=1085
501
* I think its actually a bug in libpng. This function dies with an
502
* error based on image width. However I've produced a work around
503
* using the indivial functions. Repeated below.
505
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
506
&color_type, &interlace_type, &compression_type, &filter_type);
508
width = png_get_image_width(png_ptr, info_ptr);
509
height = png_get_image_height(png_ptr, info_ptr);
510
bit_depth = png_get_bit_depth(png_ptr, info_ptr);
511
color_type = png_get_color_type(png_ptr, info_ptr);
512
interlace_type = png_get_interlace_type(png_ptr, info_ptr);
513
compression_type = png_get_compression_type(png_ptr, info_ptr);
514
if (color_type == PNG_COLOR_TYPE_PALETTE &&
517
/* Convert indexed images to RGB */
518
png_set_expand (png_ptr);
520
} else if (color_type == PNG_COLOR_TYPE_GRAY &&
523
/* Convert grayscale to RGB */
524
png_set_expand (png_ptr);
526
} else if (png_get_valid (png_ptr,
527
info_ptr, PNG_INFO_tRNS)) {
529
/* If we have transparency header, convert it to alpha
531
png_set_expand(png_ptr);
533
} else if (bit_depth < 8) {
535
/* If we have < 8 scale it up to 8 */
536
png_set_expand(png_ptr);
539
/* Conceivably, png_set_packing() is a better idea;
540
* God only knows how libpng works
543
/* If we are 16-bit, convert to 8-bit */
544
if (bit_depth == 16) {
545
png_set_strip_16(png_ptr);
548
/* If gray scale, convert to RGB */
549
if (color_type == PNG_COLOR_TYPE_GRAY ||
550
color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
551
png_set_gray_to_rgb(png_ptr);
554
/* If interlaced, handle that */
555
if (interlace_type != PNG_INTERLACE_NONE) {
556
png_set_interlace_handling(png_ptr);
559
/* Update the info the reflect our transformations */
560
png_read_update_info(png_ptr, info_ptr);
561
/* re-read due to transformations just made */
563
* This seems to bug on at least one system (other than mine)
564
* http://www.metalforge.net/cfmb/viewtopic.php?t=1085
566
* I think its actually a bug in libpng. This function dies with an
567
* error based on image width. However I've produced a work around
568
* using the indivial functions. Repeated below.
570
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
571
&color_type, &interlace_type, &compression_type, &filter_type);
573
width = png_get_image_width(png_ptr, info_ptr);
574
height = png_get_image_height(png_ptr, info_ptr);
575
bit_depth = png_get_bit_depth(png_ptr, info_ptr);
576
color_type = png_get_color_type(png_ptr, info_ptr);
577
interlace_type = png_get_interlace_type(png_ptr, info_ptr);
578
compression_type = png_get_compression_type(png_ptr, info_ptr);
580
if (color_type & PNG_COLOR_MASK_ALPHA)
585
/* Allocate the memory we need once, and increase it if necessary.
586
* This is more efficient the allocating this block of memory every time.
588
if (pixels_byte==0) {
589
pixels_byte = width * height * bpp;
590
pixels = (uint8*)malloc(pixels_byte);
591
} else if ((width * height * bpp) > pixels_byte) {
592
pixels_byte =width * height * bpp;
593
/* Doing a free/malloc is probably more efficient -
594
* we don't care about the old data in this
598
pixels= (uint8*)malloc(pixels_byte);
602
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
604
return PNGX_OUTOFMEM;
606
if (rows_byte == 0) {
607
rows =(png_bytepp) malloc(sizeof(char*) * height);
609
} else if (height > rows_byte) {
610
rows =(png_bytepp) realloc(rows, sizeof(char*) * height);
614
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
616
return PNGX_OUTOFMEM;
619
for (y=0; y<height; y++)
620
rows[y] = pixels + y * width * bpp;
622
png_read_image(png_ptr, rows);
624
fprintf(stderr,"image is %d X %d, bpp=%d, color_type=%d\n",
625
width, height, bpp, color_type);
628
*pix = gdk_pixmap_new(window, width, height, -1);
632
gdk_gc_set_function(gc, GDK_COPY);
634
if (color_type & PNG_COLOR_MASK_ALPHA) {
635
*mask=gdk_pixmap_new(window, width, height,1);
636
gc_alpha=gdk_gc_new(*mask);
637
gdk_gc_set_function(gc_alpha, GDK_COPY);
640
gdk_gc_set_foreground(gc_alpha, &scolor);
641
gdk_draw_rectangle(*mask, gc_alpha, 1, 0, 0, width, height);
644
gdk_gc_set_foreground(gc_alpha, &scolor);
649
gc_alpha = None; /* Prevent compile warnings */
652
for (y=0; y<height; y++) {
653
for (x=0; x<width; x++) {
654
rgb[i++]=rows[y][x*bpp]; /* red */
655
rgb[i++]=rows[y][x*bpp+1]; /* green */
656
rgb[i++]=rows[y][x*bpp+2]; /* blue */
658
alpha = rows[y][x*bpp+3];
659
/* Transparent bit */
661
gdk_draw_point(*mask, gc_alpha, x, y);
666
gdk_draw_rgb_image(*pix, gc, 0, 0, 32, 32, GDK_RGB_DITHER_NONE, rgb, 32*3);
667
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
669
gdk_gc_destroy(gc_alpha);