Files
fs2open.github.com/code/pngutils/pngutils.cpp
T
The_E 2f46cbe8a3 sync to trunk 10046
git-svn-id: svn://svn.icculus.org/fs2open/branches/antipodes@10047 387891d4-d844-0410-90c0-e4c51a9137d3
2013-11-25 18:40:16 +10:00

210 lines
5.7 KiB
C++

#include <stdio.h>
#include <string.h>
#include "png.h"
#include "globalincs/pstypes.h"
#include "pngutils/pngutils.h"
#include "cfile/cfile.h"
#include "bmpman/bmpman.h"
#include "palman/palman.h"
#include "graphics/2d.h"
CFILE *png_file = NULL;
//copy/pasted from libpng
void png_scp_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
{
png_size_t check;
if (png_ptr == NULL)
return;
/* fread() returns 0 on error, so it is OK to store this in a png_size_t
* instead of an int, which is what fread() actually returns.
*/
check = (png_size_t)cfread(data, (png_size_t)1, length, png_file);
if (check != length)
png_error(png_ptr, "Read Error");
}
// Reads header information from the PNG file into the bitmap pointer
//
// filename - name of the PNG bitmap file
// w - (output) width of the bitmap
// h - (output) height of the bitmap
// bpp - (output) bits per pixel of the bitmap
//
// returns - PNG_ERROR_NONE if successful, otherwise error code
//
int png_read_header(const char *real_filename, CFILE *img_cfp, int *w, int *h, int *bpp, ubyte *palette)
{
char filename[MAX_FILENAME_LEN];
png_infop info_ptr;
png_structp png_ptr;
png_file = NULL;
//mprintf(("png_read_header: %s\n", real_filename));
if (img_cfp == NULL) {
strcpy_s( filename, real_filename );
char *p = strchr( filename, '.' );
if ( p )
*p = 0;
strcat_s( filename, ".png" );
png_file = cfopen( filename , "rb" );
if ( !png_file ) {
return PNG_ERROR_READING;
}
} else {
png_file = img_cfp;
}
Assert( png_file != NULL );
if (png_file == NULL)
return PNG_ERROR_READING;
/* Create and initialize the png_struct with the desired error handler
* functions. If you want to use the default stderr and longjump method,
* you can supply NULL for the last three parameters. We also supply the
* the compiler header file version, so that we know if the application
* was compiled with a compatible version of the library. REQUIRED
*/
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL)
{
mprintf(("png_read_header: error creating read struct\n"));
cfclose(png_file);
return PNG_ERROR_READING;
}
/* Allocate/initialize the memory for image information. REQUIRED. */
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL)
{
mprintf(("png_read_header: error creating info struct\n"));
cfclose(png_file);
png_destroy_read_struct(&png_ptr, NULL, NULL);
return PNG_ERROR_READING;
}
if (setjmp(png_jmpbuf(png_ptr)))
{
mprintf(("png_read_header: something went wrong\n"));
/* Free all of the memory associated with the png_ptr and info_ptr */
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
cfclose(png_file);
/* If we get here, we had a problem reading the file */
return PNG_ERROR_READING;
}
png_set_read_fn(png_ptr, &png_file, png_scp_read_data);
png_read_info(png_ptr, info_ptr);
if (w) *w = png_get_image_width(png_ptr, info_ptr);
if (h) *h = png_get_image_height(png_ptr, info_ptr);
// this turns out to be near useless, but meh
if (bpp) *bpp = (png_get_channels(png_ptr, info_ptr) * png_get_bit_depth(png_ptr, info_ptr));
if (img_cfp == NULL) {
cfclose(png_file);
png_file = NULL;
}
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return PNG_ERROR_NONE;
}
// Loads a PNG image
//
// filename - name of the targa file to load
// image_data - allocated storage for the bitmap
//
// returns - true if succesful, false otherwise
//
int png_read_bitmap(const char *real_filename, ubyte *image_data, ubyte *bpp, int dest_size, int cf_type)
{
char filename[MAX_FILENAME_LEN];
png_infop info_ptr;
png_structp png_ptr;
png_bytepp row_pointers;
unsigned int i, len;
png_file = NULL;
strcpy_s( filename, real_filename );
char *p = strchr( filename, '.' );
if ( p ) *p = 0;
strcat_s( filename, ".png" );
png_file = cfopen(filename, "rb", CFILE_NORMAL, cf_type);
if (png_file == NULL)
return PNG_ERROR_READING;
/* Create and initialize the png_struct with the desired error handler
* functions. If you want to use the default stderr and longjump method,
* you can supply NULL for the last three parameters. We also supply the
* the compiler header file version, so that we know if the application
* was compiled with a compatible version of the library. REQUIRED
*/
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL)
{
mprintf(("png_read_bitmap: png_ptr went wrong\n"));
cfclose(png_file);
return PNG_ERROR_READING;
}
/* Allocate/initialize the memory for image information. REQUIRED. */
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL)
{
mprintf(("png_read_bitmap: info_ptr went wrong\n"));
cfclose(png_file);
png_destroy_read_struct(&png_ptr, NULL, NULL);
return PNG_ERROR_READING;
}
if (setjmp(png_jmpbuf(png_ptr)))
{
mprintf(("png_read_bitmap: something went wrong\n"));
/* Free all of the memory associated with the png_ptr and info_ptr */
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
cfclose(png_file);
/* If we get here, we had a problem reading the file */
return PNG_ERROR_READING;
}
png_set_read_fn(png_ptr, &png_file, png_scp_read_data);
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_BGR | PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_STRIP_16, NULL);
len = png_get_rowbytes(png_ptr, info_ptr);
row_pointers = png_get_rows(png_ptr, info_ptr);
if(bpp)
*bpp = (ubyte)(len / png_get_image_width(png_ptr, info_ptr)) << 3;
//copy row data to image
unsigned int height = png_get_image_height(png_ptr, info_ptr);
for (i = 0; i < height; i++) {
memcpy(&image_data[i * len], row_pointers[i], len);
}
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
cfclose(png_file);
return PNG_ERROR_NONE;
}