From 62cdc4181f536384c70254f1e5d8ab311cff368d Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Sun, 10 May 2009 04:19:07 +0000 Subject: Merge libdimension-png into libdimension. --- Makefile.am | 2 +- configure.ac | 1 - libdimension-png/Makefile.am | 28 ---- libdimension-png/dimension-png.h | 43 ----- libdimension-png/png.c | 328 ------------------------------------- libdimension/Makefile.am | 6 +- libdimension/dimension.h | 1 + libdimension/dimension/png.h | 43 +++++ libdimension/png.c | 328 +++++++++++++++++++++++++++++++++++++ libdimensionxx/Makefile.am | 4 +- libdimensionxx/dimensionxx.hpp | 2 - libdimensionxx/dimensionxx/png.hpp | 2 +- libdimensionxx/png.cpp | 1 - tests/Makefile.am | 4 +- tests/png.c | 3 +- 15 files changed, 382 insertions(+), 414 deletions(-) delete mode 100644 libdimension-png/Makefile.am delete mode 100644 libdimension-png/dimension-png.h delete mode 100644 libdimension-png/png.c create mode 100644 libdimension/dimension/png.h create mode 100644 libdimension/png.c diff --git a/Makefile.am b/Makefile.am index 4e9f6bc..11601b2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -18,6 +18,6 @@ ########################################################################### ACLOCAL_AMFLAGS = -I m4 -SUBDIRS = libdimension libdimension-png libdimensionxx tests +SUBDIRS = libdimension libdimensionxx tests EXTRA_DIST = autogen.sh diff --git a/configure.ac b/configure.ac index 8599feb..b68aa8b 100644 --- a/configure.ac +++ b/configure.ac @@ -45,7 +45,6 @@ dnl Generate Makefiles AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_FILES([Makefile libdimension/Makefile - libdimension-png/Makefile libdimensionxx/Makefile tests/Makefile]) AC_OUTPUT diff --git a/libdimension-png/Makefile.am b/libdimension-png/Makefile.am deleted file mode 100644 index cd82a66..0000000 --- a/libdimension-png/Makefile.am +++ /dev/null @@ -1,28 +0,0 @@ -########################################################################### -## Copyright (C) 2008 Tavian Barnes ## -## ## -## This file is part of The Dimension Build Suite. ## -## ## -## The Dimension Build Suite 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 3 of the ## -## License, or (at your option) any later version. ## -## ## -## The Dimension Build Suite 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 . ## -########################################################################### - -nobase_include_HEADERS = dimension-png.h - -lib_LTLIBRARIES = libdimension-png.la - -INCLUDES = -I../libdimension - -libdimension_png_la_SOURCES = dimension-png.h png.c -libdimension_png_la_LDFLAGS = -version-info 0:0:0 -libdimension_png_la_LIBADD = -lpng diff --git a/libdimension-png/dimension-png.h b/libdimension-png/dimension-png.h deleted file mode 100644 index 9ee55c3..0000000 --- a/libdimension-png/dimension-png.h +++ /dev/null @@ -1,43 +0,0 @@ -/************************************************************************* - * Copyright (C) 2008 Tavian Barnes * - * * - * This file is part of The Dimension Library. * - * * - * The Dimension Library is free software; you can redistribute it and/ * - * or modify it under the terms of the GNU Lesser General Public License * - * as published by the Free Software Foundation; either version 3 of the * - * License, or (at your option) any later version. * - * * - * The Dimension Library 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 * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -#ifndef DIMENSION_PNG_H -#define DIMENSION_PNG_H - -#include -#include - -#ifdef __cplusplus -/* We've been included from a C++ file; mark everything here as extern "C" */ -extern "C" { -#endif - -/* Write canvas to file in PNG format. Returns 0 on success, nonzero on - failure */ -int dmnsn_png_write_canvas(const dmnsn_canvas *canvas, FILE *file); - -/* Read a canvas from a PNG file. Returns NULL on failure. */ -dmnsn_canvas *dmnsn_png_read_canvas(FILE *file); - -#ifdef __cplusplus -} -#endif - -#endif /* DIMENSION_PNG_H */ diff --git a/libdimension-png/png.c b/libdimension-png/png.c deleted file mode 100644 index 7e9036f..0000000 --- a/libdimension-png/png.c +++ /dev/null @@ -1,328 +0,0 @@ -/************************************************************************* - * Copyright (C) 2008 Tavian Barnes * - * * - * This file is part of The Dimension Library. * - * * - * The Dimension Library is free software; you can redistribute it and/ * - * or modify it under the terms of the GNU Lesser General Public License * - * as published by the Free Software Foundation; either version 3 of the * - * License, or (at your option) any later version. * - * * - * The Dimension Library 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 * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -#include "dimension-png.h" -#include -#include -#include -#include - -/* Write a canvas to a png file, using libpng. Return 0 on success, nonzero on - failure. */ -int -dmnsn_png_write_canvas(const dmnsn_canvas *canvas, FILE *file) -{ - png_structp png_ptr; - png_infop info_ptr; - png_uint_32 width, height; - unsigned int x, y; - uint16_t *row = NULL; - dmnsn_color color; - dmnsn_sRGB sRGB; - - if (!file) return 1; /* file was NULL */ - - width = canvas->x; - height = canvas->y; - - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png_ptr) return 1; /* Couldn't create libpng write struct */ - - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - /* Couldn't create libpng info struct */ - png_destroy_write_struct(&png_ptr, NULL); - return 1; - } - - /* libpng will longjmp here if it encounters an error from here on */ - if (setjmp(png_jmpbuf(png_ptr))) { - /* libpng error */ - if (row) free(row); - png_destroy_write_struct(&png_ptr, &info_ptr); - return 1; - } - - /* Associate file with the libpng write struct */ - png_init_io(png_ptr, file); - - /* Set header correctly for 16-bit sRGB image */ - png_set_IHDR(png_ptr, info_ptr, width, height, 16, - PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, PNG_sRGB_INTENT_ABSOLUTE); - - /* We think of transparency in the opposite way that PNG does */ - png_set_invert_alpha(png_ptr); - - /* Write the info struct */ - png_write_info(png_ptr, info_ptr); - - if (htonl(1) != 1) { - /* We are little-endian; swap the byte order of the pixels */ - png_set_swap(png_ptr); - } - - /* Allocate the temporary row of RGBA values */ - row = malloc(4*sizeof(uint16_t)*width); - if (!row) { - png_destroy_write_struct(&png_ptr, &info_ptr); - return 1; - } - - /* Write the pixels */ - for (y = 0; y < height; ++y) { - for (x = 0; x < width; ++x) { - /* Invert the rows. PNG coordinates are fourth quadrant. */ - color = dmnsn_get_pixel(canvas, x, height - y - 1); - sRGB = dmnsn_sRGB_from_color(color); - - /* Saturate R, G, and B to [0, UINT16_MAX] */ - - if (sRGB.R <= 0.0) { - row[4*x] = 0; - } else if (sRGB.R >= 1.0) { - row[4*x] = UINT16_MAX; - } else { - row[4*x] = sRGB.R*UINT16_MAX; - } - - if (sRGB.G <= 0.0) { - row[4*x + 1] = 0; - } else if (sRGB.G >= 1.0) { - row[4*x + 1] = UINT16_MAX; - } else { - row[4*x + 1] = sRGB.G*UINT16_MAX; - } - - if (sRGB.B <= 0.0) { - row[4*x + 2] = 0; - } else if (sRGB.B >= 1.0) { - row[4*x + 2] = UINT16_MAX; - } else { - row[4*x + 2] = sRGB.B*UINT16_MAX; - } - - /* color.filter + color.trans is in [0.0, 1.0] by definition */ - row[4*x + 3] = (color.filter + color.trans)*UINT16_MAX; - } - - /* Write the row */ - png_write_row(png_ptr, (png_bytep)row); - } - - /* Finish the PNG file */ - png_write_end(png_ptr, info_ptr); - - free(row); - png_destroy_write_struct(&png_ptr, &info_ptr); - return 0; -} - -/* Read a canvas from the PNG file `file'. Return NULL on error. */ -dmnsn_canvas * -dmnsn_png_read_canvas(FILE *file) -{ - dmnsn_canvas *canvas; - png_byte header[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - png_structp png_ptr; - png_infop info_ptr; - png_uint_32 width, height, rowbytes; - int bit_depth, color_type, interlace_type, compression_type, filter_method; - png_bytep image = NULL; - png_bytep *row_pointers = NULL; - unsigned int x, y; - dmnsn_color color; - dmnsn_sRGB sRGB; - png_bytep png_pixel; - - if (!file) return NULL; /* file was NULL */ - - fread(header, 1, 8, file); - if (png_sig_cmp(header, 0, 8)) return NULL; /* file is not a PNG file */ - - /* Create the libpng read struct */ - png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png_ptr) return NULL; - - /* Create the libpng info struct */ - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - png_destroy_read_struct(&png_ptr, NULL, NULL); - return NULL; - } - - /* libpng will longjmp here if it encounters an error from here on */ - if (setjmp(png_jmpbuf(png_ptr))) { - /* libpng error */ - if (row_pointers) free(row_pointers); - if (image) free(image); - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - return NULL; - } - - /* Associate the read struct with the file, and tell it we've already checked - 8 bytes of signature */ - png_init_io(png_ptr, file); - png_set_sig_bytes(png_ptr, 8); - - /* Read the PNG header into info struct */ - png_read_info(png_ptr, info_ptr); - - /* Get useful information from the info struct */ - png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, - &interlace_type, &compression_type, &filter_method); - - /* - * - Convert paletted images to RGB. - * - Convert a tRNS chunk to an alpha channel - * - Convert grayscale to RGB - * - Invert the alpha channel - */ - if (color_type == PNG_COLOR_TYPE_PALETTE) { - png_set_palette_to_rgb(png_ptr); - } - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { - png_set_tRNS_to_alpha(png_ptr); - } - if (color_type == PNG_COLOR_TYPE_GRAY - || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { - png_set_gray_to_rgb(png_ptr); - } - png_set_invert_alpha(png_ptr); - - /* Update the info struct */ - png_read_update_info(png_ptr, info_ptr); - - /* Get bytes/image row */ - rowbytes = png_get_rowbytes(png_ptr, info_ptr); - - /* Allocate the temporary image buffer */ - image = malloc(rowbytes*height); - if (!image) { - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - return NULL; - } - - /* Allocate and set an array of pointers to rows in image */ - - row_pointers = malloc(sizeof(png_bytep)*height); - if (!row_pointers) { - free(image); - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - return NULL; - } - - for (y = 0; y < height; ++y) { - row_pointers[y] = image + y*rowbytes; - } - - /* Read the image to image all at once. At the expense of greater memory use, - this handles interlacing for us. */ - png_read_image(png_ptr, row_pointers); - - /* Allocate the canvas */ - canvas = dmnsn_new_canvas(width, height); - if (!canvas) { - free(row_pointers); - free(image); - png_read_end(png_ptr, NULL); - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - return NULL; - } - - /* Now we convert the image to our canvas format. This depends on the image - bit depth (which has been scaled up to at least 8 or 16), and the presence - of an alpha channel. For performance reasons, the tests are outside the - loops, although that doesn't really matter for a decent compiler. */ - if (bit_depth == 16) { - if (color_type & PNG_COLOR_MASK_ALPHA) { - for (x = 0; x < width; ++x) { - for (y = 0; y < height; ++y) { - png_pixel = image + 8*(y*width + x); - - sRGB.R = ((double)((png_pixel[0] << UINT16_C(8)) + png_pixel[1])) - /UINT16_MAX; - sRGB.G = ((double)((png_pixel[2] << UINT16_C(8)) + png_pixel[3])) - /UINT16_MAX; - sRGB.B = ((double)((png_pixel[4] << UINT16_C(8)) + png_pixel[5])) - /UINT16_MAX; - - color = dmnsn_color_from_sRGB(sRGB); - color.trans = ((double)((png_pixel[6] << UINT16_C(8)) - + png_pixel[7]))/UINT16_MAX; - dmnsn_set_pixel(canvas, x, height - y - 1, color); - } - } - } else { - for (x = 0; x < width; ++x) { - for (y = 0; y < height; ++y) { - png_pixel = image + 6*(y*width + x); - - sRGB.R = ((double)((png_pixel[0] << UINT16_C(8)) + png_pixel[1])) - /UINT16_MAX; - sRGB.G = ((double)((png_pixel[2] << UINT16_C(8)) + png_pixel[3])) - /UINT16_MAX; - sRGB.B = ((double)((png_pixel[4] << UINT16_C(8)) + png_pixel[5])) - /UINT16_MAX; - - color = dmnsn_color_from_sRGB(sRGB); - dmnsn_set_pixel(canvas, x, height - y - 1, color); - } - } - } - } else { - /* Bit depth is 8 */ - if (color_type & PNG_COLOR_MASK_ALPHA) { - for (x = 0; x < width; ++x) { - for (y = 0; y < height; ++y) { - png_pixel = image + 4*(y*width + x); - - sRGB.R = ((double)png_pixel[0])/UINT8_MAX; - sRGB.G = ((double)png_pixel[1])/UINT8_MAX; - sRGB.B = ((double)png_pixel[2])/UINT8_MAX; - - color = dmnsn_color_from_sRGB(sRGB); - color.trans = ((double)png_pixel[3])/UINT8_MAX; - dmnsn_set_pixel(canvas, x, height - y - 1, color); - } - } - } else { - for (x = 0; x < width; ++x) { - for (y = 0; y < height; ++y) { - png_pixel = image + 3*(y*width + x); - - sRGB.R = ((double)png_pixel[0])/UINT8_MAX; - sRGB.G = ((double)png_pixel[1])/UINT8_MAX; - sRGB.B = ((double)png_pixel[2])/UINT8_MAX; - - color = dmnsn_color_from_sRGB(sRGB); - dmnsn_set_pixel(canvas, x, height - y - 1, color); - } - } - } - } - - free(row_pointers); - free(image); - png_read_end(png_ptr, NULL); - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - return canvas; -} diff --git a/libdimension/Makefile.am b/libdimension/Makefile.am index ee3b6dc..7114b04 100644 --- a/libdimension/Makefile.am +++ b/libdimension/Makefile.am @@ -17,10 +17,10 @@ ## along with this program. If not, see . ## ########################################################################### -nobase_include_HEADERS = dimension.h dimension/array.h dimension/canvas.h dimension/color.h dimension/error.h dimension/geometry.h +nobase_include_HEADERS = dimension.h dimension/array.h dimension/canvas.h dimension/color.h dimension/error.h dimension/geometry.h dimension/png.h lib_LTLIBRARIES = libdimension.la -libdimension_la_SOURCES = $(nobase_include_HEADERS) array.c canvas.c color.c error.c geometry.c +libdimension_la_SOURCES = $(nobase_include_HEADERS) array.c canvas.c color.c error.c geometry.c png.c libdimension_la_LDFLAGS = -version-info 0:0:0 -libdimension_la_LIBADD = -lm -lpthread +libdimension_la_LIBADD = -lm -lpthread -lpng diff --git a/libdimension/dimension.h b/libdimension/dimension.h index ac65f4c..50e1544 100644 --- a/libdimension/dimension.h +++ b/libdimension/dimension.h @@ -32,6 +32,7 @@ extern "C" { #include #include #include +#include #ifdef __cplusplus } diff --git a/libdimension/dimension/png.h b/libdimension/dimension/png.h new file mode 100644 index 0000000..9ee55c3 --- /dev/null +++ b/libdimension/dimension/png.h @@ -0,0 +1,43 @@ +/************************************************************************* + * Copyright (C) 2008 Tavian Barnes * + * * + * This file is part of The Dimension Library. * + * * + * The Dimension Library is free software; you can redistribute it and/ * + * or modify it under the terms of the GNU Lesser General Public License * + * as published by the Free Software Foundation; either version 3 of the * + * License, or (at your option) any later version. * + * * + * The Dimension Library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this program. If not, see * + * . * + *************************************************************************/ + +#ifndef DIMENSION_PNG_H +#define DIMENSION_PNG_H + +#include +#include + +#ifdef __cplusplus +/* We've been included from a C++ file; mark everything here as extern "C" */ +extern "C" { +#endif + +/* Write canvas to file in PNG format. Returns 0 on success, nonzero on + failure */ +int dmnsn_png_write_canvas(const dmnsn_canvas *canvas, FILE *file); + +/* Read a canvas from a PNG file. Returns NULL on failure. */ +dmnsn_canvas *dmnsn_png_read_canvas(FILE *file); + +#ifdef __cplusplus +} +#endif + +#endif /* DIMENSION_PNG_H */ diff --git a/libdimension/png.c b/libdimension/png.c new file mode 100644 index 0000000..5f45011 --- /dev/null +++ b/libdimension/png.c @@ -0,0 +1,328 @@ +/************************************************************************* + * Copyright (C) 2008 Tavian Barnes * + * * + * This file is part of The Dimension Library. * + * * + * The Dimension Library is free software; you can redistribute it and/ * + * or modify it under the terms of the GNU Lesser General Public License * + * as published by the Free Software Foundation; either version 3 of the * + * License, or (at your option) any later version. * + * * + * The Dimension Library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this program. If not, see * + * . * + *************************************************************************/ + +#include "dimension.h" +#include +#include +#include +#include + +/* Write a canvas to a png file, using libpng. Return 0 on success, nonzero on + failure. */ +int +dmnsn_png_write_canvas(const dmnsn_canvas *canvas, FILE *file) +{ + png_structp png_ptr; + png_infop info_ptr; + png_uint_32 width, height; + unsigned int x, y; + uint16_t *row = NULL; + dmnsn_color color; + dmnsn_sRGB sRGB; + + if (!file) return 1; /* file was NULL */ + + width = canvas->x; + height = canvas->y; + + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) return 1; /* Couldn't create libpng write struct */ + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + /* Couldn't create libpng info struct */ + png_destroy_write_struct(&png_ptr, NULL); + return 1; + } + + /* libpng will longjmp here if it encounters an error from here on */ + if (setjmp(png_jmpbuf(png_ptr))) { + /* libpng error */ + if (row) free(row); + png_destroy_write_struct(&png_ptr, &info_ptr); + return 1; + } + + /* Associate file with the libpng write struct */ + png_init_io(png_ptr, file); + + /* Set header correctly for 16-bit sRGB image */ + png_set_IHDR(png_ptr, info_ptr, width, height, 16, + PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, PNG_sRGB_INTENT_ABSOLUTE); + + /* We think of transparency in the opposite way that PNG does */ + png_set_invert_alpha(png_ptr); + + /* Write the info struct */ + png_write_info(png_ptr, info_ptr); + + if (htonl(1) != 1) { + /* We are little-endian; swap the byte order of the pixels */ + png_set_swap(png_ptr); + } + + /* Allocate the temporary row of RGBA values */ + row = malloc(4*sizeof(uint16_t)*width); + if (!row) { + png_destroy_write_struct(&png_ptr, &info_ptr); + return 1; + } + + /* Write the pixels */ + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) { + /* Invert the rows. PNG coordinates are fourth quadrant. */ + color = dmnsn_get_pixel(canvas, x, height - y - 1); + sRGB = dmnsn_sRGB_from_color(color); + + /* Saturate R, G, and B to [0, UINT16_MAX] */ + + if (sRGB.R <= 0.0) { + row[4*x] = 0; + } else if (sRGB.R >= 1.0) { + row[4*x] = UINT16_MAX; + } else { + row[4*x] = sRGB.R*UINT16_MAX; + } + + if (sRGB.G <= 0.0) { + row[4*x + 1] = 0; + } else if (sRGB.G >= 1.0) { + row[4*x + 1] = UINT16_MAX; + } else { + row[4*x + 1] = sRGB.G*UINT16_MAX; + } + + if (sRGB.B <= 0.0) { + row[4*x + 2] = 0; + } else if (sRGB.B >= 1.0) { + row[4*x + 2] = UINT16_MAX; + } else { + row[4*x + 2] = sRGB.B*UINT16_MAX; + } + + /* color.filter + color.trans is in [0.0, 1.0] by definition */ + row[4*x + 3] = (color.filter + color.trans)*UINT16_MAX; + } + + /* Write the row */ + png_write_row(png_ptr, (png_bytep)row); + } + + /* Finish the PNG file */ + png_write_end(png_ptr, info_ptr); + + free(row); + png_destroy_write_struct(&png_ptr, &info_ptr); + return 0; +} + +/* Read a canvas from the PNG file `file'. Return NULL on error. */ +dmnsn_canvas * +dmnsn_png_read_canvas(FILE *file) +{ + dmnsn_canvas *canvas; + png_byte header[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + png_structp png_ptr; + png_infop info_ptr; + png_uint_32 width, height, rowbytes; + int bit_depth, color_type, interlace_type, compression_type, filter_method; + png_bytep image = NULL; + png_bytep *row_pointers = NULL; + unsigned int x, y; + dmnsn_color color; + dmnsn_sRGB sRGB; + png_bytep png_pixel; + + if (!file) return NULL; /* file was NULL */ + + fread(header, 1, 8, file); + if (png_sig_cmp(header, 0, 8)) return NULL; /* file is not a PNG file */ + + /* Create the libpng read struct */ + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) return NULL; + + /* Create the libpng info struct */ + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_read_struct(&png_ptr, NULL, NULL); + return NULL; + } + + /* libpng will longjmp here if it encounters an error from here on */ + if (setjmp(png_jmpbuf(png_ptr))) { + /* libpng error */ + if (row_pointers) free(row_pointers); + if (image) free(image); + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + return NULL; + } + + /* Associate the read struct with the file, and tell it we've already checked + 8 bytes of signature */ + png_init_io(png_ptr, file); + png_set_sig_bytes(png_ptr, 8); + + /* Read the PNG header into info struct */ + png_read_info(png_ptr, info_ptr); + + /* Get useful information from the info struct */ + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, + &interlace_type, &compression_type, &filter_method); + + /* + * - Convert paletted images to RGB. + * - Convert a tRNS chunk to an alpha channel + * - Convert grayscale to RGB + * - Invert the alpha channel + */ + if (color_type == PNG_COLOR_TYPE_PALETTE) { + png_set_palette_to_rgb(png_ptr); + } + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { + png_set_tRNS_to_alpha(png_ptr); + } + if (color_type == PNG_COLOR_TYPE_GRAY + || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { + png_set_gray_to_rgb(png_ptr); + } + png_set_invert_alpha(png_ptr); + + /* Update the info struct */ + png_read_update_info(png_ptr, info_ptr); + + /* Get bytes/image row */ + rowbytes = png_get_rowbytes(png_ptr, info_ptr); + + /* Allocate the temporary image buffer */ + image = malloc(rowbytes*height); + if (!image) { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + return NULL; + } + + /* Allocate and set an array of pointers to rows in image */ + + row_pointers = malloc(sizeof(png_bytep)*height); + if (!row_pointers) { + free(image); + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + return NULL; + } + + for (y = 0; y < height; ++y) { + row_pointers[y] = image + y*rowbytes; + } + + /* Read the image to image all at once. At the expense of greater memory use, + this handles interlacing for us. */ + png_read_image(png_ptr, row_pointers); + + /* Allocate the canvas */ + canvas = dmnsn_new_canvas(width, height); + if (!canvas) { + free(row_pointers); + free(image); + png_read_end(png_ptr, NULL); + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + return NULL; + } + + /* Now we convert the image to our canvas format. This depends on the image + bit depth (which has been scaled up to at least 8 or 16), and the presence + of an alpha channel. For performance reasons, the tests are outside the + loops, although that doesn't really matter for a decent compiler. */ + if (bit_depth == 16) { + if (color_type & PNG_COLOR_MASK_ALPHA) { + for (x = 0; x < width; ++x) { + for (y = 0; y < height; ++y) { + png_pixel = image + 8*(y*width + x); + + sRGB.R = ((double)((png_pixel[0] << UINT16_C(8)) + png_pixel[1])) + /UINT16_MAX; + sRGB.G = ((double)((png_pixel[2] << UINT16_C(8)) + png_pixel[3])) + /UINT16_MAX; + sRGB.B = ((double)((png_pixel[4] << UINT16_C(8)) + png_pixel[5])) + /UINT16_MAX; + + color = dmnsn_color_from_sRGB(sRGB); + color.trans = ((double)((png_pixel[6] << UINT16_C(8)) + + png_pixel[7]))/UINT16_MAX; + dmnsn_set_pixel(canvas, x, height - y - 1, color); + } + } + } else { + for (x = 0; x < width; ++x) { + for (y = 0; y < height; ++y) { + png_pixel = image + 6*(y*width + x); + + sRGB.R = ((double)((png_pixel[0] << UINT16_C(8)) + png_pixel[1])) + /UINT16_MAX; + sRGB.G = ((double)((png_pixel[2] << UINT16_C(8)) + png_pixel[3])) + /UINT16_MAX; + sRGB.B = ((double)((png_pixel[4] << UINT16_C(8)) + png_pixel[5])) + /UINT16_MAX; + + color = dmnsn_color_from_sRGB(sRGB); + dmnsn_set_pixel(canvas, x, height - y - 1, color); + } + } + } + } else { + /* Bit depth is 8 */ + if (color_type & PNG_COLOR_MASK_ALPHA) { + for (x = 0; x < width; ++x) { + for (y = 0; y < height; ++y) { + png_pixel = image + 4*(y*width + x); + + sRGB.R = ((double)png_pixel[0])/UINT8_MAX; + sRGB.G = ((double)png_pixel[1])/UINT8_MAX; + sRGB.B = ((double)png_pixel[2])/UINT8_MAX; + + color = dmnsn_color_from_sRGB(sRGB); + color.trans = ((double)png_pixel[3])/UINT8_MAX; + dmnsn_set_pixel(canvas, x, height - y - 1, color); + } + } + } else { + for (x = 0; x < width; ++x) { + for (y = 0; y < height; ++y) { + png_pixel = image + 3*(y*width + x); + + sRGB.R = ((double)png_pixel[0])/UINT8_MAX; + sRGB.G = ((double)png_pixel[1])/UINT8_MAX; + sRGB.B = ((double)png_pixel[2])/UINT8_MAX; + + color = dmnsn_color_from_sRGB(sRGB); + dmnsn_set_pixel(canvas, x, height - y - 1, color); + } + } + } + } + + free(row_pointers); + free(image); + png_read_end(png_ptr, NULL); + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + return canvas; +} diff --git a/libdimensionxx/Makefile.am b/libdimensionxx/Makefile.am index 74eb03b..862f72c 100644 --- a/libdimensionxx/Makefile.am +++ b/libdimensionxx/Makefile.am @@ -19,7 +19,7 @@ nobase_include_HEADERS = dimensionxx.hpp dimensionxx/canvas.hpp dimensionxx/color.hpp dimensionxx/cookie.hpp dimensionxx/geometry.hpp dimensionxx/png.hpp -INCLUDES = -I../libdimension -I../libdimension-png +INCLUDES = -I../libdimension lib_LTLIBRARIES = libdimensionxx.la @@ -32,4 +32,4 @@ else endif libdimensionxx_la_LDFLAGS = -version-info 0:0:0 -libdimensionxx_la_LIBADD = ../libdimension/libdimension.la ../libdimension-png/libdimension-png.la +libdimensionxx_la_LIBADD = ../libdimension/libdimension.la diff --git a/libdimensionxx/dimensionxx.hpp b/libdimensionxx/dimensionxx.hpp index 7714f73..bfa0b06 100644 --- a/libdimensionxx/dimensionxx.hpp +++ b/libdimensionxx/dimensionxx.hpp @@ -29,8 +29,6 @@ #include #include #include - -// libdimension-png wrapper #include #endif /* DIMENSIONXX_HPP */ diff --git a/libdimensionxx/dimensionxx/png.hpp b/libdimensionxx/dimensionxx/png.hpp index c14b25f..07d7c18 100644 --- a/libdimensionxx/dimensionxx/png.hpp +++ b/libdimensionxx/dimensionxx/png.hpp @@ -21,7 +21,7 @@ #ifndef DIMENSIONXX_PNG_HPP #define DIMENSIONXX_PNG_HPP -// C++ wrapper for libdimension-png. PNG_Canvas derives from Canvas. +// C++ wrapper for libdimension PNG support. PNG_Canvas derives from Canvas. #include #include diff --git a/libdimensionxx/png.cpp b/libdimensionxx/png.cpp index 2d1d276..029e431 100644 --- a/libdimensionxx/png.cpp +++ b/libdimensionxx/png.cpp @@ -19,7 +19,6 @@ *************************************************************************/ #include "dimensionxx.hpp" -#include "../libdimension-png/dimension-png.h" #include #include diff --git a/tests/Makefile.am b/tests/Makefile.am index a11f18a..d4f94fc 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -21,7 +21,7 @@ check_PROGRAMS = warning error png pngxx TESTS = $(check_PROGRAMS) XFAIL_TESTS = error -INCLUDES = -I../libdimension -I../libdimension-png -I../libdimensionxx +INCLUDES = -I../libdimension -I../libdimensionxx warning_SOURCES = warning.c warning_LDADD = ../libdimension/libdimension.la @@ -30,7 +30,7 @@ error_SOURCES = error.c error_LDADD = ../libdimension/libdimension.la png_SOURCES = png.c -png_LDADD = ../libdimension/libdimension.la ../libdimension-png/libdimension-png.la +png_LDADD = ../libdimension/libdimension.la pngxx_SOURCES = pngxx.cpp pngxx_LDADD = ../libdimensionxx/libdimensionxx.la diff --git a/tests/png.c b/tests/png.c index 0ee7edb..5e7be2f 100644 --- a/tests/png.c +++ b/tests/png.c @@ -18,8 +18,7 @@ * . * *************************************************************************/ -#include "../libdimension/dimension.h" -#include "../libdimension-png/dimension-png.h" +#include "dimension.h" #include #include #include -- cgit v1.2.3