00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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 }
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 }
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 }
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 }
00095
00096
00103 claw::graphic::png::reader::reader( image& img, std::istream& f )
00104 : m_image( img )
00105 {
00106 load(f);
00107 }
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 }
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
00148
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
00163 png_set_palette_to_rgb(png_ptr);
00164
00165
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 }
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
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 }
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 }
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 }
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 }
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
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 }
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 }