GLES1RICE: Update from upstream
[mupen64plus-pandora.git] / source / rice_gles / src / liblinux / pngrw.c
1 /*
2 //  source code for the ImageLib PNG functions
3 //
4 //  Copyright (C) 2001 M. Scott Heiman
5 //  All Rights Reserved
6 //
7 // You may use the software for any purpose you see fit. You may modify
8 // it, incorporate it in a commercial application, use it for school,
9 // even turn it in as homework. You must keep the Copyright in the
10 // header and source files. This software is not in the "Public Domain".
11 // You may use this software at your own risk. I have made a reasonable
12 // effort to verify that this software works in the manner I expect it to;
13 // however,...
14 //
15 // THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" AND
16 // WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, INCLUDING
17 // WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A
18 // PARTICULAR PURPOSE. IN NO EVENT SHALL MICHAEL S. HEIMAN BE LIABLE TO
19 // YOU OR ANYONE ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR
20 // CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING
21 // WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE,
22 // OR THE CLAIMS OF THIRD PARTIES, WHETHER OR NOT MICHAEL S. HEIMAN HAS
23 // BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
24 // ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
25 // POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
26 */
27
28 #include "BMGUtils.h"
29 #include <ctype.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #ifdef _BMG_LIBPNG_STANDALONE
33 #include "BMGLibPNG.h"
34 #else
35 #include "pngrw.h"
36 #endif
37 #include <png.h>
38
39 #ifndef png_jmpbuf
40 #  define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
41 #endif
42
43
44 /* this stuff is necessary because the normal png_init_io() method crashes in Win32 */
45 static void user_read_data(png_structp png_read, png_bytep data, png_size_t length)
46 {
47     FILE *fPtr = (FILE *) png_get_io_ptr(png_read);
48     if (fread(data, 1, length, fPtr) != length)
49         fprintf(stderr, "Failed to read %i bytes from PNG file.\n", (int) length);
50 }
51
52 static void user_write_data(png_structp png_write, png_bytep data, png_size_t length)
53 {
54     FILE *fPtr = (FILE *) png_get_io_ptr(png_write);
55     if (fwrite(data, 1, length, fPtr) != length)
56         fprintf(stderr, "Failed to write %i bytes to PNG file.\n", (int) length);
57 }
58
59 static void user_flush_data(png_structp png_read)
60 {
61     FILE *fPtr = (FILE *) png_get_io_ptr(png_read);
62     fflush(fPtr);
63 }
64
65 /*
66 ReadPNG - Reads the contents of a PNG file and stores the contents into
67     BMGImageStruct
68
69 Inputs:
70     filename    - the name of the file to be opened
71
72 Outputs:
73     img         - the BMGImageStruct containing the image data
74
75 Returns:
76     BMGError - if the file could not be read or a resource error occurred
77     BMG_OK   - if the file was read and the data was stored in img
78
79 Limitations:
80     None.
81
82 Comments:
83     2-bit images are converted to 4-bit images.
84     16-bit images are converted to 8-bit images.
85     gray scale images with alpha components are converted to 32-bit images
86 */
87 BMGError ReadPNG( const char *filename,
88         struct BMGImageStruct * volatile img )
89 {
90     jmp_buf             err_jmp;
91     int                 error;
92
93     FILE * volatile     file = NULL;
94     int                 BitDepth;
95     int                 ColorType;
96     int                 InterlaceType;
97     unsigned char       signature[8];
98     png_structp volatile png_ptr = NULL;
99     png_infop   volatile info_ptr = NULL;
100     png_infop   volatile end_info = NULL;
101     png_color_16       *ImageBackground = NULL;
102     png_bytep           trns = NULL;
103     int                 NumTrans = 0;
104     int                 i, k;
105     png_color_16p       TransColors = NULL;
106     png_uint_32         Width, Height;
107
108     unsigned char      *bits;
109     unsigned char** volatile rows = NULL;
110
111     BMGError tmp;
112
113     /* error handler */
114     error = setjmp( err_jmp );
115     if (error != 0)
116     {
117         if (end_info != NULL)
118             png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info);
119         else if (info_ptr != NULL)
120             png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, NULL);
121         else if (png_ptr != NULL)
122             png_destroy_read_struct((png_structp *) &png_ptr, NULL, NULL);
123         if (rows)
124         {
125             if (rows[0])
126                 free(rows[0]);
127             free(rows);
128         }
129         if (img)
130             FreeBMGImage(img);
131         if (file)
132             fclose(file);
133         SetLastBMGError((BMGError) error);
134         return (BMGError) error;
135     }
136
137     if ( img == NULL )
138         longjmp ( err_jmp, (int)errInvalidBMGImage );
139
140     file = fopen( filename, "rb" );
141     if ( !file || fread( signature, 1, 8, file ) != 8)
142         longjmp ( err_jmp, (int)errFileOpen );
143
144     /* check the signature */
145     if ( png_sig_cmp( signature, 0, 8 ) != 0 )
146         longjmp( err_jmp, (int)errUnsupportedFileFormat );
147
148     /* create a pointer to the png read structure */
149     png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
150     if ( !png_ptr )
151         longjmp( err_jmp, (int)errMemoryAllocation );
152
153     /* create a pointer to the png info structure */
154     info_ptr = png_create_info_struct( png_ptr );
155     if ( !info_ptr )
156         longjmp( err_jmp, (int)errMemoryAllocation );
157
158     /* create a pointer to the png end-info structure */
159     end_info = png_create_info_struct(png_ptr);
160     if (!end_info)
161         longjmp( err_jmp, (int)errMemoryAllocation );
162
163     /* bamboozle the PNG longjmp buffer */
164     /*generic PNG error handler*/
165     /* error will always == 1 which == errLib */
166 //    error = png_setjmp(png_ptr);
167     error = setjmp( png_jmpbuf( png_ptr ) );
168     if ( error > 0 )
169         longjmp( err_jmp, error );
170
171     /* set function pointers in the PNG library, for read callbacks */
172     png_set_read_fn(png_ptr, (png_voidp) file, user_read_data);
173
174     /*let the read functions know that we have already read the 1st 8 bytes */
175     png_set_sig_bytes( png_ptr, 8 );
176
177     /* read all PNG data up to the image data */
178     png_read_info( png_ptr, info_ptr );
179
180     /* extract the data we need to form the HBITMAP from the PNG header */
181     png_get_IHDR( png_ptr, info_ptr, &Width, &Height, &BitDepth, &ColorType,
182         &InterlaceType, NULL, NULL);
183
184     img->width = (unsigned int) Width;
185     img->height = (unsigned int) Height;
186
187     img->bits_per_pixel = (unsigned char)32;
188     img->scan_width = Width * 4;
189
190     /* convert 16-bit images to 8-bit images */
191     if (BitDepth == 16)
192         png_set_strip_16(png_ptr);
193
194     /* These are not really required per Rice format spec,
195      * but is done just in case someone uses them.
196      */
197     /* convert palette color to rgb color */
198     if (ColorType == PNG_COLOR_TYPE_PALETTE) {
199         png_set_palette_to_rgb(png_ptr);
200         ColorType = PNG_COLOR_TYPE_RGB;
201     }
202
203     /* expand 1,2,4 bit gray scale to 8 bit gray scale */
204     if (ColorType == PNG_COLOR_TYPE_GRAY && BitDepth < 8)
205         png_set_expand_gray_1_2_4_to_8(png_ptr);
206
207     /* convert gray scale or gray scale + alpha to rgb color */
208     if (ColorType == PNG_COLOR_TYPE_GRAY ||
209         ColorType == PNG_COLOR_TYPE_GRAY_ALPHA) {
210         png_set_gray_to_rgb(png_ptr);
211         ColorType = PNG_COLOR_TYPE_RGB;
212     }
213
214     /* add alpha channel if any */
215     if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
216         png_set_tRNS_to_alpha(png_ptr);
217         ColorType = PNG_COLOR_TYPE_RGB_ALPHA;
218     }
219
220     /* convert rgb to rgba */
221     if (ColorType == PNG_COLOR_TYPE_RGB) {
222         png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
223         ColorType = PNG_COLOR_TYPE_RGB_ALPHA;
224     }
225
226     png_set_bgr(png_ptr);
227
228     /* set the background color if one is found */
229     if ( png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD) )
230         png_get_bKGD(png_ptr, info_ptr, &ImageBackground);
231
232     /* get the transparent color if one is there */
233     if ( png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS ) )
234         png_get_tRNS( png_ptr, info_ptr, &trns, &NumTrans, &TransColors );
235
236     img->palette_size = (unsigned short)0;
237     img->bytes_per_palette_entry = 4U;
238
239     tmp = AllocateBMGImage( img );
240     if ( tmp != BMG_OK )
241         longjmp( err_jmp, (int)tmp );
242
243     png_read_update_info( png_ptr, info_ptr );
244
245     /* create buffer to read data to */
246     rows = (unsigned char **)malloc(Height*sizeof(unsigned char *));
247     if ( !rows )
248         longjmp( err_jmp, (int)errMemoryAllocation );
249
250     k = png_get_rowbytes( png_ptr, info_ptr );
251     rows[0] = (unsigned char *)malloc( Height*k*sizeof(char));
252     if ( !rows[0] )
253         longjmp( err_jmp, (int)errMemoryAllocation );
254
255     for ( i = 1; i < (int)Height; i++ )
256         rows[i] = rows[i-1] + k;
257
258     /* read the entire image into rows */
259     png_read_image( png_ptr, rows );
260
261     bits = img->bits + (Height - 1) * img->scan_width;
262     for ( i = 0; i < (int)Height; i++ )
263     {
264         memcpy(bits, rows[i], 4*Width);
265         bits -= img->scan_width;
266     }
267
268     free( rows[0] );
269     free( rows );
270     png_read_end( png_ptr, info_ptr );
271     png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info);
272     fclose( file );
273
274     return BMG_OK;
275 }
276
277 BMGError ReadPNGInfo( const char *filename,
278         struct BMGImageStruct * volatile img )
279 {
280     jmp_buf             err_jmp;
281     int                 error;
282
283     FILE * volatile     file = NULL;
284     int                 BitDepth;
285     int                 ColorType;
286     int                 InterlaceType;
287     unsigned char       signature[8];
288     png_structp volatile png_ptr = NULL;
289     png_infop   volatile info_ptr = NULL;
290     png_infop   volatile end_info = NULL;
291     png_uint_32         Width, Height;
292
293     /* error handler */
294     error = setjmp( err_jmp );
295     if (error != 0)
296     {
297         if (end_info != NULL)
298             png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info);
299         else if (info_ptr != NULL)
300             png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, NULL);
301         else if (png_ptr != NULL)
302             png_destroy_read_struct((png_structp *) &png_ptr, NULL, NULL);
303         if (img)
304             FreeBMGImage(img);
305         if (file)
306             fclose(file);
307         SetLastBMGError((BMGError) error);
308         return (BMGError) error;
309     }
310
311     if ( img == NULL )
312         longjmp ( err_jmp, (int)errInvalidBMGImage );
313
314     file = fopen( filename, "rb" );
315     if ( !file || fread( signature, 1, 8, file ) != 8)
316         longjmp ( err_jmp, (int)errFileOpen );
317
318     /* check the signature */
319     if ( png_sig_cmp( signature, 0, 8 ) != 0 )
320         longjmp( err_jmp, (int)errUnsupportedFileFormat );
321
322     /* create a pointer to the png read structure */
323     png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
324     if ( !png_ptr )
325         longjmp( err_jmp, (int)errMemoryAllocation );
326
327     /* create a pointer to the png info structure */
328     info_ptr = png_create_info_struct( png_ptr );
329     if ( !info_ptr )
330         longjmp( err_jmp, (int)errMemoryAllocation );
331
332     /* create a pointer to the png end-info structure */
333     end_info = png_create_info_struct(png_ptr);
334     if (!end_info)
335         longjmp( err_jmp, (int)errMemoryAllocation );
336
337     /* bamboozle the PNG longjmp buffer */
338     /*generic PNG error handler*/
339     /* error will always == 1 which == errLib */
340 //    error = png_setjmp(png_ptr);
341     error = setjmp( png_jmpbuf( png_ptr ) );
342     if ( error > 0 )
343         longjmp( err_jmp, error );
344
345     /* set function pointers in the PNG library, for read callbacks */
346     png_set_read_fn(png_ptr, (png_voidp) file, user_read_data);
347
348     /*let the read functions know that we have already read the 1st 8 bytes */
349     png_set_sig_bytes( png_ptr, 8 );
350
351     /* read all PNG data up to the image data */
352     png_read_info( png_ptr, info_ptr );
353
354     /* extract the data we need to form the HBITMAP from the PNG header */
355     png_get_IHDR( png_ptr, info_ptr, &Width, &Height, &BitDepth, &ColorType,
356         &InterlaceType, NULL, NULL);
357
358     img->width = (unsigned int) Width;
359     img->height = (unsigned int) Height;
360
361     img->bits_per_pixel = (unsigned char)32;
362     img->scan_width = Width * 4;
363
364     img->palette_size = (unsigned short)0;
365     img->bytes_per_palette_entry = 4U;
366     img->bits = NULL;
367
368     png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info);
369     fclose( file );
370
371     return BMG_OK;
372 }
373
374 /*
375 WritePNG - writes the contents of a BMGImageStruct to a PNG file.
376
377 Inputs:
378     filename    - the name of the file to be opened
379     img         - the BMGImageStruct containing the image data
380
381 Returns:
382     0 - if the file could not be written or a resource error occurred
383     1 - if the file was written
384
385 Comments:
386         16-BPP BMG Images are converted to 24-BPP images
387
388 Limitations:
389     Color Type is limited to PNG_COLOR_TYPE_GRAY, PNG_COLOR_TYPE_RGB_ALPHA,
390     PNG_COLOR_TYPE_RGB, & PNG_COLOR_TYPE_PALETTE;
391 */
392 BMGError WritePNG( const char *filename, struct BMGImageStruct img )
393 {
394     jmp_buf     err_jmp;
395     int     error = 0;
396     int     BitDepth = 0;
397     int     ColorType = 0;
398     png_structp png_ptr = NULL;
399     png_infop   info_ptr = NULL;
400     png_colorp  PNGPalette = NULL;
401
402     unsigned char   *bits, *p, *q;
403     unsigned char   **rows = NULL;
404     volatile int GrayScale, NumColors;  // mark as volatile so GCC won't throw warning with -Wclobbered
405
406     int     DIBScanWidth;
407     FILE        *outfile = NULL;
408     int     i;
409     BMGError    tmp;
410
411     /* error handler */
412     error = setjmp( err_jmp );
413     fprintf(stderr,"Writing PNG file %s.\n", filename);
414     if ( error != 0 )
415     {
416         if ( png_ptr != NULL )
417             png_destroy_write_struct( &png_ptr, NULL );
418         if ( rows )
419         {
420             if ( rows[0] )
421             {
422                 free( rows[0] );
423             }
424             free( rows );
425         }
426         if ( PNGPalette )
427             free( PNGPalette );
428         if (outfile)
429         {
430             fclose( outfile );
431         }
432         SetLastBMGError( (BMGError)error );
433         return (BMGError)error;
434     }
435
436     SetLastBMGError( BMG_OK );
437     /* open the file */
438     if ((outfile = fopen(filename, "wb")) == NULL)
439     {
440         fprintf(stderr, "Error opening %s for reading.\n", filename);
441         longjmp( err_jmp, (int)errFileOpen );
442     }
443
444     /* 16 BPP DIBS do not have palettes.  libPNG expects 16 BPP images to have
445     a palette.  To correct this situation we must convert 16 BPP images to
446     24 BPP images before saving the data to the file */
447     if ( img.bits_per_pixel == 16 )
448     {
449         tmp = Convert16to24( &img ); 
450         if (  tmp != BMG_OK )
451             longjmp( err_jmp, (int)tmp );
452     }
453
454     GrayScale = 0;
455     NumColors = 0;
456     if (img.bits_per_pixel <= 8)  // has palette
457     {
458         NumColors = img.palette_size;
459         /* if this is a grayscale image then set the flag and delete the palette*/
460         i = 0;
461         bits = img.palette;
462         while ( i < NumColors && bits[0] == bits[1] && bits[0] == bits[2] )
463         {
464             i++;
465             bits += img.bytes_per_palette_entry;
466         }
467         GrayScale = (i == NumColors);
468     }
469
470     /* dimensions */
471     DIBScanWidth = ( img.width * img.bits_per_pixel + 7 ) / 8;
472
473     /* create the png pointer */
474     png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
475     if ( !png_ptr )
476         longjmp( err_jmp, (int)errMemoryAllocation );
477
478     /* create the info pointer */
479     info_ptr = png_create_info_struct( png_ptr );
480     if ( !info_ptr )
481         longjmp( err_jmp, (int)errMemoryAllocation );
482
483     /* bamboozle the png error handler */
484     /* error will always == 1 which equals errLib */
485 //    error = png_setjmp(png_ptr);
486     error = setjmp( png_jmpbuf( png_ptr ) );
487     if ( error > 0 )
488         longjmp( err_jmp, error );
489
490     /* set function pointers in the PNG library, for write callbacks */
491     png_set_write_fn(png_ptr, (png_voidp) outfile, user_write_data, user_flush_data);
492
493     /* prepare variables needed to create PNG header */
494     BitDepth = img.bits_per_pixel < 8 ? img.bits_per_pixel : 8;
495
496     /* determine color type */
497     if ( GrayScale )
498         ColorType = PNG_COLOR_TYPE_GRAY;
499     else if ( img.bits_per_pixel == 32 )
500         ColorType = PNG_COLOR_TYPE_RGB_ALPHA;
501     else if ( img.bits_per_pixel == 24 )
502         ColorType = PNG_COLOR_TYPE_RGB;
503     else
504         ColorType = PNG_COLOR_TYPE_PALETTE;
505
506     /* create the PNG header */
507     png_set_IHDR( png_ptr, info_ptr, img.width, img.height, BitDepth, ColorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE );
508
509     /* store the palette information if there is any */
510     if ( img.palette != NULL && !GrayScale )
511     {
512         PNGPalette = (png_colorp)png_malloc( png_ptr,
513             NumColors*sizeof(png_color));
514         if ( PNGPalette )
515         {
516             bits = img.palette;
517             for ( i = 0; i < NumColors; i++, bits += img.bytes_per_palette_entry )
518             {
519                 PNGPalette[i].red   = bits[2];
520                 PNGPalette[i].green = bits[1];
521                 PNGPalette[i].blue  = bits[0];
522             }
523             png_set_PLTE( png_ptr, info_ptr, PNGPalette, NumColors );
524         }
525         else
526             longjmp( err_jmp, (int)errMemoryAllocation );
527     }
528
529     /* write the file header information */
530     png_write_info( png_ptr, info_ptr );
531
532     /* create array to store data in */
533     rows = (unsigned char **)malloc(sizeof(unsigned char*));
534     if ( !rows )
535         longjmp( err_jmp, (int)errMemoryAllocation );
536     rows[0] = (unsigned char *)malloc( DIBScanWidth * sizeof(unsigned char));
537     if ( !rows[0] )
538         longjmp( err_jmp, (int)errMemoryAllocation );
539
540 /* point to the bottom row of the DIB data.  DIBs are stored bottom-to-top,
541     PNGs are stored top-to-bottom. */
542     bits = img.bits + (img.height - 1) * img.scan_width;
543
544     /* store bits */
545     for ( i = 0; i < (int)img.height; i++ )
546     {
547         switch ( img.bits_per_pixel )
548         {
549             case 1:
550             case 4:
551             case 8:
552                 memcpy( (void *)rows[0], (void *)bits, DIBScanWidth );
553                 break;
554             case 24:
555                 q = bits;
556                 for ( p = rows[0]; p < rows[0] + DIBScanWidth; p += 3, q += 3 )
557                 {
558                     p[0] = q[2];
559                     p[1] = q[1];
560                     p[2] = q[0];
561                 }
562                 break;
563             case 32:
564                 q = bits;
565                 for ( p = rows[0]; p < rows[0] + DIBScanWidth; p += 4, q += 4 )
566                 {
567                     p[3] = q[3];
568                     p[0] = q[2];
569                     p[1] = q[1];
570                     p[2] = q[0];
571                 }
572                 break;
573         }
574
575         png_write_rows( png_ptr, rows, 1 );
576         bits -= img.scan_width;
577     }
578
579     /* finish writing the rest of the file */
580     png_write_end( png_ptr, info_ptr );
581
582     /* clean up and exit */
583     if ( PNGPalette )
584         free( PNGPalette );
585     free( rows[0] );
586     free( rows );
587     png_destroy_write_struct( &png_ptr, NULL );
588     fclose( outfile );
589
590     return BMG_OK;
591 }
592
593 #ifdef _BMG_LIBPNG_STANDALONE
594 #pragma message ("Creating BMGLibPNG functions")
595
596 #ifdef _WIN32
597 /* saves the contents of an HBITMAP to a file.  returns 1 if successfull,
598                 // 0 otherwise */
599                 BMGError SaveBitmapToPNGFile( HBITMAP hBitmap,      /* bitmap to be saved */
600                 const char *filename) /* name of output file */
601 {
602     struct BMGImageStruct img;
603     char msg[256], ext[4], *period;
604     BMGError out = BMG_OK;
605
606     InitBMGImage( &img );
607
608     /* determine the file type by using the extension */
609     strcpy( msg, filename );
610     period = strrchr( msg, '.' );
611     if ( period != NULL )
612     {
613         period++;
614         strcpy( ext, period );
615         ext[0] = toupper( ext[0] );
616         ext[1] = toupper( ext[1] );
617         ext[2] = toupper( ext[2] );
618         ext[3] = 0;
619     }
620     else
621     {
622         strcat( msg, ".PNG" );
623         strcpy( ext, "PNG" );
624     }
625
626     if ( strcmp( ext, "PNG" ) == 0 )
627     {
628 /* extract data from the bitmap.  We assume that 32 bit images have been
629 // blended with the background (unless this is a DDB - see GetDataFromBitmap
630         // for more details) */
631         out = GetDataFromBitmap( hBitmap, &img, 1 ); 
632         if (  out == BMG_OK )
633         {
634             out = WritePNG( msg, img );
635         }
636         FreeBMGImage( &img );
637     }
638     else
639     {
640         out = errInvalidFileExtension;
641     }
642
643     SetLastBMGError( out );
644     return out;
645 }
646 #endif // _WIN32
647
648 /* Creates an HBITMAP to an image file.  returns an HBITMAP if successfull,
649 // NULL otherwise */
650 HBITMAP CreateBitmapFromPNGFile( const char *filename,
651                 int blend )
652 {
653     char ext[4], msg[256];
654     char *period;
655     BMGError out = BMG_OK;
656     struct BMGImageStruct img;
657     HBITMAP hBitmap = NULL;
658
659     InitBMGImage( &img );
660     img.opt_for_bmp = 1;
661
662     strcpy( msg, filename );
663     period = strrchr( msg, '.' );
664     if ( period != NULL )
665     {
666         period++;
667         strncpy( ext, period, 3 );
668         ext[0] = toupper( ext[0] );
669         ext[1] = toupper( ext[1] );
670         ext[2] = toupper( ext[2] );
671         ext[3] = 0;
672     }
673     else
674     {
675         strcat( msg, ".PNG" );
676         strcpy( ext, "PNG" );
677     }
678
679     if ( strcmp( ext, "PNG" ) == 0 )
680     {
681         out = ReadPNG( msg, &img ); 
682         if (  out == BMG_OK )
683         {
684             hBitmap = CreateBitmapFromData( img, blend );
685         }
686         FreeBMGImage( &img );
687     }
688     else
689     {
690         out = errInvalidFileExtension;
691     }
692
693     SetLastBMGError( out );
694     return hBitmap;
695 }
696
697 #endif
698