From 4f9f95a05a41bfbcc9965eaaf7f2d14c6af9f261 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Sun, 12 Apr 2009 15:42:04 +0000 Subject: Write C++ libdimension-png wrapper. --- libdimension-png/dimension-png.h | 2 +- libdimension-png/png.c | 38 ++++---- libdimension/color.c | 16 +++- libdimension/dimension.h | 3 +- libdimension/dimension/color.h | 1 + libdimension/error.c | 14 +-- libdimensionxx/Makefile.am | 4 +- libdimensionxx/cookie.cpp | 163 ++++++++++++++++++++++++++++++++++ libdimensionxx/dimensionxx.hpp | 9 +- libdimensionxx/dimensionxx/canvas.hpp | 13 ++- libdimensionxx/dimensionxx/color.hpp | 25 ++++++ libdimensionxx/dimensionxx/cookie.hpp | 35 ++++++++ libdimensionxx/dimensionxx/error.hpp | 30 +++++++ libdimensionxx/dimensionxx/png.hpp | 59 ++++++++++++ libdimensionxx/png.cpp | 96 ++++++++++++++++++++ tests/Makefile.am | 7 +- tests/png.c | 4 +- tests/pngxx | 148 ++++++++++++++++++++++++++++++ tests/pngxx.cpp | 102 +++++++++++++++++++++ 19 files changed, 729 insertions(+), 40 deletions(-) create mode 100644 libdimensionxx/cookie.cpp create mode 100644 libdimensionxx/dimensionxx/cookie.hpp create mode 100644 libdimensionxx/dimensionxx/error.hpp create mode 100644 libdimensionxx/dimensionxx/png.hpp create mode 100644 libdimensionxx/png.cpp create mode 100755 tests/pngxx create mode 100644 tests/pngxx.cpp diff --git a/libdimension-png/dimension-png.h b/libdimension-png/dimension-png.h index f8b4775..46ce82d 100644 --- a/libdimension-png/dimension-png.h +++ b/libdimension-png/dimension-png.h @@ -29,7 +29,7 @@ extern "C" { #endif int dmnsn_png_write_canvas(const dmnsn_canvas *canvas, FILE *file); -int dmnsn_png_read_canvas(dmnsn_canvas **canvas, FILE *file); +dmnsn_canvas *dmnsn_png_read_canvas(FILE *file); #ifdef __cplusplus } diff --git a/libdimension-png/png.c b/libdimension-png/png.c index 9bd22be..b639900 100644 --- a/libdimension-png/png.c +++ b/libdimension-png/png.c @@ -119,9 +119,10 @@ dmnsn_png_write_canvas(const dmnsn_canvas *canvas, FILE *file) return 0; } -int -dmnsn_png_read_canvas(dmnsn_canvas **canvas, FILE *file) +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; @@ -134,28 +135,25 @@ dmnsn_png_read_canvas(dmnsn_canvas **canvas, FILE *file) dmnsn_sRGB sRGB; png_bytep png_pixel; - /* Ensure that *canvas can always be deleted. */ - *canvas = NULL; - - if (!file) return 1; + if (!file) return NULL; fread(header, 1, 8, file); - if (png_sig_cmp(header, 0, 8)) return 1; + if (png_sig_cmp(header, 0, 8)) return NULL; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png_ptr) return 1; + if (!png_ptr) return NULL; info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); - return 1; + return NULL; } if (setjmp(png_jmpbuf(png_ptr))) { if (row_pointers) free(row_pointers); if (image) free(image); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - return 1; + return NULL; } png_init_io(png_ptr, file); @@ -190,14 +188,14 @@ dmnsn_png_read_canvas(dmnsn_canvas **canvas, FILE *file) image = malloc(rowbytes*height); if (!image) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - return 1; + return NULL; } row_pointers = malloc(sizeof(png_bytep)*height); if (!row_pointers) { free(image); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - return 1; + return NULL; } for (y = 0; y < height; ++y) { @@ -206,13 +204,13 @@ dmnsn_png_read_canvas(dmnsn_canvas **canvas, FILE *file) png_read_image(png_ptr, row_pointers); - *canvas = dmnsn_new_canvas(width, height); - if (!*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 1; + return NULL; } if (bit_depth == 16) { @@ -231,7 +229,7 @@ dmnsn_png_read_canvas(dmnsn_canvas **canvas, FILE *file) 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); + dmnsn_set_pixel(canvas, x, height - y - 1, color); } } } else { @@ -247,7 +245,7 @@ dmnsn_png_read_canvas(dmnsn_canvas **canvas, FILE *file) /UINT16_MAX; color = dmnsn_color_from_sRGB(sRGB); - dmnsn_set_pixel(*canvas, x, height - y - 1, color); + dmnsn_set_pixel(canvas, x, height - y - 1, color); } } } @@ -264,7 +262,7 @@ dmnsn_png_read_canvas(dmnsn_canvas **canvas, FILE *file) color = dmnsn_color_from_sRGB(sRGB); color.trans = ((double)png_pixel[3])/UINT8_MAX; - dmnsn_set_pixel(*canvas, x, height - y - 1, color); + dmnsn_set_pixel(canvas, x, height - y - 1, color); } } } else { @@ -277,7 +275,7 @@ dmnsn_png_read_canvas(dmnsn_canvas **canvas, FILE *file) sRGB.B = ((double)png_pixel[2])/UINT8_MAX; color = dmnsn_color_from_sRGB(sRGB); - dmnsn_set_pixel(*canvas, x, height - y - 1, color); + dmnsn_set_pixel(canvas, x, height - y - 1, color); } } } @@ -287,5 +285,5 @@ dmnsn_png_read_canvas(dmnsn_canvas **canvas, FILE *file) free(image); png_read_end(png_ptr, NULL); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - return 0; + return canvas; } diff --git a/libdimension/color.c b/libdimension/color.c index 4caf53b..e2a4df9 100644 --- a/libdimension/color.c +++ b/libdimension/color.c @@ -19,7 +19,7 @@ *************************************************************************/ #include "dimension.h" -#include /* For pow() */ +#include /* For pow(), sqrt() */ /* sRGB white point (D50) */ const dmnsn_CIE_XYZ dmnsn_whitepoint = { .X = 0.9504060171449392, @@ -253,3 +253,17 @@ dmnsn_color_add(dmnsn_color color1, dmnsn_color color2) return ret; } + +double +dmnsn_color_difference(dmnsn_color color1, dmnsn_color color2) +{ + dmnsn_CIE_Lab Lab, Lab1, Lab2; + dmnsn_color ret; + + Lab1 = dmnsn_Lab_from_color(color1, dmnsn_whitepoint); + Lab2 = dmnsn_Lab_from_color(color2, dmnsn_whitepoint); + + return sqrt((Lab1.L - Lab2.L)*(Lab1.L - Lab2.L) + + (Lab1.a - Lab2.a)*(Lab1.a - Lab2.a) + + (Lab1.b - Lab2.b)*(Lab1.b - Lab2.b)); +} diff --git a/libdimension/dimension.h b/libdimension/dimension.h index 22fb700..df50524 100644 --- a/libdimension/dimension.h +++ b/libdimension/dimension.h @@ -36,7 +36,8 @@ typedef enum { DMNSN_SEVERITY_HIGH /* Always die */ } dmnsn_severity; -#define dmnsn_error(severity, str) dmnsn_report_error(severity, __func__, str) +#define dmnsn_error(severity, str) \ + dmnsn_report_error(severity, __PRETTY_FUNCTION__, str) void dmnsn_report_error(dmnsn_severity severity, const char *func, const char *str); diff --git a/libdimension/dimension/color.h b/libdimension/dimension/color.h index 5567628..0e64875 100644 --- a/libdimension/dimension/color.h +++ b/libdimension/dimension/color.h @@ -80,6 +80,7 @@ dmnsn_CIE_Luv dmnsn_Luv_from_color(dmnsn_color color, dmnsn_CIE_XYZ white); dmnsn_sRGB dmnsn_sRGB_from_color(dmnsn_color color); dmnsn_color dmnsn_color_add(dmnsn_color color1, dmnsn_color color2); +double dmnsn_color_difference(dmnsn_color color1, dmnsn_color color2); #ifdef __cplusplus } diff --git a/libdimension/error.c b/libdimension/error.c index 9dae673..6edf577 100644 --- a/libdimension/error.c +++ b/libdimension/error.c @@ -30,10 +30,10 @@ void dmnsn_report_error(dmnsn_severity severity, const char *func, const char *str) { if (severity >= dmnsn_get_resilience()) { - fprintf(stderr, "Dimension ERROR: %s(): %s\n", func, str); + fprintf(stderr, "Dimension ERROR: %s: %s\n", func, str); exit(EXIT_FAILURE); } else { - fprintf(stderr, "Dimension WARNING: %s(): %s\n", func, str); + fprintf(stderr, "Dimension WARNING: %s: %s\n", func, str); } } @@ -42,12 +42,12 @@ dmnsn_get_resilience() { dmnsn_severity resilience; if (pthread_mutex_lock(&dmnsn_resilience_mutex) != 0) { - fprintf(stderr, "Dimension WARNING: %s(): %s\n", __func__, + fprintf(stderr, "Dimension WARNING: %s: %s\n", __PRETTY_FUNCTION__, "Couldn't lock resilience mutex."); } resilience = dmnsn_resilience; if (pthread_mutex_unlock(&dmnsn_resilience_mutex) != 0) { - fprintf(stderr, "Dimension WARNING: %s(): %s\n", __func__, + fprintf(stderr, "Dimension WARNING: %s: %s\n", __PRETTY_FUNCTION__, "Couldn't unlock resilience mutex."); } return resilience; @@ -57,18 +57,18 @@ void dmnsn_set_resilience(dmnsn_severity resilience) { if (resilience > DMNSN_SEVERITY_HIGH) { - fprintf(stderr, "Dimension ERROR: %s(): %s\n", __func__, + fprintf(stderr, "Dimension ERROR: %s: %s\n", __PRETTY_FUNCTION__, "Resilience has wrong value."); exit(EXIT_FAILURE); } if (pthread_mutex_lock(&dmnsn_resilience_mutex) != 0) { - fprintf(stderr, "Dimension WARNING: %s(): %s\n", __func__, + fprintf(stderr, "Dimension WARNING: %s: %s\n", __PRETTY_FUNCTION__, "Couldn't lock resilience mutex."); } dmnsn_resilience = resilience; if (pthread_mutex_unlock(&dmnsn_resilience_mutex) != 0) { - fprintf(stderr, "Dimension WARNING: %s(): %s\n", __func__, + fprintf(stderr, "Dimension WARNING: %s: %s\n", __PRETTY_FUNCTION__, "Couldn't unlock resilience mutex."); } } diff --git a/libdimensionxx/Makefile.am b/libdimensionxx/Makefile.am index 39687fe..da8f544 100644 --- a/libdimensionxx/Makefile.am +++ b/libdimensionxx/Makefile.am @@ -17,12 +17,12 @@ ## along with this program. If not, see . ## ########################################################################### -nobase_include_HEADERS = dimensionxx.hpp dimensionxx/geometry.hpp dimensionxx/color.hpp dimensionxx/canvas.hpp +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 lib_LTLIBRARIES = libdimensionxx.la -libdimensionxx_la_SOURCES = dimensionxx.hpp dimensionxx/geometry.hpp dimensionxx/color.hpp dimensionxx/canvas.hpp canvas.cpp color.cpp geometry.cpp +libdimensionxx_la_SOURCES = $(nobase_include_HEADERS) canvas.cpp color.cpp cookie.cpp geometry.cpp png.cpp libdimensionxx_la_LDFLAGS = -version-info 0:0:0 libdimensionxx_la_LIBADD = ../libdimension/libdimension.la ../libdimension-png/libdimension-png.la diff --git a/libdimensionxx/cookie.cpp b/libdimensionxx/cookie.cpp new file mode 100644 index 0000000..dd8a06d --- /dev/null +++ b/libdimensionxx/cookie.cpp @@ -0,0 +1,163 @@ +/************************************************************************* + * 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 "dimensionxx.hpp" +#include + +namespace Dimension +{ + namespace + { + struct Cookie + { + public: + std::istream* istr; + std::ostream* ostr; + }; + + ssize_t + cookie_read(void* cookie, char* buf, size_t size) + { + Cookie* streams = reinterpret_cast(cookie); + + streams->istr->read(buf, size); + + if (streams->istr->eof()) { + return streams->istr->gcount(); + } else if (!streams->istr->good()) { + return -1; + } else { + return streams->istr->gcount(); + } + } + + ssize_t + cookie_write(void* cookie, const char* buf, size_t size) + { + Cookie* streams = reinterpret_cast(cookie); + + streams->ostr->write(buf, size); + + if (!streams->ostr->good()) { + return -1; + } else { + return size; + } + } + + int + cookie_seek(void* cookie, off64_t* offset, int whence) + { + Cookie* streams = reinterpret_cast(cookie); + bool success = true; + + if (streams->istr) { + switch (whence) { + case SEEK_SET: + streams->istr->seekg(*offset, std::ios::beg); + break; + case SEEK_CUR: + streams->istr->seekg(*offset, std::ios::cur); + break; + case SEEK_END: + streams->istr->seekg(*offset, std::ios::end); + break; + } + + if (!streams->istr->good()) { + success = false; + } + } + + if (streams->ostr) { + switch (whence) { + case SEEK_SET: + streams->ostr->seekp(*offset, std::ios::beg); + break; + case SEEK_CUR: + streams->ostr->seekp(*offset, std::ios::cur); + break; + case SEEK_END: + streams->ostr->seekp(*offset, std::ios::end); + } + + if (!streams->ostr->good()) { + success = false; + } + } + + return !success; + } + + int + cookie_close(void* cookie) + { + delete reinterpret_cast(cookie); + } + } + + std::FILE* + fcookie(std::istream& istr) + { + Cookie* cookie = new Cookie; + cookie->istr = &istr; + cookie->ostr = 0; + + cookie_io_functions_t io_funcs; + io_funcs.read = &cookie_read; + io_funcs.write = 0; + io_funcs.seek = &cookie_seek; + io_funcs.close = &cookie_close; + + return fopencookie(reinterpret_cast(cookie), "r", io_funcs); + } + + std::FILE* + fcookie(std::ostream& ostr) + { + Cookie* cookie = new Cookie; + cookie->istr = 0; + cookie->ostr = &ostr; + + cookie_io_functions_t io_funcs; + io_funcs.read = 0; + io_funcs.write = &cookie_write; + io_funcs.seek = &cookie_seek; + io_funcs.close = &cookie_close; + + return fopencookie(reinterpret_cast(cookie), "w", io_funcs); + } + + std::FILE* + fcookie(std::iostream& iostr) + { + Cookie* cookie = new Cookie; + cookie->istr = &iostr; + cookie->ostr = &iostr; + + cookie_io_functions_t io_funcs; + io_funcs.read = &cookie_read; + io_funcs.write = &cookie_write; + io_funcs.seek = &cookie_seek; + io_funcs.close = &cookie_close; + + return fopencookie(reinterpret_cast(cookie), "r+", io_funcs); + } +} diff --git a/libdimensionxx/dimensionxx.hpp b/libdimensionxx/dimensionxx.hpp index a9e89d8..7714f73 100644 --- a/libdimensionxx/dimensionxx.hpp +++ b/libdimensionxx/dimensionxx.hpp @@ -21,9 +21,16 @@ #ifndef DIMENSIONXX_HPP #define DIMENSIONXX_HPP -/* More includes */ +// Internal helpers +#include + +// libdimension wrappers +#include #include #include #include +// libdimension-png wrapper +#include + #endif /* DIMENSIONXX_HPP */ diff --git a/libdimensionxx/dimensionxx/canvas.hpp b/libdimensionxx/dimensionxx/canvas.hpp index f51aa75..c501413 100644 --- a/libdimensionxx/dimensionxx/canvas.hpp +++ b/libdimensionxx/dimensionxx/canvas.hpp @@ -26,10 +26,14 @@ namespace Dimension class Canvas { public: - Canvas(unsigned int x, unsigned int y) - : m_canvas(dmnsn_new_canvas(x, y)) { } + Canvas(unsigned int width, unsigned int height) + : m_canvas(dmnsn_new_canvas(width, height)) { } + explicit Canvas(dmnsn_canvas* canvas) : m_canvas(canvas) { } virtual ~Canvas(); + unsigned int width() const { return m_canvas->x; } + unsigned int height() const { return m_canvas->y; } + Color pixel(unsigned int x, unsigned int y) const { return Color(dmnsn_get_pixel(m_canvas, x, y)); } void pixel(unsigned int x, unsigned int y, const Color& c) @@ -38,9 +42,12 @@ namespace Dimension dmnsn_canvas* dmnsn() { return m_canvas; } const dmnsn_canvas* dmnsn() const { return m_canvas; } - private: + protected: + Canvas() : m_canvas(0) { } + dmnsn_canvas* m_canvas; + private: // Copying prohibited Canvas(const Canvas&); Canvas& operator=(const Canvas&); diff --git a/libdimensionxx/dimensionxx/color.hpp b/libdimensionxx/dimensionxx/color.hpp index 5db041a..afd7ea5 100644 --- a/libdimensionxx/dimensionxx/color.hpp +++ b/libdimensionxx/dimensionxx/color.hpp @@ -51,6 +51,8 @@ namespace Dimension double trans(double t) { m_color.trans = t; } // Color& operator=(const Color& c); + Color& operator+=(const Color& c) + { m_color = dmnsn_color_add(m_color, c.m_color); return *this; } dmnsn_color dmnsn() const { return m_color; } @@ -61,6 +63,7 @@ namespace Dimension class CIE_XYZ { public: + CIE_XYZ() { } CIE_XYZ(double X, double Y, double Z) { m_XYZ.X = X; m_XYZ.Y = Y; m_XYZ.Z = Z; } CIE_XYZ(const Color& c) : m_XYZ(dmnsn_XYZ_from_color(c.dmnsn())) { } @@ -85,6 +88,7 @@ namespace Dimension class CIE_xyY { public: + CIE_xyY() { } CIE_xyY(double x, double y, double Y) { m_xyY.x = x; m_xyY.y = y; m_xyY.Y = Y; } CIE_xyY(const Color& c) : m_xyY(dmnsn_xyY_from_color(c.dmnsn())) { } @@ -109,6 +113,7 @@ namespace Dimension class CIE_Lab { public: + CIE_Lab() { } CIE_Lab(double L, double a, double b) { m_Lab.L = L; m_Lab.a = a; m_Lab.b = b; } CIE_Lab(const Color& c, const CIE_XYZ& white = whitepoint) @@ -134,6 +139,7 @@ namespace Dimension class CIE_Luv { public: + CIE_Luv() { } CIE_Luv(double L, double u, double v) { m_Luv.L = L; m_Luv.u = u; m_Luv.v = v; } CIE_Luv(const Color& c, const CIE_XYZ& white = whitepoint) @@ -159,6 +165,7 @@ namespace Dimension class sRGB { public: + sRGB() { } sRGB(double R, double G, double B) { m_RGB.R = R; m_RGB.G = G; m_RGB.B = B; } sRGB(const Color& c) : m_RGB(dmnsn_sRGB_from_color(c.dmnsn())) { } @@ -180,6 +187,8 @@ namespace Dimension dmnsn_sRGB m_RGB; }; + // Color inline constructors + inline Color::Color(const CIE_XYZ& XYZ) : m_color(dmnsn_color_from_XYZ(XYZ.dmnsn())) { } @@ -194,6 +203,22 @@ namespace Dimension inline Color::Color(const sRGB& RGB) : m_color(dmnsn_color_from_sRGB(RGB.dmnsn())) { } + + // Color operators + + inline Color + operator+(const Color& lhs, const Color& rhs) + { + Color temp = lhs; + temp += rhs; + return temp; + } + + inline double + operator-(const Color& lhs, const Color& rhs) + { + return dmnsn_color_difference(lhs.dmnsn(), rhs.dmnsn()); + } } #endif /* DIMENSIONXX_COLOR_HPP */ diff --git a/libdimensionxx/dimensionxx/cookie.hpp b/libdimensionxx/dimensionxx/cookie.hpp new file mode 100644 index 0000000..acb783d --- /dev/null +++ b/libdimensionxx/dimensionxx/cookie.hpp @@ -0,0 +1,35 @@ +/************************************************************************* + * 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 DIMENSIONXX_COOKIE_HPP +#define DIMENSIONXX_COOKIE_HPP + +#include +#include +#include + +namespace Dimension +{ + std::FILE* fcookie(std::istream& istr); + std::FILE* fcookie(std::ostream& ostr); + std::FILE* fcookie(std::iostream& iostr); +} + +#endif /* DIMENSIONXX_COOKIE_HPP */ diff --git a/libdimensionxx/dimensionxx/error.hpp b/libdimensionxx/dimensionxx/error.hpp new file mode 100644 index 0000000..a6a4ca6 --- /dev/null +++ b/libdimensionxx/dimensionxx/error.hpp @@ -0,0 +1,30 @@ +/************************************************************************* + * 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 DIMENSIONXX_ERROR_HPP +#define DIMENSIONXX_ERROR_HPP + +#include + +namespace Dimension +{ +} + +#endif /* DIMENSIONXX_ERROR_HPP */ diff --git a/libdimensionxx/dimensionxx/png.hpp b/libdimensionxx/dimensionxx/png.hpp new file mode 100644 index 0000000..96ab2ca --- /dev/null +++ b/libdimensionxx/dimensionxx/png.hpp @@ -0,0 +1,59 @@ +/************************************************************************* + * 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 DIMENSIONXX_PNG_HPP +#define DIMENSIONXX_PNG_HPP + +#include +#include + +namespace Dimension +{ + class PNG_Canvas : public Canvas + { + public: + explicit PNG_Canvas(std::istream& istr) + : Canvas(), m_istr(&istr), m_ostr(0), m_written(false) { read(); } + PNG_Canvas(unsigned int x, unsigned int y, std::ostream& ostr) + : Canvas(x, y), m_istr(0), m_ostr(&ostr), m_written(false) { } + PNG_Canvas(std::istream& istr, std::ostream& ostr) + : Canvas(), m_istr(&istr), m_ostr(&ostr), m_written(false) { read(); } + virtual ~PNG_Canvas(); + + void write(); + + protected: + PNG_Canvas(std::ostream* ostr) + : Canvas(), m_istr(0), m_ostr(ostr), m_written(false) { } + + private: + std::istream* m_istr; + std::ostream* m_ostr; + bool m_written; + + void read(); + + // Copying prohibited + PNG_Canvas(const PNG_Canvas&); + PNG_Canvas& operator=(const PNG_Canvas&); + }; +} + +#endif /* DIMENSIONXX_PNG_HPP */ diff --git a/libdimensionxx/png.cpp b/libdimensionxx/png.cpp new file mode 100644 index 0000000..14b8c4d --- /dev/null +++ b/libdimensionxx/png.cpp @@ -0,0 +1,96 @@ +/************************************************************************* + * 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 "dimensionxx.hpp" +#include "../libdimension-png/dimension-png.h" + +namespace Dimension +{ + PNG_Canvas::~PNG_Canvas() + { + if (m_ostr && !m_written) { + try { + write(); + } catch (...) { + dmnsn_error(DMNSN_SEVERITY_MEDIUM, + "Writing canvas to PNG failed in PNG_Canvas destructor."); + } + } + } + + void PNG_Canvas::write() + { + if (m_written) { + dmnsn_error(DMNSN_SEVERITY_MEDIUM, + "Attempt to write canvas to PNG twice."); + return; + } + + if (!m_ostr) { + dmnsn_error(DMNSN_SEVERITY_MEDIUM, + "Attempt to write canvas to PNG without an output stream."); + return; + } + + FILE* file = fcookie(*m_ostr); + if (!file) { + dmnsn_error(DMNSN_SEVERITY_MEDIUM, + "Couldn't create C++/C IO interface when writing canvas" + " to PNG."); + return; + } + + if (dmnsn_png_write_canvas(m_canvas, file)) { + fclose(file); + dmnsn_error(DMNSN_SEVERITY_MEDIUM, + "Writing canvas to PNG failed."); + return; + } + + fclose(file); + m_written = true; + } + + void PNG_Canvas::read() + { + if (!m_istr) { + dmnsn_error(DMNSN_SEVERITY_MEDIUM, + "Attempt to read canvas from PNG without an input stream."); + return; + } + + FILE* file = fcookie(*m_istr); + if (!file) { + dmnsn_error(DMNSN_SEVERITY_MEDIUM, + "Couldn't create C++/C IO interface when reading canvas" + " from PNG."); + return; + } + + if (!(m_canvas = dmnsn_png_read_canvas(file))) { + fclose(file); + dmnsn_error(DMNSN_SEVERITY_MEDIUM, + "Reading canvas from PNG failed."); + return; + } + + fclose(file); + } +} diff --git a/tests/Makefile.am b/tests/Makefile.am index f23b469..a11f18a 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -17,11 +17,11 @@ ## along with this program. If not, see . ## ########################################################################### -check_PROGRAMS = warning error png +check_PROGRAMS = warning error png pngxx TESTS = $(check_PROGRAMS) XFAIL_TESTS = error -INCLUDES = -I../libdimension -I../libdimension-png +INCLUDES = -I../libdimension -I../libdimension-png -I../libdimensionxx warning_SOURCES = warning.c warning_LDADD = ../libdimension/libdimension.la @@ -31,3 +31,6 @@ error_LDADD = ../libdimension/libdimension.la png_SOURCES = png.c png_LDADD = ../libdimension/libdimension.la ../libdimension-png/libdimension-png.la + +pngxx_SOURCES = pngxx.cpp +pngxx_LDADD = ../libdimensionxx/libdimensionxx.la diff --git a/tests/png.c b/tests/png.c index b7edd95..0ee7edb 100644 --- a/tests/png.c +++ b/tests/png.c @@ -33,7 +33,7 @@ int main() { dmnsn_sRGB sRGB; FILE *ofile, *ifile; unsigned int i, j; - const unsigned int x = 300, y = 300; + const unsigned int x = 333, y = 300; dmnsn_set_resilience(DMNSN_SEVERITY_LOW); @@ -121,7 +121,7 @@ int main() { return EXIT_FAILURE; } - if (dmnsn_png_read_canvas(&canvas, ifile)) { + if (!(canvas = dmnsn_png_read_canvas(ifile))) { fprintf(stderr, "--- Reading canvas failed! ---\n"); return EXIT_FAILURE; } diff --git a/tests/pngxx b/tests/pngxx new file mode 100755 index 0000000..436e7d8 --- /dev/null +++ b/tests/pngxx @@ -0,0 +1,148 @@ +#! /bin/sh + +# pngxx - temporary wrapper script for .libs/pngxx +# Generated by ltmain.sh (GNU libtool) 2.2.6 +# +# The pngxx program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='/bin/sed -e 1s/^X//' +sed_quote_subst='s/\([`"$\\]\)/\\\1/g' + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command="(cd /home/tavianator/dimension/tests; { test -z \"\${LIBRARY_PATH+set}\" || unset LIBRARY_PATH || { LIBRARY_PATH=; export LIBRARY_PATH; }; }; { test -z \"\${COMPILER_PATH+set}\" || unset COMPILER_PATH || { COMPILER_PATH=; export COMPILER_PATH; }; }; { test -z \"\${GCC_EXEC_PREFIX+set}\" || unset GCC_EXEC_PREFIX || { GCC_EXEC_PREFIX=; export GCC_EXEC_PREFIX; }; }; { test -z \"\${LD_RUN_PATH+set}\" || unset LD_RUN_PATH || { LD_RUN_PATH=; export LD_RUN_PATH; }; }; { test -z \"\${LD_LIBRARY_PATH+set}\" || unset LD_LIBRARY_PATH || { LD_LIBRARY_PATH=; export LD_LIBRARY_PATH; }; }; PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/bin/perlbin/site:/usr/bin/perlbin/vendor:/usr/bin/perlbin/core:/opt/qt/bin; export PATH; g++ -g -O2 -o \$progdir/\$file pngxx.o ../libdimensionxx/.libs/libdimensionxx.so /home/tavianator/dimension/libdimension/.libs/libdimension.so -lm -lpthread /home/tavianator/dimension/libdimension-png/.libs/libdimension-png.so -lpng -Wl,-rpath -Wl,/home/tavianator/dimension/libdimensionxx/.libs -Wl,-rpath -Wl,/home/tavianator/dimension/libdimension/.libs -Wl,-rpath -Wl,/home/tavianator/dimension/libdimension-png/.libs)" + +# This environment variable determines our operation mode. +if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then + # install mode needs the following variables: + generated_by_libtool_version='2.2.6' + notinst_deplibs=' ../libdimensionxx/libdimensionxx.la /home/tavianator/dimension/libdimension/libdimension.la /home/tavianator/dimension/libdimension-png/libdimension-png.la' +else + # When we are sourced in execute mode, $file and $ECHO are already set. + if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then + ECHO="echo" + file="$0" + # Make sure echo works. + if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift + elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t'; then + # Yippee, $ECHO works! + : + else + # Restart under the correct shell, and then maybe $ECHO will work. + exec /bin/sh "$0" --no-reexec ${1+"$@"} + fi + fi + + # Find the directory that this script lives in. + thisdir=`$ECHO "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "x$thisdir" = "x$file" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=`ls -ld "$file" | /bin/sed -n 's/.*-> //p'` + while test -n "$file"; do + destdir=`$ECHO "X$file" | $Xsed -e 's%/[^/]*$%%'` + + # If there was a directory component, then change thisdir. + if test "x$destdir" != "x$file"; then + case "$destdir" in + [\\/]* | [A-Za-z]:[\\/]*) thisdir="$destdir" ;; + *) thisdir="$thisdir/$destdir" ;; + esac + fi + + file=`$ECHO "X$file" | $Xsed -e 's%^.*/%%'` + file=`ls -ld "$thisdir/$file" | /bin/sed -n 's/.*-> //p'` + done + + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=no + if test "$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR" = "yes"; then + # special case for '.' + if test "$thisdir" = "."; then + thisdir=`pwd` + fi + # remove .libs from thisdir + case "$thisdir" in + *[\\/].libs ) thisdir=`$ECHO "X$thisdir" | $Xsed -e 's%[\\/][^\\/]*$%%'` ;; + .libs ) thisdir=. ;; + esac + fi + + # Try to get the absolute directory name. + absdir=`cd "$thisdir" && pwd` + test -n "$absdir" && thisdir="$absdir" + + program=lt-'pngxx' + progdir="$thisdir/.libs" + + if test ! -f "$progdir/$program" || + { file=`ls -1dt "$progdir/$program" "$progdir/../$program" 2>/dev/null | /bin/sed 1q`; \ + test "X$file" != "X$progdir/$program"; }; then + + file="$$-$program" + + if test ! -d "$progdir"; then + mkdir "$progdir" + else + rm -f "$progdir/$file" + fi + + # relink executable if necessary + if test -n "$relink_command"; then + if relink_command_output=`eval $relink_command 2>&1`; then : + else + echo "$relink_command_output" >&2 + rm -f "$progdir/$file" + exit 1 + fi + fi + + mv -f "$progdir/$file" "$progdir/$program" 2>/dev/null || + { rm -f "$progdir/$program"; + mv -f "$progdir/$file" "$progdir/$program"; } + rm -f "$progdir/$file" + fi + + if test -f "$progdir/$program"; then + if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then + # Run the actual program with our arguments. + + exec "$progdir/$program" ${1+"$@"} + + $ECHO "$0: cannot exec $program $*" 1>&2 + exit 1 + fi + else + # The program doesn't exist. + $ECHO "$0: error: \`$progdir/$program' does not exist" 1>&2 + $ECHO "This script is just a wrapper for $program." 1>&2 + echo "See the libtool documentation for more information." 1>&2 + exit 1 + fi +fi diff --git a/tests/pngxx.cpp b/tests/pngxx.cpp new file mode 100644 index 0000000..ed7cffd --- /dev/null +++ b/tests/pngxx.cpp @@ -0,0 +1,102 @@ +/************************************************************************* + * Copyright (C) 2008 Tavian Barnes * + * * + * This file is part of The Dimension Test Suite. * + * * + * Dimension 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. * + * * + * Dimension 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 "../libdimensionxx/dimensionxx.hpp" +#include + +int +main() +{ + dmnsn_set_resilience(DMNSN_SEVERITY_LOW); + + const unsigned int width = 333, height = 300; + + { + std::ofstream ofstr("dimensionxx1.png", std::ios::binary); + Dimension::PNG_Canvas ocanvas(3*width, height, ofstr); + + Dimension::CIE_xyY xyY; + Dimension::CIE_Lab Lab; + Dimension::CIE_Luv Luv; + Dimension::sRGB RGB; + Dimension::Color color; + + for (unsigned int x = 0; x < width; ++x) { + for (unsigned int y = 0; y < height; ++y) { + /* CIE xyY colorspace */ + xyY = Dimension::CIE_xyY(static_cast(x)/(width - 1), + static_cast(y)/(height - 1), + 0.5); + color = xyY; + RGB = color; + + if (RGB.R() > 1.0 || RGB.G() > 1.0 || RGB.B() > 1.0 + || RGB.R() < 0.0 || RGB.G() < 0.0 || RGB.B() < 0.0) { + /* Out of sRGB gamut */ + color.trans(0.5); + } + + ocanvas.pixel(x, y, color); + + /* CIE Lab colorspace */ + + Lab = Dimension::CIE_Lab(75.0, + 200.0*(static_cast(x)/ + (width - 1) - 0.5), + 200.0*(static_cast(y)/ + (height - 1) - 0.5)); + color = Lab; + RGB = color; + + if (RGB.R() > 1.0 || RGB.G() > 1.0 || RGB.B() > 1.0 + || RGB.R() < 0.0 || RGB.G() < 0.0 || RGB.B() < 0.0) { + /* Out of sRGB gamut */ + color.trans(0.5); + } + + ocanvas.pixel(x + width, y, color); + + /* CIE Luv colorspace */ + + Luv = Dimension::CIE_Luv(75.0, + 200.0*(static_cast(x)/ + (width - 1) - 0.5), + 200.0*(static_cast(y)/ + (height - 1) - 0.5)); + color = Luv; + RGB = color; + + if (RGB.R() > 1.0 || RGB.G() > 1.0 || RGB.B() > 1.0 + || RGB.R() < 0.0 || RGB.G() < 0.0 || RGB.B() < 0.0) { + /* Out of sRGB gamut */ + color.trans(0.5); + } + + ocanvas.pixel(x + 2*width, y, color); + } + } + } + + std::ifstream ifstr("dimensionxx1.png", std::ios::binary); + std::ofstream ofstr("dimensionxx2.png", std::ios::binary); + Dimension::PNG_Canvas iocanvas(ifstr, ofstr); + + return 0; +} -- cgit v1.2.3