PANDORA: Make GLES context compatible with latest driver (FB only, no X11)
[mupen64plus-pandora.git] / source / rice_gles / src / liblinux / pngrw.c
CommitLineData
d07c171f 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 */
45static 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
52static 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
59static 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/*
66ReadPNG - Reads the contents of a PNG file and stores the contents into
67 BMGImageStruct
68
69Inputs:
70 filename - the name of the file to be opened
71
72Outputs:
73 img - the BMGImageStruct containing the image data
74
75Returns:
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
79Limitations:
80 None.
81
82Comments:
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*/
87BMGError 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
277BMGError 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/*
375WritePNG - writes the contents of a BMGImageStruct to a PNG file.
376
377Inputs:
378 filename - the name of the file to be opened
379 img - the BMGImageStruct containing the image data
380
381Returns:
382 0 - if the file could not be written or a resource error occurred
383 1 - if the file was written
384
385Comments:
386 16-BPP BMG Images are converted to 24-BPP images
387
388Limitations:
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*/
392BMGError 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 */
650HBITMAP 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