/* * gtkatlantic - the gtk+ monopd client, enjoy network monopoly games * * * Copyright (C) 2002-2004 Rochet Sylvain * * gtkatlantic 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. * * 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include "readpng.h" gboolean readpng_init(FILE *infile, png_structp *png_struct, png_infop *png_info, _png_imagedata *png_imagedata) { guchar sig[8]; png_uint_32 width, height; fread(sig, 1, 8, infile); if (!png_check_sig(sig, 8)) return FALSE; *png_struct = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_struct) return FALSE; *png_info = png_create_info_struct(*png_struct); if (!*png_info) { png_destroy_read_struct(png_struct, NULL, NULL); return FALSE; } if (setjmp(png_jmpbuf(*png_struct))) { png_destroy_read_struct(png_struct, png_info, NULL); return FALSE; } png_init_io(*png_struct, infile); png_set_sig_bytes(*png_struct, 8); png_read_info(*png_struct, *png_info); png_get_IHDR(*png_struct, *png_info, &width, &height, &png_imagedata->bit_depth, &png_imagedata->color_type, NULL, NULL, NULL); png_imagedata->width = width; png_imagedata->height = height; if (png_imagedata->color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(*png_struct); if (png_imagedata->color_type == PNG_COLOR_TYPE_GRAY && png_imagedata->bit_depth < 8) png_set_expand(*png_struct); if (png_get_valid(*png_struct, *png_info, PNG_INFO_tRNS)) png_set_expand(*png_struct); if (png_imagedata->bit_depth == 16) png_set_strip_16(*png_struct); if (png_imagedata->color_type == PNG_COLOR_TYPE_GRAY || png_imagedata->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(*png_struct); png_read_update_info(*png_struct, *png_info); png_imagedata->rowbytes = png_get_rowbytes(*png_struct, *png_info); png_imagedata->channels = (int)png_get_channels(*png_struct, *png_info); if (png_imagedata->channels != 3 && png_imagedata->channels != 4) { png_destroy_read_struct(png_struct, png_info, NULL); return FALSE; } png_imagedata->size = png_imagedata->width * png_imagedata->height * png_imagedata->channels; png_imagedata->size_image = png_imagedata->width * png_imagedata->height * 3; if(png_imagedata->channels == 4) { /* image with alpha channel */ png_imagedata->size_alpha = png_imagedata->width * png_imagedata->height; png_imagedata->have_alpha = TRUE; } else { png_imagedata->size_alpha = 0; png_imagedata->have_alpha = FALSE; } png_imagedata->nb_pixel = png_imagedata->width * png_imagedata->height; png_imagedata->available_alpha = FALSE; png_imagedata->image_allocated = FALSE; png_imagedata->alpha_allocated = FALSE; png_imagedata->image_need = FALSE; png_imagedata->alpha_need = FALSE; return TRUE; } gboolean readpng_decode_image(png_structp *png_struct, png_infop *png_info, _png_imagedata *png_imagedata, gboolean get_alpha) { guint32 i; png_bytepp row_pointers = NULL; guchar *tmp, *ptr_image, *ptr_alpha, *ptr_in; if (setjmp(png_jmpbuf(*png_struct))) { png_destroy_read_struct(png_struct, png_info, NULL); return FALSE; } if( ( row_pointers = (png_bytepp)g_malloc0(png_imagedata->height * sizeof(png_bytep)) ) == NULL) return FALSE; tmp = g_malloc0(png_imagedata->size); for (i = 0; i < png_imagedata->height; ++i) row_pointers[i] = tmp + i * png_imagedata->rowbytes; png_read_image(*png_struct, row_pointers); g_free(row_pointers); row_pointers = NULL; png_read_end(*png_struct, NULL); png_imagedata->image = g_malloc0(png_imagedata->size_image); png_imagedata->image_allocated = TRUE; if(!png_imagedata->have_alpha) memcpy(png_imagedata->image, tmp, png_imagedata->size_image); else if(png_imagedata->have_alpha && get_alpha) { png_imagedata->alpha = g_malloc0(png_imagedata->size_alpha); png_imagedata->alpha_allocated = TRUE; png_imagedata->available_alpha = TRUE; ptr_in = tmp; ptr_image = png_imagedata->image; ptr_alpha = png_imagedata->alpha; for(i = 1 ; i <= png_imagedata->size ; i++) { if(i % 4) *ptr_image++ = *ptr_in++; else *ptr_alpha++ = *ptr_in++; } } else if(png_imagedata->have_alpha && !get_alpha) { ptr_in = tmp; ptr_image = png_imagedata->image; for(i = 1 ; i <= png_imagedata->size ; i++) { if(i % 4) *ptr_image++ = *ptr_in++; else ptr_in++; } } g_free(tmp); return TRUE; } guchar *readpng_get_image(_png_imagedata *png_imagedata) { if(!png_imagedata->image_allocated) return NULL; png_imagedata->image_need = TRUE; return png_imagedata->image; } guchar *readpng_get_alpha(_png_imagedata *png_imagedata) { if(!png_imagedata->alpha_allocated) return NULL; png_imagedata->alpha_need = TRUE; return png_imagedata->alpha; } guchar *readpng_get_image_zone(_png_imagedata *png_imagedata, guint16 x, guint16 y, guint16 width, guint16 height) { guint32 i; if(x + width > png_imagedata->width) return NULL; if(y + height > png_imagedata->height) return NULL; png_imagedata->part_image = g_malloc0(width * height * 3); for(i = 0 ; i < height ; i++) { memcpy(png_imagedata->part_image + i * width * 3, png_imagedata->image + ((y + i) * png_imagedata->width + x) * 3, width * 3); } return png_imagedata->part_image; } guchar *readpng_get_alpha_zone(_png_imagedata *png_imagedata, guint16 x, guint16 y, guint16 width, guint16 height) { guint32 i; if(x + width > png_imagedata->width) return NULL; if(y + height > png_imagedata->height) return NULL; png_imagedata->part_alpha = g_malloc0(width * height); for(i = 0 ; i < height ; i++) { memcpy(png_imagedata->part_alpha + i * width, png_imagedata->alpha + (y + i) * png_imagedata->width + x, width); } return png_imagedata->part_alpha; } void readpng_cleanup(png_structp *png_struct, png_infop *png_info, _png_imagedata *png_imagedata) { if(png_imagedata->image_allocated && ! png_imagedata->image_need) g_free(png_imagedata->image); if(png_imagedata->alpha_allocated && ! png_imagedata->alpha_need) g_free(png_imagedata->alpha); if (png_struct && png_info) { png_destroy_read_struct(png_struct, png_info, NULL); *png_struct = NULL; *png_info = NULL; } }