/* =========================================================================== 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); }