Claw
1.7.0
|
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-2011 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@gamned.org 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_expand_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()