png_reader.cpp

Go to the documentation of this file.
00001 /*
00002   CLAW - a C++ Library Absolutely Wonderful
00003 
00004   CLAW is a free library without any particular aim but being useful to 
00005   anyone.
00006 
00007   Copyright (C) 2005-2008 Julien Jorge
00008 
00009   This library is free software; you can redistribute it and/or
00010   modify it under the terms of the GNU Lesser General Public
00011   License as published by the Free Software Foundation; either
00012   version 2.1 of the License, or (at your option) any later version.
00013 
00014   This library is distributed in the hope that it will be useful,
00015   but WITHOUT ANY WARRANTY; without even the implied warranty of
00016   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017   Lesser General Public License for more details.
00018 
00019   You should have received a copy of the GNU Lesser General Public
00020   License along with this library; if not, write to the Free Software
00021   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00022 
00023   contact: julien_jorge@yahoo.fr
00024 */
00030 #include <claw/png.hpp>
00031 
00032 #include <claw/exception.hpp>
00033 #include <claw/assert.hpp>
00034 
00035 #include <limits>
00036 
00037 /*----------------------------------------------------------------------------*/
00044 void claw__graphic__png__source_manager__read
00045 ( png_structp png_ptr, png_bytep data, png_size_t length )
00046 {
00047   claw::graphic::png::reader::source_manager* self =
00048     (claw::graphic::png::reader::source_manager*)png_get_io_ptr(png_ptr);
00049 
00050   self->read(data, length);
00051 } // claw__graphic__png__source_manager__read()
00052 
00053 
00054 
00055 
00056 /*----------------------------------------------------------------------------*/
00061 claw::graphic::png::reader::source_manager::source_manager( std::istream& is )
00062   : m_input(is)
00063 {
00064   CLAW_PRECOND( !!is );
00065 } // png::reader::source_manager::source_manager()
00066 
00067 /*----------------------------------------------------------------------------*/
00073 void claw::graphic::png::reader::source_manager::read
00074 ( png_bytep data, png_size_t length )
00075 {
00076   m_input.read( (char*)data, length * sizeof(png_byte) );
00077 } // png::reader::source_manager::read()
00078 
00079 
00080 
00081 
00082 /*----------------------------------------------------------------------------*/
00083 const unsigned int claw::graphic::png::reader::s_rgba_pixel_size = 4;
00084 
00085 /*----------------------------------------------------------------------------*/
00090 claw::graphic::png::reader::reader( image& img )
00091   : m_image( img )
00092 {
00093 
00094 } // png::reader::reader()
00095 
00096 /*----------------------------------------------------------------------------*/
00103 claw::graphic::png::reader::reader( image& img, std::istream& f )
00104   : m_image( img )
00105 {
00106   load(f);
00107 } // png::reader::reader()
00108 
00109 /*----------------------------------------------------------------------------*/
00114 void claw::graphic::png::reader::load( std::istream& f )
00115 {
00116   CLAW_PRECOND( !!f );
00117 
00118   std::istream::pos_type init_pos = f.tellg();
00119 
00120   try
00121     {
00122       read_from_file(f);
00123     }
00124   catch(...)
00125     {
00126       f.clear();
00127       f.seekg( init_pos, std::ios_base::beg );
00128       throw;
00129     }
00130 } // png::reader::load()
00131 
00132 /*----------------------------------------------------------------------------*/
00137 void claw::graphic::png::reader::read_from_file( std::istream& f )
00138 {
00139   source_manager infile(f);
00140   png_structp png_ptr;
00141   png_infop info_ptr;
00142 
00143   create_read_structures(png_ptr, info_ptr);
00144 
00145   if (setjmp(png_jmpbuf(png_ptr)))
00146     {
00147       /* If we get here, we had a problem reading the file */
00148       /* Free all of the memory associated with the png_ptr and info_ptr */
00149       png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
00150       throw CLAW_EXCEPTION("Invalid PNG file.");
00151     }
00152       
00153   check_if_png( png_ptr, f );
00154 
00155   png_set_read_fn( png_ptr, (void *)&infile,
00156                    claw__graphic__png__source_manager__read );
00157 
00158   png_set_strip_16(png_ptr);
00159   png_set_gray_1_2_4_to_8(png_ptr);
00160   png_set_packing(png_ptr);
00161 
00162   // transform palette index into RGB value
00163   png_set_palette_to_rgb(png_ptr);
00164 
00165   // add an alpha value if none
00166   png_set_filler( png_ptr,
00167                   std::numeric_limits<rgba_pixel_8::component_type>::max(),
00168                   PNG_FILLER_AFTER );
00169 
00170   png_read_info(png_ptr, info_ptr);
00171   read_image( png_ptr, info_ptr );
00172       
00173   png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
00174 } // png::reader::read_from_file()
00175 
00176 /*----------------------------------------------------------------------------*/
00182 void claw::graphic::png::reader::check_if_png
00183 ( png_structp png_ptr, std::istream& f ) const
00184 {
00185   CLAW_PRECOND( !!f );
00186 
00187   const unsigned int bytes_to_check = 8;
00188   png_byte buffer[bytes_to_check];
00189 
00190   /* Read in some of the signature bytes */
00191   f.read( (char*)buffer, bytes_to_check * sizeof(png_byte) );
00192 
00193   if ( (png_sig_cmp(buffer, (png_size_t)0, bytes_to_check) != 0) || !f )
00194     throw CLAW_EXCEPTION( "Not a PNG file." );
00195 
00196   png_set_sig_bytes(png_ptr, bytes_to_check);
00197 } // png::reader::check_if_png()
00198 
00199 /*----------------------------------------------------------------------------*/
00205 void claw::graphic::png::reader::read_image
00206 ( png_structp png_ptr, png_infop info_ptr )
00207 {
00208   CLAW_PRECOND( png_ptr );
00209   CLAW_PRECOND( info_ptr );
00210 
00211   m_image.set_size( png_get_image_width(png_ptr, info_ptr),
00212                     png_get_image_height(png_ptr, info_ptr) );
00213 
00214   if ( png_get_interlace_type(png_ptr, info_ptr) == PNG_INTERLACE_NONE )
00215     read_sequential_image(png_ptr, info_ptr);
00216   else
00217     read_interlaced_image( png_ptr, info_ptr,
00218                            png_set_interlace_handling(png_ptr) );
00219 } // png::reader::read_image()
00220 
00221 /*----------------------------------------------------------------------------*/
00227 void claw::graphic::png::reader::read_sequential_image
00228 ( png_structp png_ptr, png_infop info_ptr )
00229 {
00230   CLAW_PRECOND( png_ptr );
00231   CLAW_PRECOND( info_ptr );
00232 
00233   png_bytep data =
00234     (png_bytep)png_malloc( png_ptr, s_rgba_pixel_size * m_image.width() );
00235 
00236   try
00237     {
00238       for (unsigned int y=0; y!=m_image.height(); ++y)
00239         {
00240           png_read_row(png_ptr, data, NULL);
00241           copy_pixel_line( data, y );
00242         }
00243     }
00244   catch(...)
00245     {
00246       png_free(png_ptr, data);
00247       throw;
00248     }
00249 
00250   png_free(png_ptr, data);
00251 } // png::reader::read_sequential_image()
00252 
00253 /*----------------------------------------------------------------------------*/
00260 void claw::graphic::png::reader::read_interlaced_image
00261 ( png_structp png_ptr, png_infop info_ptr, unsigned int passes )
00262 {
00263   CLAW_PRECOND( passes > 1 );
00264   CLAW_PRECOND( png_ptr );
00265   CLAW_PRECOND( info_ptr );
00266 
00267   const unsigned int row_length = s_rgba_pixel_size * m_image.width();
00268   png_bytepp data =
00269     (png_bytepp)png_malloc( png_ptr, sizeof(png_bytep) * m_image.height() );
00270   unsigned int i=0;
00271 
00272   try
00273     {
00274       for (i=0; i!=m_image.height(); ++i)
00275         {
00276           data[i] = (png_bytep)png_malloc( png_ptr, row_length );
00277 
00278           if (!data[i])
00279             throw std::bad_alloc();
00280 
00281           copy_pixel_line( data[i], i );
00282         }
00283 
00284       for (unsigned int p=0; p!=passes; ++p)
00285         png_read_rows( png_ptr, data, NULL, m_image.height() );
00286 
00287       for (unsigned int y=0; y!=m_image.height(); ++y)
00288         copy_pixel_line( data[y], y );
00289     }
00290   catch(...)
00291     {
00292       for(unsigned int j=0; j!=i; ++j)
00293         png_free(png_ptr, data[j]);
00294 
00295       png_free(png_ptr, data);
00296       throw;
00297     }
00298 
00299   for(i=0; i!=m_image.height(); ++i)
00300     png_free(png_ptr, data[i]);
00301 
00302   png_free(png_ptr, data);
00303 } // png::reader::read_interlaced_image()
00304 
00305 /*----------------------------------------------------------------------------*/
00311 void
00312 claw::graphic::png::reader::copy_pixel_line( png_bytep data, unsigned int y )
00313 {
00314   CLAW_PRECOND( data );
00315   CLAW_PRECOND( y < m_image.height() );
00316 
00317   // four bytes for each pixel in the line
00318   for (unsigned int x=0; x!=m_image.width(); ++x, data+=s_rgba_pixel_size)
00319     {
00320       m_image[y][x].components.red   = data[0];
00321       m_image[y][x].components.green = data[1];
00322       m_image[y][x].components.blue  = data[2];
00323       m_image[y][x].components.alpha = data[3];
00324     }
00325 } // png::reader::copy_pixel_line()
00326 
00327 /*----------------------------------------------------------------------------*/
00333 void claw::graphic::png::reader::create_read_structures
00334 ( png_structp& png_ptr, png_infop& info_ptr ) const
00335 {
00336   png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
00337 
00338   if (png_ptr)
00339     {
00340       info_ptr = png_create_info_struct(png_ptr);
00341 
00342       if (!info_ptr)
00343         png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
00344     }
00345 
00346   if (!png_ptr || !info_ptr)
00347     throw CLAW_EXCEPTION("Can't create PNG read structures.");
00348 } // png::reader::create_read_structures()

Generated on 9 Nov 2009 for CLAW Library (a C++ Library Absolutely Wonderful) by  doxygen 1.6.1