Crossfire Client, Branch  R11627
png.c
Go to the documentation of this file.
00001 const char * const rcsid_gtk2_png_c =
00002     "$Id: png.c 9193 2008-06-01 14:26:32Z anmaster $";
00003 /*
00004     Crossfire client, a client program for the crossfire program.
00005 
00006     Copyright (C) 2005 Mark Wedel & Crossfire Development Team
00007 
00008     This program is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     This program is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with this program; if not, write to the Free Software
00020     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021 
00022     The author can be reached via e-mail to crossfire@metalforge.org
00023 */
00024 
00030 #include <config.h>
00031 #include <stdlib.h>
00032 #include <sys/stat.h>
00033 #ifndef WIN32
00034 #include <unistd.h>
00035 #endif
00036 #include <png.h>
00037 #include <client-types.h>
00038 #include <client.h>
00039 
00040 /* Pick up the gtk headers we need */
00041 #include <gtk/gtk.h>
00042 #ifndef WIN32
00043 #include <gdk/gdkx.h>
00044 #else
00045 #include <gdk/gdkwin32.h>
00046 #endif
00047 #include <gdk/gdkkeysyms.h>
00048 
00049 
00050 /* Defines for PNG return values */
00051 /* These should be in a header file, but currently our calling functions
00052  * routines just check for nonzero return status and don't really care
00053  * why the load failed.
00054  */
00055 #define PNGX_NOFILE     1
00056 #define PNGX_OUTOFMEM   2
00057 #define PNGX_DATA       3
00058 
00059 static uint8 *data_cp;
00060 static int data_len, data_start;
00061 
00068 static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length) {
00069     memcpy(data, data_cp + data_start, length);
00070     data_start += length;
00071 }
00072 
00080 uint8 *png_to_data(uint8 *data, int len, uint32 *width, uint32 *height)
00081 {
00082     uint8 *pixels=NULL;
00083     static png_bytepp   rows=NULL;
00084     static int rows_byte=0;
00085 
00086     png_structp png_ptr;
00087     png_infop   info_ptr;
00088     int bit_depth, color_type, interlace_type, compression_type, y;
00089 
00090     data_len=len;
00091     data_cp = data;
00092     data_start=0;
00093 
00094     png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
00095                                      NULL, NULL, NULL);
00096 
00097     if (!png_ptr) {
00098         return NULL;
00099     }
00100     info_ptr = png_create_info_struct (png_ptr);
00101 
00102     if (!info_ptr) {
00103         png_destroy_read_struct (&png_ptr, NULL, NULL);
00104         return NULL;
00105     }
00106 
00107 
00108     if (setjmp (png_jmpbuf(png_ptr))) {
00109         png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
00110         return NULL;
00111     }
00112 
00113 
00114     png_set_read_fn(png_ptr, NULL, user_read_data);
00115     png_read_info (png_ptr, info_ptr);
00116 
00117         /*
00118          * This seems to bug on at least one system (other than mine)
00119          * http://www.metalforge.net/cfmb/viewtopic.php?t=1085
00120          *
00121          * I think its actually a bug in libpng. This function dies with an
00122          * error based on image width. However I've produced a work around
00123          * using the indivial functions. Repeated below.
00124          *
00125     png_get_IHDR(png_ptr, info_ptr, (png_uint_32*)width, (png_unit_32*)height, &bit_depth,
00126                  &color_type, &interlace_type, &compression_type, &filter_type);
00127          */
00128         *width = png_get_image_width(png_ptr, info_ptr);
00129         *height = png_get_image_height(png_ptr, info_ptr);
00130         bit_depth = png_get_bit_depth(png_ptr, info_ptr);
00131         color_type = png_get_color_type(png_ptr, info_ptr);
00132         interlace_type = png_get_interlace_type(png_ptr, info_ptr);
00133         compression_type = png_get_compression_type(png_ptr, info_ptr);
00134 
00135     if (color_type == PNG_COLOR_TYPE_PALETTE &&
00136             bit_depth <= 8) {
00137 
00138                 /* Convert indexed images to RGB */
00139                 png_set_expand (png_ptr);
00140 
00141     } else if (color_type == PNG_COLOR_TYPE_GRAY &&
00142                    bit_depth < 8) {
00143 
00144                 /* Convert grayscale to RGB */
00145                 png_set_expand (png_ptr);
00146 
00147     } else if (png_get_valid (png_ptr,
00148                                   info_ptr, PNG_INFO_tRNS)) {
00149 
00150                 /* If we have transparency header, convert it to alpha
00151                    channel */
00152                 png_set_expand(png_ptr);
00153 
00154     } else if (bit_depth < 8) {
00155 
00156                 /* If we have < 8 scale it up to 8 */
00157                 png_set_expand(png_ptr);
00158 
00159 
00160                 /* Conceivably, png_set_packing() is a better idea;
00161                  * God only knows how libpng works
00162                  */
00163     }
00164         /* If we are 16-bit, convert to 8-bit */
00165     if (bit_depth == 16) {
00166                 png_set_strip_16(png_ptr);
00167     }
00168 
00169         /* If gray scale, convert to RGB */
00170     if (color_type == PNG_COLOR_TYPE_GRAY ||
00171             color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
00172                 png_set_gray_to_rgb(png_ptr);
00173     }
00174 
00175         /* If interlaced, handle that */
00176     if (interlace_type != PNG_INTERLACE_NONE) {
00177                 png_set_interlace_handling(png_ptr);
00178     }
00179 
00180     /* pad it to 4 bytes to make processing easier */
00181     if (!(color_type & PNG_COLOR_MASK_ALPHA))
00182         png_set_filler(png_ptr, 255, PNG_FILLER_AFTER);
00183 
00184     /* Update the info the reflect our transformations */
00185     png_read_update_info(png_ptr, info_ptr);
00186     /* re-read due to transformations just made */
00187         /*
00188          * See above for error description
00189     png_get_IHDR(png_ptr, info_ptr, (png_uint_32*)width, (png_uint_32*)height, &bit_depth,
00190                  &color_type, &interlace_type, &compression_type, &filter_type);
00191         */
00192         *width = png_get_image_width(png_ptr, info_ptr);
00193         *height = png_get_image_height(png_ptr, info_ptr);
00194         bit_depth = png_get_bit_depth(png_ptr, info_ptr);
00195         color_type = png_get_color_type(png_ptr, info_ptr);
00196         interlace_type = png_get_interlace_type(png_ptr, info_ptr);
00197         compression_type = png_get_compression_type(png_ptr, info_ptr);
00198 
00199 
00200     pixels = (uint8*)malloc(*width * *height * 4);
00201 
00202     if (!pixels) {
00203         png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
00204         LOG(LOG_CRITICAL,"gtk::png_to_data","Out of memory - exiting");
00205         exit(1);
00206     }
00207 
00208     /* the png library needs the rows, but we will just return the raw data */
00209     if (rows_byte == 0) {
00210         rows =(png_bytepp) malloc(sizeof(char*) * *height);
00211         rows_byte=*height;
00212     } else if (*height > rows_byte) {
00213         rows =(png_bytepp) realloc(rows, sizeof(char*) * *height);
00214         rows_byte=*height;
00215     }
00216     if (!rows) {
00217         png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
00218         return NULL;
00219     }
00220 
00221     for (y=0; y<*height; y++)
00222         rows[y] = pixels + y * *width * 4;
00223 
00224     png_read_image(png_ptr, rows);
00225     png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
00226 
00227     return pixels;
00228 }
00229 
00230 /* RATIO is used to know what units scale is - in this case, a percentage, so
00231  * it is set to 100
00232  */
00233 #define RATIO   100
00234 
00235 #define MAX_IMAGE_WIDTH         1024
00236 #define MAX_IMAGE_HEIGHT        1024
00237 #define BPP 4
00238 
00267 uint8 *rescale_rgba_data(uint8 *data, int *width, int *height, int scale)
00268 {
00269     static int xrow[BPP * MAX_IMAGE_WIDTH], yrow[BPP*MAX_IMAGE_HEIGHT];
00270     static uint8 *nrows[MAX_IMAGE_HEIGHT];
00271 
00272     /* Figure out new height/width */
00273     int new_width = *width  * scale / RATIO, new_height = *height * scale / RATIO;
00274 
00275     int sourcerow=0, ytoleft, ytofill, xtoleft, xtofill, dest_column=0, source_column=0, needcol,
00276         destrow=0;
00277     int x,y;
00278     uint8 *ndata;
00279     uint8 r,g,b,a;
00280 
00281     if (*width > MAX_IMAGE_WIDTH || new_width > MAX_IMAGE_WIDTH
00282     || *height > MAX_IMAGE_HEIGHT || new_height > MAX_IMAGE_HEIGHT)
00283     {
00284         LOG(LOG_CRITICAL,"gtk::rescale_rgba_data","Image too big");
00285         exit(0);
00286     }
00287 
00288     /* clear old values these may have */
00289     memset(yrow, 0, sizeof(int) * *height * BPP);
00290 
00291     ndata = (uint8*)malloc(new_width * new_height * BPP);
00292 
00293     for (y=0; y<new_height; y++)
00294         nrows[y] = (png_bytep) (ndata + y * new_width * BPP);
00295 
00296     ytoleft = scale;
00297     ytofill = RATIO;
00298 
00299     for (y=0,sourcerow=0; y < new_height; y++) {
00300         memset(xrow, 0, sizeof(int) * *width * BPP);
00301         while (ytoleft < ytofill) {
00302             for (x=0; x< *width; ++x) {
00303                 /* Only want to copy the data if this is not a transperent pixel.
00304                  * If it is transparent, the color information is has is probably
00305                  * bogus, and blending that makes the results look worse.
00306                  */
00307                 if (data[(sourcerow * *width + x)*BPP+3] > 0 ) {
00308                     yrow[x*BPP] += ytoleft * data[(sourcerow * *width + x)*BPP]/RATIO;
00309                     yrow[x*BPP+1] += ytoleft * data[(sourcerow * *width + x)*BPP+1]/RATIO;
00310                     yrow[x*BPP+2] += ytoleft * data[(sourcerow * *width + x)*BPP+2]/RATIO;
00311                 }
00312                 /* Alpha is a bit special - we don't want to blend it -
00313                  * we want to take whatever is the more opaque value.
00314                  */
00315                 if (data[(sourcerow * *width + x)*BPP+3] > yrow[x*BPP+3])
00316                     yrow[x*BPP+3] = data[(sourcerow * *width + x)*BPP+3];
00317             }
00318             ytofill -= ytoleft;
00319             ytoleft = scale;
00320             if (sourcerow < *height)
00321                 sourcerow++;
00322         }
00323 
00324         for (x=0; x < *width; ++x) {
00325             if (data[(sourcerow * *width + x)*BPP+3] > 0 ) {
00326                 xrow[x*BPP] = yrow[x*BPP] + ytofill * data[(sourcerow * *width + x)*BPP] / RATIO;
00327                 xrow[x*BPP+1] = yrow[x*BPP+1] + ytofill * data[(sourcerow * *width + x)*BPP+1] / RATIO;
00328                 xrow[x*BPP+2] = yrow[x*BPP+2] + ytofill * data[(sourcerow * *width + x)*BPP+2] / RATIO;
00329             }
00330             if (data[(sourcerow * *width + x)*BPP+3] > xrow[x*BPP+3])
00331                 xrow[x*BPP+3] = data[(sourcerow * *width + x)*BPP+3];
00332             yrow[x*BPP]=0; yrow[x*BPP+1]=0; yrow[x*BPP+2]=0; yrow[x*BPP+3]=0;
00333         }
00334 
00335         ytoleft -= ytofill;
00336         if (ytoleft <= 0) {
00337             ytoleft = scale;
00338             if (sourcerow < *height)
00339                 sourcerow++;
00340         }
00341 
00342         ytofill = RATIO;
00343         xtofill = RATIO;
00344         dest_column = 0;
00345         source_column=0;
00346         needcol=0;
00347         r=0; g=0; b=0; a=0;
00348 
00349         for (x=0; x< *width; x++) {
00350             xtoleft = scale;
00351 
00352             while (xtoleft >= xtofill) {
00353                 if (needcol) {
00354                     dest_column++;
00355                     r=0; g=0; b=0; a=0;
00356                 }
00357 
00358                 if (xrow[source_column*BPP+3] > 0) {
00359                     r += xtofill * xrow[source_column*BPP] / RATIO;
00360                     g += xtofill * xrow[1+source_column*BPP] / RATIO;
00361                     b += xtofill * xrow[2+source_column*BPP] / RATIO;
00362                 }
00363                 if (xrow[3+source_column*BPP] > a)
00364                     a = xrow[3+source_column*BPP];
00365 
00366                 nrows[destrow][dest_column * BPP] = r;
00367                 nrows[destrow][1+dest_column * BPP] = g;
00368                 nrows[destrow][2+dest_column * BPP] = b;
00369                 nrows[destrow][3+dest_column * BPP] = a;
00370                 xtoleft -= xtofill;
00371                 xtofill = RATIO;
00372                 needcol=1;
00373             }
00374 
00375             if (xtoleft > 0 ){
00376                 if (needcol) {
00377                     dest_column++;
00378                     r=0; g=0; b=0; a=0;
00379                     needcol=0;
00380                 }
00381 
00382                 if (xrow[3+source_column*BPP] > 0) {
00383                     r += xtoleft * xrow[source_column*BPP] / RATIO;
00384                     g += xtoleft * xrow[1+source_column*BPP] / RATIO;
00385                     b += xtoleft * xrow[2+source_column*BPP] / RATIO;
00386                 }
00387                 if (xrow[3+source_column*BPP] > a)
00388                     a = xrow[3+source_column*BPP];
00389 
00390                 xtofill -= xtoleft;
00391             }
00392             source_column++;
00393         }
00394 
00395         if (xtofill > 0 ) {
00396             source_column--;
00397             if (xrow[3+source_column*BPP] > 0) {
00398                 r += xtofill * xrow[source_column*BPP] / RATIO;
00399                 g += xtofill * xrow[1+source_column*BPP] / RATIO;
00400                 b += xtofill * xrow[2+source_column*BPP] / RATIO;
00401             }
00402             if (xrow[3+source_column*BPP] > a)
00403                 a = xrow[3+source_column*BPP];
00404         }
00405 
00406         /* Not positve, but without the bound checking for dest_column,
00407          * we were overrunning the buffer.  My guess is this only really
00408          * showed up if when the images are being scaled - there is probably
00409          * something like half a pixel left over.
00410          */
00411         if (!needcol && (dest_column < new_width)) {
00412             nrows[destrow][dest_column * BPP] = r;
00413             nrows[destrow][1+dest_column * BPP] = g;
00414             nrows[destrow][2+dest_column * BPP] = b;
00415             nrows[destrow][3+dest_column * BPP] = a;
00416         }
00417         destrow++;
00418     }
00419     *width = new_width;
00420     *height = new_height;
00421     return ndata;
00422 }
00423 
00424 
00425 guchar rgb[512*512*3];  
00441 int rgba_to_gdkpixmap(GdkWindow *window, uint8 *data,int width, int height,
00442                    GdkPixmap **pix, GdkBitmap **mask, GdkColormap *colormap)
00443 {
00444     GdkGC       *gc, *gc_alpha;
00445     int         has_alpha=0, alpha;
00446     GdkColor  scolor;
00447     int x,y;
00448 
00449     *pix = gdk_pixmap_new(window, width, height, -1);
00450 
00451     gc=gdk_gc_new(*pix);
00452     gdk_gc_set_function(gc, GDK_COPY);
00453 
00454     *mask=gdk_pixmap_new(window, width, height,1);
00455     gc_alpha=gdk_gc_new(*mask);
00456 
00457     scolor.pixel=1;
00458     gdk_gc_set_foreground(gc_alpha, &scolor);
00459     gdk_draw_rectangle(*mask, gc_alpha, 1, 0, 0, width, height);
00460 
00461     scolor.pixel=0;
00462     gdk_gc_set_foreground(gc_alpha, &scolor);
00463 
00464     /* we need to draw the alpha channel.  The image may not in fact
00465      * have alpha, but no way to know at this point other than to try
00466      * and draw it.
00467      */
00468     for (y=0; y<height; y++) {
00469         for (x=0; x<width; x++) {
00470             alpha = data[(y * width + x) * 4 +3];
00471             /* Transparent bit */
00472             if (alpha==0) {
00473                 gdk_draw_point(*mask, gc_alpha, x, y);
00474                 has_alpha=1;
00475             }
00476         }
00477     }
00478 
00479     gdk_draw_rgb_32_image(*pix, gc,  0, 0, width, height, GDK_RGB_DITHER_NONE, data, width*4);
00480     if (!has_alpha) {
00481         gdk_pixmap_unref(*mask);
00482         *mask = NULL;
00483     }
00484 
00485     gdk_gc_destroy(gc_alpha);
00486     gdk_gc_destroy(gc);
00487     return 0;
00488 }
00489 
00500 int rgba_to_gdkpixbuf(uint8 *data,int width, int height,GdkPixbuf **pix)
00501 {
00502     int         rowstride;
00503     guchar  *pixels, *p;
00504     int x,y;
00505 
00506 #if 0
00507     /* I'm not sure why this doesn't work, since it seems
00508      * the data should be in the right format, but it doesn't.
00509      */
00510     *pix = gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB,
00511                     TRUE, 8, width, height, width * 4, NULL, NULL);
00512     return 0;
00513 
00514 #else
00515     *pix  = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height);
00516 
00517     rowstride =  gdk_pixbuf_get_rowstride(*pix);
00518     pixels = gdk_pixbuf_get_pixels(*pix);
00519 
00520     for (y=0; y<height; y++) {
00521         for (x=0; x<width; x++) {
00522             p = pixels + y * rowstride + x * 4;
00523             p[0] = data[4*(x + y * width)];
00524             p[1] = data[4*(x + y * width) + 1 ];
00525             p[2] = data[4*(x + y * width) + 2 ];
00526             p[3] = data[4*(x + y * width) + 3 ];
00527 
00528         }
00529     }
00530 
00531     return 0;
00532 #endif
00533 }
00534 
00544 int png_to_gdkpixmap(GdkWindow *window, uint8 *data, int len,
00545                    GdkPixmap **pix, GdkBitmap **mask, GdkColormap *colormap)
00546 {
00547     static uint8 *pixels=NULL;
00548     static int pixels_byte=0, rows_byte=0;
00549     static png_bytepp   rows=NULL;
00550     unsigned long width, height;
00551     png_structp png_ptr;
00552     png_infop   info_ptr;
00553     int bit_depth, color_type, interlace_type, compression_type, filter_type,
00554         bpp, x,y,has_alpha,i,alpha;
00555     GdkColor  scolor;
00556     GdkGC       *gc, *gc_alpha;
00557 
00558     data_len=len;
00559     data_cp = data;
00560     data_start=0;
00561 
00562     png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
00563                                      NULL, NULL, NULL);
00564 
00565     if (!png_ptr) {
00566         return PNGX_OUTOFMEM;
00567     }
00568     info_ptr = png_create_info_struct (png_ptr);
00569 
00570     if (!info_ptr) {
00571         png_destroy_read_struct (&png_ptr, NULL, NULL);
00572         return PNGX_OUTOFMEM;
00573     }
00574     if (setjmp (png_ptr->jmpbuf)) {
00575         png_destroy_read_struct (&png_ptr, &info_ptr,NULL);
00576         return PNGX_DATA;
00577     }
00578     has_alpha=0;
00579     png_set_read_fn(png_ptr, NULL, user_read_data);
00580     png_read_info (png_ptr, info_ptr);
00581 
00582     png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
00583                  &color_type, &interlace_type, &compression_type, &filter_type);
00584 
00585     if (color_type == PNG_COLOR_TYPE_PALETTE &&
00586             bit_depth <= 8) {
00587 
00588                 /* Convert indexed images to RGB */
00589                 png_set_expand (png_ptr);
00590 
00591     } else if (color_type == PNG_COLOR_TYPE_GRAY &&
00592                    bit_depth < 8) {
00593 
00594                 /* Convert grayscale to RGB */
00595                 png_set_expand (png_ptr);
00596 
00597     } else if (png_get_valid (png_ptr,
00598                                   info_ptr, PNG_INFO_tRNS)) {
00599 
00600                 /* If we have transparency header, convert it to alpha
00601                    channel */
00602                 png_set_expand(png_ptr);
00603 
00604     } else if (bit_depth < 8) {
00605 
00606                 /* If we have < 8 scale it up to 8 */
00607                 png_set_expand(png_ptr);
00608 
00609 
00610                 /* Conceivably, png_set_packing() is a better idea;
00611                  * God only knows how libpng works
00612                  */
00613     }
00614         /* If we are 16-bit, convert to 8-bit */
00615     if (bit_depth == 16) {
00616                 png_set_strip_16(png_ptr);
00617     }
00618 
00619         /* If gray scale, convert to RGB */
00620     if (color_type == PNG_COLOR_TYPE_GRAY ||
00621             color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
00622                 png_set_gray_to_rgb(png_ptr);
00623     }
00624 
00625         /* If interlaced, handle that */
00626     if (interlace_type != PNG_INTERLACE_NONE) {
00627                 png_set_interlace_handling(png_ptr);
00628     }
00629 
00630     /* Update the info the reflect our transformations */
00631     png_read_update_info(png_ptr, info_ptr);
00632     /* re-read due to transformations just made */
00633     png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
00634                  &color_type, &interlace_type, &compression_type, &filter_type);
00635     if (color_type & PNG_COLOR_MASK_ALPHA)
00636                 bpp = 4;
00637     else
00638                 bpp = 3;
00639 
00640     /* Allocate the memory we need once, and increase it if necessary.
00641      * This is more efficient the allocating this block of memory every time.
00642      */
00643     if (pixels_byte==0) {
00644         pixels_byte = width * height * bpp;
00645         pixels = (uint8*)malloc(pixels_byte);
00646     } else if ((width * height * bpp) > pixels_byte) {
00647         pixels_byte =width * height * bpp;
00648         /* Doing a free/malloc is probably more efficient -
00649          * we don't care about the old data in this
00650          * buffer.
00651          */
00652         free(pixels);
00653         pixels= (uint8*)malloc(pixels_byte);
00654     }
00655 
00656     if (!pixels) {
00657         png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
00658         pixels_byte=0;
00659         return PNGX_OUTOFMEM;
00660     }
00661     if (rows_byte == 0) {
00662         rows =(png_bytepp) malloc(sizeof(char*) * height);
00663         rows_byte=height;
00664     } else if (height > rows_byte) {
00665         rows =(png_bytepp) realloc(rows, sizeof(char*) * height);
00666         rows_byte=height;
00667     }
00668     if (!rows) {
00669         png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
00670         pixels_byte=0;
00671         return PNGX_OUTOFMEM;
00672     }
00673 
00674     for (y=0; y<height; y++)
00675         rows[y] = pixels + y * width * bpp;
00676 
00677     png_read_image(png_ptr, rows);
00678 #if 0
00679     fprintf(stderr,"image is %d X %d, bpp=%d, color_type=%d\n",
00680             width, height, bpp, color_type);
00681 #endif
00682 
00683     *pix = gdk_pixmap_new(window, width, height, -1);
00684 
00685 
00686     gc=gdk_gc_new(*pix);
00687     gdk_gc_set_function(gc, GDK_COPY);
00688 
00689     if (color_type & PNG_COLOR_MASK_ALPHA) {
00690         *mask=gdk_pixmap_new(window, width, height,1);
00691         gc_alpha=gdk_gc_new(*mask);
00692         gdk_gc_set_function(gc_alpha, GDK_COPY);
00693 
00694         scolor.pixel=1;
00695         gdk_gc_set_foreground(gc_alpha, &scolor);
00696         gdk_draw_rectangle(*mask, gc_alpha, 1, 0, 0, width, height);
00697 
00698         scolor.pixel=0;
00699         gdk_gc_set_foreground(gc_alpha, &scolor);
00700         has_alpha=1;
00701     }
00702     else {
00703         *mask = NULL;
00704         gc_alpha = NULL;    /* Prevent compile warnings */
00705     }
00706     i=0;
00707     for (y=0; y<height; y++) {
00708         for (x=0; x<width; x++) {
00709             rgb[i++]=rows[y][x*bpp];    /* red */
00710             rgb[i++]=rows[y][x*bpp+1];  /* green */
00711             rgb[i++]=rows[y][x*bpp+2];  /* blue */
00712             if (has_alpha) {
00713                 alpha = rows[y][x*bpp+3];
00714                 /* Transparent bit */
00715                 if (alpha==0) {
00716                     gdk_draw_point(*mask, gc_alpha, x, y);
00717                 }
00718             }
00719         }
00720     }
00721     gdk_draw_rgb_image(*pix, gc,  0, 0, 32, 32, GDK_RGB_DITHER_NONE, rgb, 32*3);
00722     png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
00723     if (has_alpha)
00724         gdk_gc_destroy(gc_alpha);
00725     gdk_gc_destroy(gc);
00726     return 0;
00727 }