/*************************************************************************** img.cpp -- Images manipulation ------------------- created : Tue Aug 17 20:13:08 CEST 1999 copyright : (C) 1999 by Eric Espie email : torcs@free.fr version : $Id: img.cpp,v 1.5 2006/10/29 15:55:33 berniw Exp $ ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /** @file Images manipulation tools. Load and store png images with easy interface. @author Eric Espie @version $Id: img.cpp,v 1.5 2006/10/29 15:55:33 berniw Exp $ @ingroup img */ #ifdef WIN32 #include #endif #include "png.h" #include #include #include #ifdef WIN32 #include #endif static char buf[1024]; #define PNG_BYTES_TO_CHECK 4 /** Load an image from disk to a buffer in RGBA mode. @ingroup img @param filename name of the image to load @param widthp width of the read image @param heightp height of the read image @param screen_gamma gamma correction value @return Pointer on the buffer containing the image
NULL Error */ unsigned char * GfImgReadPng(const char *filename, int *widthp, int *heightp, float screen_gamma) { unsigned char buf[PNG_BYTES_TO_CHECK]; FILE *fp; png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; int bit_depth, color_type, interlace_type; /* png_color_16p image_background; */ double gamma; png_bytep *row_pointers; unsigned char *image_ptr, *cur_ptr; png_uint_32 rowbytes; png_uint_32 i; if ((fp = fopen(filename, "rb")) == NULL) { GfTrace("Can't open file %s\n", filename); return (unsigned char *)NULL; } if (fread(buf, 1, PNG_BYTES_TO_CHECK, fp) != PNG_BYTES_TO_CHECK) { GfTrace("Can't read file %s\n", filename); fclose(fp); return (unsigned char *)NULL; } if (png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK) != 0) { GfTrace("File %s not in png format\n", filename); fclose(fp); return (unsigned char *)NULL; } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, (png_error_ptr)NULL, (png_error_ptr)NULL); if (png_ptr == NULL) { GfTrace("Img Failed to create read_struct\n"); fclose(fp); return (unsigned char *)NULL; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fclose(fp); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return (unsigned char *)NULL; } if (setjmp(png_ptr->jmpbuf)) { /* Free all of the memory associated with the png_ptr and info_ptr */ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(fp); /* If we get here, we had a problem reading the file */ return (unsigned char *)NULL; } png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); *widthp = (int)width; *heightp = (int)height; if (bit_depth == 1 && color_type == PNG_COLOR_TYPE_GRAY) png_set_invert_mono(png_ptr); if (bit_depth == 16) { png_set_swap(png_ptr); png_set_strip_16(png_ptr); } if (bit_depth < 8) { png_set_packing(png_ptr); } if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_expand(png_ptr); } if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { png_set_expand(png_ptr); } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_expand(png_ptr); } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); } if (bit_depth == 8 && color_type == PNG_COLOR_TYPE_RGB) { png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); } if (png_get_gAMA(png_ptr, info_ptr, &gamma)) { png_set_gamma(png_ptr, screen_gamma, gamma); } else { png_set_gamma(png_ptr, screen_gamma, 0.50); } png_read_update_info(png_ptr, info_ptr); rowbytes = png_get_rowbytes(png_ptr, info_ptr); // RGBA expected. if (rowbytes != (4 * width)) { GfTrace("%s bad byte count... %u instead of %u\n", filename, rowbytes, 4 * width); fclose(fp); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return (unsigned char *)NULL; } row_pointers = (png_bytep*)malloc(height * sizeof(png_bytep)); if (row_pointers == NULL) { fclose(fp); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return (unsigned char *)NULL; } image_ptr = (unsigned char *)malloc(height * rowbytes); if (image_ptr == NULL) { fclose(fp); png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return (unsigned char *)NULL; } for (i = 0, cur_ptr = image_ptr + (height - 1) * rowbytes ; i < height; i++, cur_ptr -= rowbytes) { row_pointers[i] = cur_ptr; } png_read_image(png_ptr, row_pointers); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); free(row_pointers); fclose(fp); return image_ptr; } /** Write a buffer to a png image on disk. @ingroup img @param img image data (RGB) @param filename filename of the png file @param width width of the image @param height height of the image @return 0 Ok
-1 Error */ int GfImgWritePng(unsigned char *img, const char *filename, int width, int height) { FILE *fp; png_structp png_ptr; png_infop info_ptr; png_bytep *row_pointers; png_uint_32 rowbytes; int i; unsigned char *cur_ptr; #if 0 void *handle; #endif float screen_gamma; fp = fopen(filename, "wb"); if (fp == NULL) { GfTrace("Can't open file %s\n", filename); return -1; } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, (png_error_ptr)NULL, (png_error_ptr)NULL); if (png_ptr == NULL) { return -1; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); return -1; } if (setjmp(png_ptr->jmpbuf)) { png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); return -1; } png_init_io(png_ptr, fp); png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); #if 0 handle = GfParmReadFile(GFSCR_CONF_FILE, GFPARM_RMODE_STD | GFPARM_RMODE_CREAT); screen_gamma = (float)GfParmGetNum(handle, GFSCR_SECT_PROP, GFSCR_ATT_GAMMA, (char*)NULL, 2.0); GfParmReleaseHandle(handle); #else screen_gamma = 2.0; #endif png_set_gAMA(png_ptr, info_ptr, screen_gamma); /* png_set_bgr(png_ptr); TO INVERT THE COLORS !!!! */ png_write_info(png_ptr, info_ptr); png_write_flush(png_ptr); rowbytes = width * 3; row_pointers = (png_bytep*)malloc(height * sizeof(png_bytep)); if (row_pointers == NULL) { fclose(fp); png_destroy_write_struct(&png_ptr, &info_ptr); return -1; } for (i = 0, cur_ptr = img + (height - 1) * rowbytes ; i < height; i++, cur_ptr -= rowbytes) { row_pointers[i] = cur_ptr; } png_write_image(png_ptr, row_pointers); png_write_end(png_ptr, (png_infop)NULL); png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); free(row_pointers); return 0; } /** Free the texture @ingroup img @param tex texture to free @return none */ void GfImgFreeTex(GLuint tex) { if (tex != 0) { glDeleteTextures(1, &tex); } } /** Read a png image into a texture. @ingroup img @param filename file name of the image @return None. */ GLuint GfImgReadTex(char *filename) { void *handle; float screen_gamma; GLbyte *tex; int w, h; GLuint retTex; sprintf(buf, "%s%s", GetLocalDir(), GFSCR_CONF_FILE); handle = GfParmReadFile(buf, GFPARM_RMODE_STD | GFPARM_RMODE_CREAT); screen_gamma = (float)GfParmGetNum(handle, GFSCR_SECT_PROP, GFSCR_ATT_GAMMA, (char*)NULL, 2.0); tex = (GLbyte*)GfImgReadPng(filename, &w, &h, screen_gamma); if (!tex) { GfParmReleaseHandle(handle); return 0; } glGenTextures(1, &retTex); glBindTexture(GL_TEXTURE_2D, retTex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *)(tex)); free(tex); GfParmReleaseHandle(handle); return retTex; }