/* Png.cc
Copyright © 2003 David Reveman.
This file is part of Waimea.
Waimea 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, or (at your option) any later
version.
Waimea 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 Waimea; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
#ifdef HAVE_CONFIG_H
# include "../config.h"
#endif // HAVE_CONFIG_H
#ifdef PNG
extern "C" {
#ifdef STDC_HEADERS
# include <stdlib.h>
#endif // STDC_HEADERS
#include "png.h"
}
#ifndef png_jmpbuf
# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
#endif
#include "Util.hh"
#define PNG_BYTES_TO_CHECK 4
bool check_if_png(FILE *fp) {
png_byte buf[PNG_BYTES_TO_CHECK];
if (fread(buf, 1, PNG_BYTES_TO_CHECK, fp) != PNG_BYTES_TO_CHECK)
return false;
return (! png_sig_cmp(buf, (png_size_t) 0, PNG_BYTES_TO_CHECK));
}
static void premultiply_data(png_structp, png_row_infop row_info,
png_bytep data) {
for (unsigned int i = 0; i < row_info->rowbytes; i += 4) {
unsigned char *base = &data[i];
unsigned char blue = base[0];
unsigned char green = base[1];
unsigned char red = base[2];
unsigned char alpha = base[3];
WaPixel p;
red = (unsigned) red * (unsigned) alpha / 255;
green = (unsigned) green * (unsigned) alpha / 255;
blue = (unsigned) blue * (unsigned) alpha / 255;
p = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
memcpy(base, &p, sizeof (WaPixel));
}
}
unsigned char *read_png_to_rgba(FILE *fp, int *pwidth, int *pheight) {
png_structp png_ptr;
png_infop info_ptr;
png_uint_32 width, height;
int bit_depth, color_type, interlace_type, compression_type, filter_type;
int channels;
unsigned char *data;
png_bytepp volatile rows = NULL;
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) return NULL;
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
png_destroy_read_struct(&png_ptr, NULL, NULL);
return NULL;
}
if (setjmp(png_jmpbuf(png_ptr)))
goto bail;
png_init_io(png_ptr, fp);
png_read_info(png_ptr, info_ptr);
bit_depth = png_get_bit_depth(png_ptr, info_ptr);
if (bit_depth < 1 || bit_depth > 16)
goto bail;
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
&interlace_type, &compression_type, &filter_type);
if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8) {
png_set_expand(png_ptr);
} else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
png_set_expand(png_ptr);
} else if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) {
png_set_expand(png_ptr);
} else if (bit_depth < 8) {
png_set_expand(png_ptr);
}
if (bit_depth == 16)
png_set_strip_16(png_ptr);
if (color_type == PNG_COLOR_TYPE_GRAY ||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png_ptr);
if (interlace_type != PNG_INTERLACE_NONE)
png_set_interlace_handling(png_ptr);
png_set_bgr(png_ptr);
png_set_filler(png_ptr, 255, PNG_FILLER_AFTER);
png_set_read_user_transform_fn(png_ptr, premultiply_data);
png_read_update_info(png_ptr, info_ptr);
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
&interlace_type, &compression_type, &filter_type);
if (width == 0 || height == 0) {
WARNING << "transformed PNG has zero width or height" << endl;
goto bail;
}
if (bit_depth != 8) {
WARNING << "bits per channel of transformed PNG is not 8" << endl;
goto bail;
}
if (! (color_type == PNG_COLOR_TYPE_RGB ||
color_type == PNG_COLOR_TYPE_RGB_ALPHA) ) {
WARNING << "transformed PNG not RGB or ARGB" << endl;
goto bail;
}
channels = png_get_channels(png_ptr, info_ptr);
if (! (channels == 3 || channels == 4) ) {
WARNING << "transformed PNG has unsupported number of channels, "
"must be 3 or 4." << endl;
goto bail;
}
data = new unsigned char[sizeof(WaPixel) * width * height];
rows = (png_bytepp) new png_bytep[height];
for (unsigned int i = 0; i < height; i++)
rows[i] = data + i * width * sizeof(WaPixel);
png_read_image(png_ptr, rows);
png_read_end(png_ptr, info_ptr);
*pwidth = width;
*pheight = height;
delete [] rows;
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return data;
bail:
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return NULL;
}
#endif // PNG
syntax highlighted by Code2HTML, v. 0.9.1