/*
===========================================================================
Copyright (C) 1999 - 2005, Id Software, Inc.
Copyright (C) 2000 - 2013, Raven Software, Inc.
Copyright (C) 2001 - 2013, Activision, Inc.
Copyright (C) 2005 - 2015, ioquake3 contributors
Copyright (C) 2013 - 2015, OpenJK contributors
This file is part of the OpenJK source code.
OpenJK is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see .
===========================================================================
*/
#include "../server/exe_headers.h"
#include "tr_common.h"
#include
void user_write_data( png_structp png_ptr, png_bytep data, png_size_t length ) {
fileHandle_t fp = *(fileHandle_t*)png_get_io_ptr( png_ptr );
ri.FS_Write( data, length, fp );
}
void user_flush_data( png_structp png_ptr ) {
//TODO: ri->FS_Flush?
}
int RE_SavePNG( const char *filename, byte *buf, size_t width, size_t height, int byteDepth ) {
fileHandle_t fp;
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
unsigned int x, y;
png_byte ** row_pointers = NULL;
/* "status" contains the return value of this function. At first
it is set to a value which means 'failure'. When the routine
has finished its work, it is set to a value which means
'success'. */
int status = -1;
/* The following number is set by trial and error only. I cannot
see where it it is documented in the libpng manual.
*/
int depth = 8;
fp = ri.FS_FOpenFileWrite( filename, qtrue );
if ( !fp ) {
goto fopen_failed;
}
png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) {
goto png_create_write_struct_failed;
}
info_ptr = png_create_info_struct (png_ptr);
if (info_ptr == NULL) {
goto png_create_info_struct_failed;
}
/* Set up error handling. */
if (setjmp (png_jmpbuf (png_ptr))) {
goto png_failure;
}
/* Set image attributes. */
png_set_IHDR (png_ptr,
info_ptr,
width,
height,
depth,
PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
/* Initialize rows of PNG. */
row_pointers = (png_byte **)png_malloc (png_ptr, height * sizeof (png_byte *));
for ( y=0; y RGBA
png_set_add_alpha (png_ptr, 0xff, PNG_FILLER_AFTER);
}
png_read_update_info (png_ptr, info_ptr);
// We always assume there are 4 channels. RGB channels are expanded to RGBA when read.
byte *tempData = (byte *) R_Malloc (width_ * height_ * 4, TAG_TEMP_PNG, qfalse);
if ( !tempData )
{
ri.Printf (PRINT_ERROR, "Could not allocate enough memory to load the image.");
return 0;
}
// Dynamic array of row pointers, with 'height' elements, initialized to NULL.
byte **row_pointers = (byte **) R_Malloc (sizeof (byte *) * height_, TAG_TEMP_PNG, qfalse);
if ( !row_pointers )
{
ri.Printf (PRINT_ERROR, "Could not allocate enough memory to load the image.");
R_Free (tempData);
return 0;
}
// Re-set the jmp so that these new memory allocations can be reclaimed
if ( setjmp (png_jmpbuf (png_ptr)) )
{
R_Free (row_pointers);
R_Free (tempData);
return 0;
}
for ( unsigned int i = 0, j = 0; i < height_; i++, j += 4 )
{
row_pointers[i] = tempData + j * width_;
}
png_read_image (png_ptr, row_pointers);
// Finish reading
png_read_end (png_ptr, NULL);
R_Free (row_pointers);
// Finally assign all the parameters
*data = tempData;
*width = width_;
*height = height_;
return 1;
}
void ReadBytes ( void *dest, size_t len )
{
memcpy (dest, buf + offset, len);
offset += len;
}
private:
char *buf;
size_t offset;
png_structp png_ptr;
png_infop info_ptr;
};
void user_read_data( png_structp png_ptr, png_bytep data, png_size_t length ) {
png_voidp r = png_get_io_ptr (png_ptr);
PNGFileReader *reader = (PNGFileReader *)r;
reader->ReadBytes (data, length);
}
// Loads a PNG image from file.
void LoadPNG ( const char *filename, byte **data, int *width, int *height )
{
char *buf = NULL;
int len = ri.FS_ReadFile (filename, (void **)&buf);
if ( len < 0 || buf == NULL )
{
return;
}
PNGFileReader reader (buf);
reader.Read (data, width, height);
}