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, std::numeric_limits<pixel32::component_type>::max(),
00167                   PNG_FILLER_AFTER );
00168 
00169   png_read_info(png_ptr, info_ptr);
00170   read_image( png_ptr, info_ptr );
00171       
00172   png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
00173 } // png::reader::read_from_file()
00174 
00175 /*----------------------------------------------------------------------------*/
00181 void claw::graphic::png::reader::check_if_png
00182 ( png_structp png_ptr, std::istream& f ) const
00183 {
00184   CLAW_PRECOND( !!f );
00185 
00186   const unsigned int bytes_to_check = 8;
00187   png_byte buffer[bytes_to_check];
00188 
00189   /* Read in some of the signature bytes */
00190   f.read( (char*)buffer, bytes_to_check * sizeof(png_byte) );
00191 
00192   if ( (png_sig_cmp(buffer, (png_size_t)0, bytes_to_check) != 0) || !f )
00193     throw CLAW_EXCEPTION( "Not a PNG file." );
00194 
00195   png_set_sig_bytes(png_ptr, bytes_to_check);
00196 } // png::reader::check_if_png()
00197 
00198 /*----------------------------------------------------------------------------*/
00204 void claw::graphic::png::reader::read_image
00205 ( png_structp png_ptr, png_infop info_ptr )
00206 {
00207   CLAW_PRECOND( png_ptr );
00208   CLAW_PRECOND( info_ptr );
00209 
00210   m_image.set_size( png_get_image_width(png_ptr, info_ptr),
00211                     png_get_image_height(png_ptr, info_ptr) );
00212 
00213   if ( png_get_interlace_type(png_ptr, info_ptr) == PNG_INTERLACE_NONE )
00214     read_sequential_image(png_ptr, info_ptr);
00215   else
00216     read_interlaced_image( png_ptr, info_ptr,
00217                            png_set_interlace_handling(png_ptr) );
00218 } // png::reader::read_image()
00219 
00220 /*----------------------------------------------------------------------------*/
00226 void claw::graphic::png::reader::read_sequential_image
00227 ( png_structp png_ptr, png_infop info_ptr )
00228 {
00229   CLAW_PRECOND( png_ptr );
00230   CLAW_PRECOND( info_ptr );
00231 
00232   png_bytep data =
00233     (png_bytep)png_malloc( png_ptr, s_rgba_pixel_size * m_image.width() );
00234 
00235   try
00236     {
00237       for (unsigned int y=0; y!=m_image.height(); ++y)
00238         {
00239           png_read_row(png_ptr, data, NULL);
00240           copy_pixel_line( data, y );
00241         }
00242     }
00243   catch(...)
00244     {
00245       png_free(png_ptr, data);
00246       throw;
00247     }
00248 
00249   png_free(png_ptr, data);
00250 } // png::reader::read_sequential_image()
00251 
00252 /*----------------------------------------------------------------------------*/
00259 void claw::graphic::png::reader::read_interlaced_image
00260 ( png_structp png_ptr, png_infop info_ptr, unsigned int passes )
00261 {
00262   CLAW_PRECOND( passes > 1 );
00263   CLAW_PRECOND( png_ptr );
00264   CLAW_PRECOND( info_ptr );
00265 
00266   const unsigned int row_length = s_rgba_pixel_size * m_image.width();
00267   png_bytepp data =
00268     (png_bytepp)png_malloc( png_ptr, sizeof(png_bytep) * m_image.height() );
00269   unsigned int i=0;
00270 
00271   try
00272     {
00273       for (i=0; i!=m_image.height(); ++i)
00274         {
00275           data[i] = (png_bytep)png_malloc( png_ptr, row_length );
00276 
00277           if (!data[i])
00278             throw std::bad_alloc();
00279 
00280           copy_pixel_line( data[i], i );
00281         }
00282 
00283       for (unsigned int p=0; p!=passes; ++p)
00284         png_read_rows( png_ptr, data, NULL, m_image.height() );
00285 
00286       for (unsigned int y=0; y!=m_image.height(); ++y)
00287         copy_pixel_line( data[y], y );
00288     }
00289   catch(...)
00290     {
00291       for(unsigned int j=0; j!=i; ++j)
00292         png_free(png_ptr, data[j]);
00293 
00294       png_free(png_ptr, data);
00295       throw;
00296     }
00297 
00298   for(i=0; i!=m_image.height(); ++i)
00299     png_free(png_ptr, data[i]);
00300 
00301   png_free(png_ptr, data);
00302 } // png::reader::read_interlaced_image()
00303 
00304 /*----------------------------------------------------------------------------*/
00310 void
00311 claw::graphic::png::reader::copy_pixel_line( png_bytep data, unsigned int y )
00312 {
00313   CLAW_PRECOND( data );
00314   CLAW_PRECOND( y < m_image.height() );
00315 
00316   // four bytes for each pixel in the line
00317   for (unsigned int x=0; x!=m_image.width(); ++x, data+=s_rgba_pixel_size)
00318     {
00319       m_image[y][x].components.red   = data[0];
00320       m_image[y][x].components.green = data[1];
00321       m_image[y][x].components.blue  = data[2];
00322       m_image[y][x].components.alpha = data[3];
00323     }
00324 } // png::reader::copy_pixel_line()
00325 
00326 /*----------------------------------------------------------------------------*/
00332 void claw::graphic::png::reader::create_read_structures
00333 ( png_structp& png_ptr, png_infop& info_ptr ) const
00334 {
00335   png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
00336 
00337   if (png_ptr)
00338     {
00339       info_ptr = png_create_info_struct(png_ptr);
00340 
00341       if (!info_ptr)
00342         png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
00343     }
00344 
00345   if (!png_ptr || !info_ptr)
00346     throw CLAW_EXCEPTION("Can't create PNG read structures.");
00347 } // png::reader::create_read_structures()

Generated on Thu Jun 26 09:35:04 2008 for CLAW Library (a C++ Library Absolutely Wonderful) by  doxygen 1.5.6