Logo Search packages:      
Sourcecode: gtkatlantic version File versions

readpng.c

/*
 *     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 <stdio.h>
#include <stdlib.h>
#include <glib.h>

#include <png.h>
#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;
      }
}

Generated by  Doxygen 1.6.0   Back to index