Rice Video Plugin for GLES1.1
[mupen64plus-pandora.git] / source / rice_gles / src / liblinux / pngrw.c
diff --git a/source/rice_gles/src/liblinux/pngrw.c b/source/rice_gles/src/liblinux/pngrw.c
new file mode 100644 (file)
index 0000000..f9a3b86
--- /dev/null
@@ -0,0 +1,698 @@
+/*
+//  source code for the ImageLib PNG functions
+//
+//  Copyright (C) 2001 M. Scott Heiman
+//  All Rights Reserved
+//
+// You may use the software for any purpose you see fit. You may modify
+// it, incorporate it in a commercial application, use it for school,
+// even turn it in as homework. You must keep the Copyright in the
+// header and source files. This software is not in the "Public Domain".
+// You may use this software at your own risk. I have made a reasonable
+// effort to verify that this software works in the manner I expect it to;
+// however,...
+//
+// THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" AND
+// WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, INCLUDING
+// WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A
+// PARTICULAR PURPOSE. IN NO EVENT SHALL MICHAEL S. HEIMAN BE LIABLE TO
+// YOU OR ANYONE ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR
+// CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING
+// WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE,
+// OR THE CLAIMS OF THIRD PARTIES, WHETHER OR NOT MICHAEL S. HEIMAN HAS
+// BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+// ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+// POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include "BMGUtils.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef _BMG_LIBPNG_STANDALONE
+#include "BMGLibPNG.h"
+#else
+#include "pngrw.h"
+#endif
+#include <png.h>
+
+#ifndef png_jmpbuf
+#  define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
+#endif
+
+
+/* this stuff is necessary because the normal png_init_io() method crashes in Win32 */
+static void user_read_data(png_structp png_read, png_bytep data, png_size_t length)
+{
+    FILE *fPtr = (FILE *) png_get_io_ptr(png_read);
+    if (fread(data, 1, length, fPtr) != length)
+        fprintf(stderr, "Failed to read %i bytes from PNG file.\n", (int) length);
+}
+
+static void user_write_data(png_structp png_write, png_bytep data, png_size_t length)
+{
+    FILE *fPtr = (FILE *) png_get_io_ptr(png_write);
+    if (fwrite(data, 1, length, fPtr) != length)
+        fprintf(stderr, "Failed to write %i bytes to PNG file.\n", (int) length);
+}
+
+static void user_flush_data(png_structp png_read)
+{
+    FILE *fPtr = (FILE *) png_get_io_ptr(png_read);
+    fflush(fPtr);
+}
+
+/*
+ReadPNG - Reads the contents of a PNG file and stores the contents into
+    BMGImageStruct
+
+Inputs:
+    filename    - the name of the file to be opened
+
+Outputs:
+    img         - the BMGImageStruct containing the image data
+
+Returns:
+    BMGError - if the file could not be read or a resource error occurred
+    BMG_OK   - if the file was read and the data was stored in img
+
+Limitations:
+    None.
+
+Comments:
+    2-bit images are converted to 4-bit images.
+    16-bit images are converted to 8-bit images.
+    gray scale images with alpha components are converted to 32-bit images
+*/
+BMGError ReadPNG( const char *filename,
+        struct BMGImageStruct * volatile img )
+{
+    jmp_buf             err_jmp;
+    int                 error;
+
+    FILE * volatile     file = NULL;
+    int                 BitDepth;
+    int                 ColorType;
+    int                 InterlaceType;
+    unsigned char       signature[8];
+    png_structp volatile png_ptr = NULL;
+    png_infop   volatile info_ptr = NULL;
+    png_infop   volatile end_info = NULL;
+    png_color_16       *ImageBackground = NULL;
+    png_bytep           trns = NULL;
+    int                 NumTrans = 0;
+    int                 i, k;
+    png_color_16p       TransColors = NULL;
+    png_uint_32         Width, Height;
+
+    unsigned char      *bits;
+    unsigned char** volatile rows = NULL;
+
+    BMGError tmp;
+
+    /* error handler */
+    error = setjmp( err_jmp );
+    if (error != 0)
+    {
+        if (end_info != NULL)
+            png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info);
+        else if (info_ptr != NULL)
+            png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, NULL);
+        else if (png_ptr != NULL)
+            png_destroy_read_struct((png_structp *) &png_ptr, NULL, NULL);
+        if (rows)
+        {
+            if (rows[0])
+                free(rows[0]);
+            free(rows);
+        }
+        if (img)
+            FreeBMGImage(img);
+        if (file)
+            fclose(file);
+        SetLastBMGError((BMGError) error);
+        return (BMGError) error;
+    }
+
+    if ( img == NULL )
+        longjmp ( err_jmp, (int)errInvalidBMGImage );
+
+    file = fopen( filename, "rb" );
+    if ( !file || fread( signature, 1, 8, file ) != 8)
+        longjmp ( err_jmp, (int)errFileOpen );
+
+    /* check the signature */
+    if ( png_sig_cmp( signature, 0, 8 ) != 0 )
+        longjmp( err_jmp, (int)errUnsupportedFileFormat );
+
+    /* create a pointer to the png read structure */
+    png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
+    if ( !png_ptr )
+        longjmp( err_jmp, (int)errMemoryAllocation );
+
+    /* create a pointer to the png info structure */
+    info_ptr = png_create_info_struct( png_ptr );
+    if ( !info_ptr )
+        longjmp( err_jmp, (int)errMemoryAllocation );
+
+    /* create a pointer to the png end-info structure */
+    end_info = png_create_info_struct(png_ptr);
+    if (!end_info)
+        longjmp( err_jmp, (int)errMemoryAllocation );
+
+    /* bamboozle the PNG longjmp buffer */
+    /*generic PNG error handler*/
+    /* error will always == 1 which == errLib */
+//    error = png_setjmp(png_ptr);
+    error = setjmp( png_jmpbuf( png_ptr ) );
+    if ( error > 0 )
+        longjmp( err_jmp, error );
+
+    /* set function pointers in the PNG library, for read callbacks */
+    png_set_read_fn(png_ptr, (png_voidp) file, user_read_data);
+
+    /*let the read functions know that we have already read the 1st 8 bytes */
+    png_set_sig_bytes( png_ptr, 8 );
+
+    /* read all PNG data up to the image data */
+    png_read_info( png_ptr, info_ptr );
+
+    /* extract the data we need to form the HBITMAP from the PNG header */
+    png_get_IHDR( png_ptr, info_ptr, &Width, &Height, &BitDepth, &ColorType,
+        &InterlaceType, NULL, NULL);
+
+    img->width = (unsigned int) Width;
+    img->height = (unsigned int) Height;
+
+    img->bits_per_pixel = (unsigned char)32;
+    img->scan_width = Width * 4;
+
+    /* convert 16-bit images to 8-bit images */
+    if (BitDepth == 16)
+        png_set_strip_16(png_ptr);
+
+    /* These are not really required per Rice format spec,
+     * but is done just in case someone uses them.
+     */
+    /* convert palette color to rgb color */
+    if (ColorType == PNG_COLOR_TYPE_PALETTE) {
+        png_set_palette_to_rgb(png_ptr);
+        ColorType = PNG_COLOR_TYPE_RGB;
+    }
+
+    /* expand 1,2,4 bit gray scale to 8 bit gray scale */
+    if (ColorType == PNG_COLOR_TYPE_GRAY && BitDepth < 8)
+        png_set_expand_gray_1_2_4_to_8(png_ptr);
+
+    /* convert gray scale or gray scale + alpha to rgb color */
+    if (ColorType == PNG_COLOR_TYPE_GRAY ||
+        ColorType == PNG_COLOR_TYPE_GRAY_ALPHA) {
+        png_set_gray_to_rgb(png_ptr);
+        ColorType = PNG_COLOR_TYPE_RGB;
+    }
+
+    /* add alpha channel if any */
+    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
+        png_set_tRNS_to_alpha(png_ptr);
+        ColorType = PNG_COLOR_TYPE_RGB_ALPHA;
+    }
+
+    /* convert rgb to rgba */
+    if (ColorType == PNG_COLOR_TYPE_RGB) {
+        png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
+        ColorType = PNG_COLOR_TYPE_RGB_ALPHA;
+    }
+
+    png_set_bgr(png_ptr);
+
+    /* set the background color if one is found */
+    if ( png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD) )
+        png_get_bKGD(png_ptr, info_ptr, &ImageBackground);
+
+    /* get the transparent color if one is there */
+    if ( png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS ) )
+        png_get_tRNS( png_ptr, info_ptr, &trns, &NumTrans, &TransColors );
+
+    img->palette_size = (unsigned short)0;
+    img->bytes_per_palette_entry = 4U;
+
+    tmp = AllocateBMGImage( img );
+    if ( tmp != BMG_OK )
+        longjmp( err_jmp, (int)tmp );
+
+    png_read_update_info( png_ptr, info_ptr );
+
+    /* create buffer to read data to */
+    rows = (unsigned char **)malloc(Height*sizeof(unsigned char *));
+    if ( !rows )
+        longjmp( err_jmp, (int)errMemoryAllocation );
+
+    k = png_get_rowbytes( png_ptr, info_ptr );
+    rows[0] = (unsigned char *)malloc( Height*k*sizeof(char));
+    if ( !rows[0] )
+        longjmp( err_jmp, (int)errMemoryAllocation );
+
+    for ( i = 1; i < (int)Height; i++ )
+        rows[i] = rows[i-1] + k;
+
+    /* read the entire image into rows */
+    png_read_image( png_ptr, rows );
+
+    bits = img->bits + (Height - 1) * img->scan_width;
+    for ( i = 0; i < (int)Height; i++ )
+    {
+        memcpy(bits, rows[i], 4*Width);
+        bits -= img->scan_width;
+    }
+
+    free( rows[0] );
+    free( rows );
+    png_read_end( png_ptr, info_ptr );
+    png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info);
+    fclose( file );
+
+    return BMG_OK;
+}
+
+BMGError ReadPNGInfo( const char *filename,
+        struct BMGImageStruct * volatile img )
+{
+    jmp_buf             err_jmp;
+    int                 error;
+
+    FILE * volatile     file = NULL;
+    int                 BitDepth;
+    int                 ColorType;
+    int                 InterlaceType;
+    unsigned char       signature[8];
+    png_structp volatile png_ptr = NULL;
+    png_infop   volatile info_ptr = NULL;
+    png_infop   volatile end_info = NULL;
+    png_uint_32         Width, Height;
+
+    /* error handler */
+    error = setjmp( err_jmp );
+    if (error != 0)
+    {
+        if (end_info != NULL)
+            png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info);
+        else if (info_ptr != NULL)
+            png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, NULL);
+        else if (png_ptr != NULL)
+            png_destroy_read_struct((png_structp *) &png_ptr, NULL, NULL);
+        if (img)
+            FreeBMGImage(img);
+        if (file)
+            fclose(file);
+        SetLastBMGError((BMGError) error);
+        return (BMGError) error;
+    }
+
+    if ( img == NULL )
+        longjmp ( err_jmp, (int)errInvalidBMGImage );
+
+    file = fopen( filename, "rb" );
+    if ( !file || fread( signature, 1, 8, file ) != 8)
+        longjmp ( err_jmp, (int)errFileOpen );
+
+    /* check the signature */
+    if ( png_sig_cmp( signature, 0, 8 ) != 0 )
+        longjmp( err_jmp, (int)errUnsupportedFileFormat );
+
+    /* create a pointer to the png read structure */
+    png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
+    if ( !png_ptr )
+        longjmp( err_jmp, (int)errMemoryAllocation );
+
+    /* create a pointer to the png info structure */
+    info_ptr = png_create_info_struct( png_ptr );
+    if ( !info_ptr )
+        longjmp( err_jmp, (int)errMemoryAllocation );
+
+    /* create a pointer to the png end-info structure */
+    end_info = png_create_info_struct(png_ptr);
+    if (!end_info)
+        longjmp( err_jmp, (int)errMemoryAllocation );
+
+    /* bamboozle the PNG longjmp buffer */
+    /*generic PNG error handler*/
+    /* error will always == 1 which == errLib */
+//    error = png_setjmp(png_ptr);
+    error = setjmp( png_jmpbuf( png_ptr ) );
+    if ( error > 0 )
+        longjmp( err_jmp, error );
+
+    /* set function pointers in the PNG library, for read callbacks */
+    png_set_read_fn(png_ptr, (png_voidp) file, user_read_data);
+
+    /*let the read functions know that we have already read the 1st 8 bytes */
+    png_set_sig_bytes( png_ptr, 8 );
+
+    /* read all PNG data up to the image data */
+    png_read_info( png_ptr, info_ptr );
+
+    /* extract the data we need to form the HBITMAP from the PNG header */
+    png_get_IHDR( png_ptr, info_ptr, &Width, &Height, &BitDepth, &ColorType,
+        &InterlaceType, NULL, NULL);
+
+    img->width = (unsigned int) Width;
+    img->height = (unsigned int) Height;
+
+    img->bits_per_pixel = (unsigned char)32;
+    img->scan_width = Width * 4;
+
+    img->palette_size = (unsigned short)0;
+    img->bytes_per_palette_entry = 4U;
+    img->bits = NULL;
+
+    png_destroy_read_struct((png_structp *) &png_ptr, (png_infop *) &info_ptr, (png_infop *) &end_info);
+    fclose( file );
+
+    return BMG_OK;
+}
+
+/*
+WritePNG - writes the contents of a BMGImageStruct to a PNG file.
+
+Inputs:
+    filename    - the name of the file to be opened
+    img         - the BMGImageStruct containing the image data
+
+Returns:
+    0 - if the file could not be written or a resource error occurred
+    1 - if the file was written
+
+Comments:
+        16-BPP BMG Images are converted to 24-BPP images
+
+Limitations:
+    Color Type is limited to PNG_COLOR_TYPE_GRAY, PNG_COLOR_TYPE_RGB_ALPHA,
+    PNG_COLOR_TYPE_RGB, & PNG_COLOR_TYPE_PALETTE;
+*/
+BMGError WritePNG( const char *filename, struct BMGImageStruct img )
+{
+    jmp_buf     err_jmp;
+    int     error = 0;
+    int     BitDepth = 0;
+    int     ColorType = 0;
+    png_structp png_ptr = NULL;
+    png_infop   info_ptr = NULL;
+    png_colorp  PNGPalette = NULL;
+
+    unsigned char   *bits, *p, *q;
+    unsigned char   **rows = NULL;
+    volatile int GrayScale, NumColors;  // mark as volatile so GCC won't throw warning with -Wclobbered
+
+    int     DIBScanWidth;
+    FILE        *outfile = NULL;
+    int     i;
+    BMGError    tmp;
+
+    /* error handler */
+    error = setjmp( err_jmp );
+    fprintf(stderr,"Writing PNG file %s.\n", filename);
+    if ( error != 0 )
+    {
+        if ( png_ptr != NULL )
+            png_destroy_write_struct( &png_ptr, NULL );
+        if ( rows )
+        {
+            if ( rows[0] )
+            {
+                free( rows[0] );
+            }
+            free( rows );
+        }
+        if ( PNGPalette )
+            free( PNGPalette );
+        if (outfile)
+        {
+            fclose( outfile );
+        }
+        SetLastBMGError( (BMGError)error );
+        return (BMGError)error;
+    }
+
+    SetLastBMGError( BMG_OK );
+    /* open the file */
+    if ((outfile = fopen(filename, "wb")) == NULL)
+    {
+        fprintf(stderr, "Error opening %s for reading.\n", filename);
+        longjmp( err_jmp, (int)errFileOpen );
+    }
+
+    /* 16 BPP DIBS do not have palettes.  libPNG expects 16 BPP images to have
+    a palette.  To correct this situation we must convert 16 BPP images to
+    24 BPP images before saving the data to the file */
+    if ( img.bits_per_pixel == 16 )
+    {
+        tmp = Convert16to24( &img ); 
+        if (  tmp != BMG_OK )
+            longjmp( err_jmp, (int)tmp );
+    }
+
+    GrayScale = 0;
+    NumColors = 0;
+    if (img.bits_per_pixel <= 8)  // has palette
+    {
+        NumColors = img.palette_size;
+        /* if this is a grayscale image then set the flag and delete the palette*/
+        i = 0;
+        bits = img.palette;
+        while ( i < NumColors && bits[0] == bits[1] && bits[0] == bits[2] )
+        {
+            i++;
+            bits += img.bytes_per_palette_entry;
+        }
+        GrayScale = (i == NumColors);
+    }
+
+    /* dimensions */
+    DIBScanWidth = ( img.width * img.bits_per_pixel + 7 ) / 8;
+
+    /* create the png pointer */
+    png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+    if ( !png_ptr )
+        longjmp( err_jmp, (int)errMemoryAllocation );
+
+    /* create the info pointer */
+    info_ptr = png_create_info_struct( png_ptr );
+    if ( !info_ptr )
+        longjmp( err_jmp, (int)errMemoryAllocation );
+
+    /* bamboozle the png error handler */
+    /* error will always == 1 which equals errLib */
+//    error = png_setjmp(png_ptr);
+    error = setjmp( png_jmpbuf( png_ptr ) );
+    if ( error > 0 )
+        longjmp( err_jmp, error );
+
+    /* set function pointers in the PNG library, for write callbacks */
+    png_set_write_fn(png_ptr, (png_voidp) outfile, user_write_data, user_flush_data);
+
+    /* prepare variables needed to create PNG header */
+    BitDepth = img.bits_per_pixel < 8 ? img.bits_per_pixel : 8;
+
+    /* determine color type */
+    if ( GrayScale )
+        ColorType = PNG_COLOR_TYPE_GRAY;
+    else if ( img.bits_per_pixel == 32 )
+        ColorType = PNG_COLOR_TYPE_RGB_ALPHA;
+    else if ( img.bits_per_pixel == 24 )
+        ColorType = PNG_COLOR_TYPE_RGB;
+    else
+        ColorType = PNG_COLOR_TYPE_PALETTE;
+
+    /* create the PNG header */
+    png_set_IHDR( png_ptr, info_ptr, img.width, img.height, BitDepth, ColorType, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE );
+
+    /* store the palette information if there is any */
+    if ( img.palette != NULL && !GrayScale )
+    {
+        PNGPalette = (png_colorp)png_malloc( png_ptr,
+            NumColors*sizeof(png_color));
+        if ( PNGPalette )
+        {
+            bits = img.palette;
+            for ( i = 0; i < NumColors; i++, bits += img.bytes_per_palette_entry )
+            {
+                PNGPalette[i].red   = bits[2];
+                PNGPalette[i].green = bits[1];
+                PNGPalette[i].blue  = bits[0];
+            }
+            png_set_PLTE( png_ptr, info_ptr, PNGPalette, NumColors );
+        }
+        else
+            longjmp( err_jmp, (int)errMemoryAllocation );
+    }
+
+    /* write the file header information */
+    png_write_info( png_ptr, info_ptr );
+
+    /* create array to store data in */
+    rows = (unsigned char **)malloc(sizeof(unsigned char*));
+    if ( !rows )
+        longjmp( err_jmp, (int)errMemoryAllocation );
+    rows[0] = (unsigned char *)malloc( DIBScanWidth * sizeof(unsigned char));
+    if ( !rows[0] )
+        longjmp( err_jmp, (int)errMemoryAllocation );
+
+/* point to the bottom row of the DIB data.  DIBs are stored bottom-to-top,
+    PNGs are stored top-to-bottom. */
+    bits = img.bits + (img.height - 1) * img.scan_width;
+
+    /* store bits */
+    for ( i = 0; i < (int)img.height; i++ )
+    {
+        switch ( img.bits_per_pixel )
+        {
+            case 1:
+            case 4:
+            case 8:
+                memcpy( (void *)rows[0], (void *)bits, DIBScanWidth );
+                break;
+            case 24:
+                q = bits;
+                for ( p = rows[0]; p < rows[0] + DIBScanWidth; p += 3, q += 3 )
+                {
+                    p[0] = q[2];
+                    p[1] = q[1];
+                    p[2] = q[0];
+                }
+                break;
+            case 32:
+                q = bits;
+                for ( p = rows[0]; p < rows[0] + DIBScanWidth; p += 4, q += 4 )
+                {
+                    p[3] = q[3];
+                    p[0] = q[2];
+                    p[1] = q[1];
+                    p[2] = q[0];
+                }
+                break;
+        }
+
+        png_write_rows( png_ptr, rows, 1 );
+        bits -= img.scan_width;
+    }
+
+    /* finish writing the rest of the file */
+    png_write_end( png_ptr, info_ptr );
+
+    /* clean up and exit */
+    if ( PNGPalette )
+        free( PNGPalette );
+    free( rows[0] );
+    free( rows );
+    png_destroy_write_struct( &png_ptr, NULL );
+    fclose( outfile );
+
+    return BMG_OK;
+}
+
+#ifdef _BMG_LIBPNG_STANDALONE
+#pragma message ("Creating BMGLibPNG functions")
+
+#ifdef _WIN32
+/* saves the contents of an HBITMAP to a file.  returns 1 if successfull,
+                // 0 otherwise */
+                BMGError SaveBitmapToPNGFile( HBITMAP hBitmap,      /* bitmap to be saved */
+                const char *filename) /* name of output file */
+{
+    struct BMGImageStruct img;
+    char msg[256], ext[4], *period;
+    BMGError out = BMG_OK;
+
+    InitBMGImage( &img );
+
+    /* determine the file type by using the extension */
+    strcpy( msg, filename );
+    period = strrchr( msg, '.' );
+    if ( period != NULL )
+    {
+        period++;
+        strcpy( ext, period );
+        ext[0] = toupper( ext[0] );
+        ext[1] = toupper( ext[1] );
+        ext[2] = toupper( ext[2] );
+        ext[3] = 0;
+    }
+    else
+    {
+        strcat( msg, ".PNG" );
+        strcpy( ext, "PNG" );
+    }
+
+    if ( strcmp( ext, "PNG" ) == 0 )
+    {
+/* extract data from the bitmap.  We assume that 32 bit images have been
+// blended with the background (unless this is a DDB - see GetDataFromBitmap
+        // for more details) */
+        out = GetDataFromBitmap( hBitmap, &img, 1 ); 
+        if (  out == BMG_OK )
+        {
+            out = WritePNG( msg, img );
+        }
+        FreeBMGImage( &img );
+    }
+    else
+    {
+        out = errInvalidFileExtension;
+    }
+
+    SetLastBMGError( out );
+    return out;
+}
+#endif // _WIN32
+
+/* Creates an HBITMAP to an image file.  returns an HBITMAP if successfull,
+// NULL otherwise */
+HBITMAP CreateBitmapFromPNGFile( const char *filename,
+                int blend )
+{
+    char ext[4], msg[256];
+    char *period;
+    BMGError out = BMG_OK;
+    struct BMGImageStruct img;
+    HBITMAP hBitmap = NULL;
+
+    InitBMGImage( &img );
+    img.opt_for_bmp = 1;
+
+    strcpy( msg, filename );
+    period = strrchr( msg, '.' );
+    if ( period != NULL )
+    {
+        period++;
+        strncpy( ext, period, 3 );
+        ext[0] = toupper( ext[0] );
+        ext[1] = toupper( ext[1] );
+        ext[2] = toupper( ext[2] );
+        ext[3] = 0;
+    }
+    else
+    {
+        strcat( msg, ".PNG" );
+        strcpy( ext, "PNG" );
+    }
+
+    if ( strcmp( ext, "PNG" ) == 0 )
+    {
+        out = ReadPNG( msg, &img ); 
+        if (  out == BMG_OK )
+        {
+            hBitmap = CreateBitmapFromData( img, blend );
+        }
+        FreeBMGImage( &img );
+    }
+    else
+    {
+        out = errInvalidFileExtension;
+    }
+
+    SetLastBMGError( out );
+    return hBitmap;
+}
+
+#endif
+