1 /* 2 * Copyright (C) 2007,2008 Alex Shulgin 3 * 4 * This file is part of png++ the C++ wrapper for libpng. PNG++ is free 5 * software; the exact copying conditions are as follows: 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright notice, 11 * this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 23 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 25 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 #ifndef PNGPP_IMAGE_HPP_INCLUDED 32 #define PNGPP_IMAGE_HPP_INCLUDED 33 34 #include <fstream> 35 #include "pixel_buffer.hpp" 36 #include "generator.hpp" 37 #include "consumer.hpp" 38 #include "convert_color_space.hpp" 39 40 namespace png 41 { 42 43 /** 44 * \brief Class template to represent PNG image. 45 * 46 * The image consists of pixel data as well as additional %image 47 * %info like interlace type, compression method, palette (for 48 * colormap-based images) etc. Provides methods to read and write 49 * images from/to a generic stream and to manipulate %image pixels. 50 * 51 * The default pixel_buffer stores pixels in a vector of vectors, which 52 * is good for openning, editing or converting an image to any 53 * pixel type. 54 * But for simple and fast image unpacking to one memory chunk this approch 55 * is unacceptable, because it leads to multiple memory allocations, the 56 * unpacked image is spread across the memory and client code needs to 57 * gather it manualy. solid_pixel_buffer solves this problem, but with 58 * restriction: pixels with fractional number of bytes per channel are 59 * not allowed (see solid_pixel_buffer.hpp for details). 60 */ 61 template< typename pixel, typename pixel_buffer_type = pixel_buffer< pixel > > 62 class image 63 { 64 public: 65 /** 66 * \brief The pixel traits type for \c pixel. 67 */ 68 typedef pixel_traits< pixel > traits; 69 70 /** 71 * \brief The pixel buffer type for \c pixel. 72 */ 73 typedef pixel_buffer_type pixbuf; 74 75 /** 76 * \brief Represents a row of image pixel data. 77 */ 78 typedef typename pixbuf::row_type row_type; 79 typedef typename pixbuf::row_access row_access; 80 typedef typename pixbuf::row_const_access row_const_access; 81 82 /** 83 * \brief A transformation functor to convert any image to 84 * appropriate color space. 85 */ 86 typedef convert_color_space< pixel > transform_convert; 87 88 /** 89 * \brief The default io transformation: does nothing. 90 */ 91 struct transform_identity 92 { operator ()png::image::transform_identity93 void operator()(io_base&) const {} 94 }; 95 96 /** 97 * \brief Constructs an empty image. 98 */ image()99 image() 100 : m_info(make_image_info< pixel >()) 101 { 102 } 103 104 /** 105 * \brief Constructs an empty image of specified width and height. 106 */ image(uint_32 width,uint_32 height)107 image(uint_32 width, uint_32 height) 108 : m_info(make_image_info< pixel >()) 109 { 110 resize(width, height); 111 } 112 113 /** 114 * \brief Constructs an image reading data from specified file 115 * using default converting transform. 116 */ image(std::string const & filename)117 explicit image(std::string const& filename) 118 { 119 read(filename, transform_convert()); 120 } 121 122 /** 123 * \brief Constructs an image reading data from specified file 124 * using custom transformaton. 125 */ 126 template< class transformation > image(std::string const & filename,transformation const & transform)127 image(std::string const& filename, 128 transformation const& transform) 129 { 130 read(filename.c_str(), transform); 131 } 132 133 /** 134 * \brief Constructs an image reading data from specified file 135 * using default converting transform. 136 */ image(char const * filename)137 explicit image(char const* filename) 138 { 139 read(filename, transform_convert()); 140 } 141 142 /** 143 * \brief Constructs an image reading data from specified file 144 * using custom transformaton. 145 */ 146 template< class transformation > image(char const * filename,transformation const & transform)147 image(char const* filename, transformation const& transform) 148 { 149 read(filename, transform); 150 } 151 152 /** 153 * \brief Constructs an image reading data from a stream using 154 * default converting transform. 155 */ image(std::istream & stream)156 explicit image(std::istream& stream) 157 { 158 read_stream(stream, transform_convert()); 159 } 160 161 /** 162 * \brief Constructs an image reading data from a stream using 163 * custom transformation. 164 */ 165 template< class transformation > image(std::istream & stream,transformation const & transform)166 image(std::istream& stream, transformation const& transform) 167 { 168 read_stream(stream, transform); 169 } 170 171 /** 172 * \brief Reads an image from specified file using default 173 * converting transform. 174 */ read(std::string const & filename)175 void read(std::string const& filename) 176 { 177 read(filename, transform_convert()); 178 } 179 180 /** 181 * \brief Reads an image from specified file using custom 182 * transformaton. 183 */ 184 template< class transformation > read(std::string const & filename,transformation const & transform)185 void read(std::string const& filename, transformation const& transform) 186 { 187 read(filename.c_str(), transform); 188 } 189 190 /** 191 * \brief Reads an image from specified file using default 192 * converting transform. 193 */ read(char const * filename)194 void read(char const* filename) 195 { 196 read(filename, transform_convert()); 197 } 198 199 /** 200 * \brief Reads an image from specified file using custom 201 * transformaton. 202 */ 203 template< class transformation > read(char const * filename,transformation const & transform)204 void read(char const* filename, transformation const& transform) 205 { 206 std::ifstream stream(filename, std::ios::binary); 207 if (!stream.is_open()) 208 { 209 throw std_error(filename); 210 } 211 stream.exceptions(std::ios::badbit); 212 read_stream(stream, transform); 213 } 214 215 /** 216 * \brief Reads an image from a stream using default 217 * converting transform. 218 */ read(std::istream & stream)219 void read(std::istream& stream) 220 { 221 read_stream(stream, transform_convert()); 222 } 223 224 /** 225 * \brief Reads an image from a stream using custom 226 * transformation. 227 */ 228 template< class transformation > read(std::istream & stream,transformation const & transform)229 void read(std::istream& stream, transformation const& transform) 230 { 231 read_stream(stream, transform); 232 } 233 234 /** 235 * \brief Reads an image from a stream using default 236 * converting transform. 237 */ 238 template< class istream > read_stream(istream & stream)239 void read_stream(istream& stream) 240 { 241 read_stream(stream, transform_convert()); 242 } 243 244 /** 245 * \brief Reads an image from a stream using custom 246 * transformation. 247 */ 248 template< class istream, class transformation > read_stream(istream & stream,transformation const & transform)249 void read_stream(istream& stream, transformation const& transform) 250 { 251 pixel_consumer pixcon(m_info, m_pixbuf); 252 pixcon.read(stream, transform); 253 } 254 255 /** 256 * \brief Writes an image to specified file. 257 */ write(std::string const & filename)258 void write(std::string const& filename) 259 { 260 write(filename.c_str()); 261 } 262 263 /** 264 * \brief Writes an image to specified file. 265 */ write(char const * filename)266 void write(char const* filename) 267 { 268 std::ofstream stream(filename, std::ios::binary); 269 if (!stream.is_open()) 270 { 271 throw std_error(filename); 272 } 273 stream.exceptions(std::ios::badbit); 274 write_stream(stream); 275 } 276 277 /** 278 * \brief Writes an image to a stream. 279 */ 280 template< class ostream > write_stream(ostream & stream)281 void write_stream(ostream& stream) 282 { 283 pixel_generator pixgen(m_info, m_pixbuf); 284 pixgen.write(stream); 285 } 286 287 /** 288 * \brief Returns a reference to image pixel buffer. 289 */ get_pixbuf()290 pixbuf& get_pixbuf() 291 { 292 return m_pixbuf; 293 } 294 295 /** 296 * \brief Returns a const reference to image pixel buffer. 297 */ get_pixbuf() const298 pixbuf const& get_pixbuf() const 299 { 300 return m_pixbuf; 301 } 302 303 /** 304 * \brief Replaces the image pixel buffer. 305 * 306 * \param buffer a pixel buffer object to take a copy from 307 */ set_pixbuf(pixbuf const & buffer)308 void set_pixbuf(pixbuf const& buffer) 309 { 310 m_pixbuf = buffer; 311 } 312 get_width() const313 uint_32 get_width() const 314 { 315 return m_pixbuf.get_width(); 316 } 317 get_height() const318 uint_32 get_height() const 319 { 320 return m_pixbuf.get_height(); 321 } 322 323 /** 324 * \brief Resizes the image pixel buffer. 325 */ resize(uint_32 width,uint_32 height)326 void resize(uint_32 width, uint_32 height) 327 { 328 m_pixbuf.resize(width, height); 329 m_info.set_width(width); 330 m_info.set_height(height); 331 } 332 333 /** 334 * \brief Returns a reference to the row of image data at 335 * specified index. 336 * 337 * \see pixel_buffer::get_row() 338 */ get_row(size_t index)339 row_access get_row(size_t index) 340 { 341 return m_pixbuf.get_row(index); 342 } 343 344 /** 345 * \brief Returns a const reference to the row of image data at 346 * specified index. 347 * 348 * \see pixel_buffer::get_row() 349 */ get_row(size_t index) const350 row_const_access get_row(size_t index) const 351 { 352 return m_pixbuf.get_row(index); 353 } 354 355 /** 356 * \brief The non-checking version of get_row() method. 357 */ operator [](size_t index)358 row_access operator[](size_t index) 359 { 360 return m_pixbuf[index]; 361 } 362 363 /** 364 * \brief The non-checking version of get_row() method. 365 */ operator [](size_t index) const366 row_const_access operator[](size_t index) const 367 { 368 return m_pixbuf[index]; 369 } 370 371 /** 372 * \brief Returns a pixel at (x,y) position. 373 */ get_pixel(size_t x,size_t y) const374 pixel get_pixel(size_t x, size_t y) const 375 { 376 return m_pixbuf.get_pixel(x, y); 377 } 378 379 /** 380 * \brief Replaces a pixel at (x,y) position. 381 */ set_pixel(size_t x,size_t y,pixel p)382 void set_pixel(size_t x, size_t y, pixel p) 383 { 384 m_pixbuf.set_pixel(x, y, p); 385 } 386 get_interlace_type() const387 interlace_type get_interlace_type() const 388 { 389 return m_info.get_interlace_type(); 390 } 391 set_interlace_type(interlace_type interlace)392 void set_interlace_type(interlace_type interlace) 393 { 394 m_info.set_interlace_type(interlace); 395 } 396 get_compression_type() const397 compression_type get_compression_type() const 398 { 399 return m_info.get_compression_type(); 400 } 401 set_compression_type(compression_type compression)402 void set_compression_type(compression_type compression) 403 { 404 m_info.set_compression_type(compression); 405 } 406 get_filter_type() const407 filter_type get_filter_type() const 408 { 409 return m_info.get_filter_type(); 410 } 411 set_filter_type(filter_type filter)412 void set_filter_type(filter_type filter) 413 { 414 m_info.set_filter_type(filter); 415 } 416 417 /** 418 * \brief Returns a reference to the image palette. 419 */ get_palette()420 palette& get_palette() 421 { 422 return m_info.get_palette(); 423 } 424 425 /** 426 * \brief Returns a const reference to the image palette. 427 */ get_palette() const428 palette const& get_palette() const 429 { 430 return m_info.get_palette(); 431 } 432 433 /** 434 * \brief Replaces the image palette. 435 */ set_palette(palette const & plte)436 void set_palette(palette const& plte) 437 { 438 m_info.set_palette(plte); 439 } 440 get_tRNS() const441 tRNS const& get_tRNS() const 442 { 443 return m_info.get_tRNS(); 444 } 445 get_tRNS()446 tRNS& get_tRNS() 447 { 448 return m_info.get_tRNS(); 449 } 450 set_tRNS(tRNS const & trns)451 void set_tRNS(tRNS const& trns) 452 { 453 m_info.set_tRNS(trns); 454 } 455 get_gamma() const456 double get_gamma() const 457 { 458 return m_info.get_gamma(); 459 } 460 set_gamma(double gamma)461 void set_gamma(double gamma) 462 { 463 m_info.set_gamma(gamma); 464 } 465 466 protected: 467 /** 468 * \brief A common base class template for pixel_consumer and 469 * pixel_generator classes. 470 */ 471 template< typename base_impl > 472 class streaming_impl 473 : public base_impl 474 { 475 public: streaming_impl(image_info & info,pixbuf & pixels)476 streaming_impl(image_info& info, pixbuf& pixels) 477 : base_impl(info), 478 m_pixbuf(pixels) 479 { 480 } 481 482 /** 483 * \brief Returns the starting address of a \c pos-th row 484 * in the image's pixel buffer. 485 */ get_next_row(size_t pos)486 byte* get_next_row(size_t pos) 487 { 488 typedef typename pixbuf::row_traits row_traits; 489 return reinterpret_cast< byte* > 490 (row_traits::get_data(m_pixbuf.get_row(pos))); 491 } 492 493 protected: 494 pixbuf& m_pixbuf; 495 }; 496 497 /** 498 * \brief The pixel buffer adapter for reading pixel data. 499 */ 500 class pixel_consumer 501 : public streaming_impl< consumer< pixel, 502 pixel_consumer, 503 image_info_ref_holder, 504 /* interlacing = */ true > > 505 { 506 public: pixel_consumer(image_info & info,pixbuf & pixels)507 pixel_consumer(image_info& info, pixbuf& pixels) 508 : streaming_impl< consumer< pixel, 509 pixel_consumer, 510 image_info_ref_holder, 511 true > >(info, pixels) 512 { 513 } 514 reset(size_t pass)515 void reset(size_t pass) 516 { 517 if (pass == 0) 518 { 519 this->m_pixbuf.resize(this->get_info().get_width(), 520 this->get_info().get_height()); 521 } 522 } 523 }; 524 525 /** 526 * \brief The pixel buffer adapter for writing pixel data. 527 */ 528 class pixel_generator 529 : public streaming_impl< generator< pixel, 530 pixel_generator, 531 image_info_ref_holder, 532 /* interlacing = */ true > > 533 { 534 public: pixel_generator(image_info & info,pixbuf & pixels)535 pixel_generator(image_info& info, pixbuf& pixels) 536 : streaming_impl< generator< pixel, 537 pixel_generator, 538 image_info_ref_holder, 539 true > >(info, pixels) 540 { 541 } 542 }; 543 544 image_info m_info; 545 pixbuf m_pixbuf; 546 }; 547 548 } // namespace png 549 550 #endif // PNGPP_IMAGE_HPP_INCLUDED 551