Claw
1.7.3
|
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_read_info(png_ptr, info_ptr); 00159 00160 png_set_strip_16(png_ptr); 00161 png_set_expand_gray_1_2_4_to_8(png_ptr); 00162 png_set_packing(png_ptr); 00163 00164 png_set_tRNS_to_alpha(png_ptr); 00165 00166 // transform palette index into RGB value 00167 png_set_palette_to_rgb(png_ptr); 00168 00169 // add an alpha value if none 00170 png_set_filler( png_ptr, 00171 std::numeric_limits<rgba_pixel_8::component_type>::max(), 00172 PNG_FILLER_AFTER ); 00173 00174 png_read_update_info(png_ptr, info_ptr); 00175 00176 read_image( png_ptr, info_ptr ); 00177 00178 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); 00179 } // png::reader::read_from_file() 00180 00181 /*----------------------------------------------------------------------------*/ 00187 void claw::graphic::png::reader::check_if_png 00188 ( png_structp png_ptr, std::istream& f ) const 00189 { 00190 CLAW_PRECOND( !!f ); 00191 00192 const unsigned int bytes_to_check = 8; 00193 png_byte buffer[bytes_to_check]; 00194 00195 /* Read in some of the signature bytes */ 00196 f.read( (char*)buffer, bytes_to_check * sizeof(png_byte) ); 00197 00198 if ( (png_sig_cmp(buffer, (png_size_t)0, bytes_to_check) != 0) || !f ) 00199 throw CLAW_EXCEPTION( "Not a PNG file." ); 00200 00201 png_set_sig_bytes(png_ptr, bytes_to_check); 00202 } // png::reader::check_if_png() 00203 00204 /*----------------------------------------------------------------------------*/ 00210 void claw::graphic::png::reader::read_image 00211 ( png_structp png_ptr, png_infop info_ptr ) 00212 { 00213 CLAW_PRECOND( png_ptr ); 00214 CLAW_PRECOND( info_ptr ); 00215 00216 m_image.set_size( png_get_image_width(png_ptr, info_ptr), 00217 png_get_image_height(png_ptr, info_ptr) ); 00218 00219 if ( png_get_interlace_type(png_ptr, info_ptr) == PNG_INTERLACE_NONE ) 00220 read_sequential_image(png_ptr, info_ptr); 00221 else 00222 read_interlaced_image( png_ptr, info_ptr, 00223 png_set_interlace_handling(png_ptr) ); 00224 } // png::reader::read_image() 00225 00226 /*----------------------------------------------------------------------------*/ 00232 void claw::graphic::png::reader::read_sequential_image 00233 ( png_structp png_ptr, png_infop info_ptr ) 00234 { 00235 CLAW_PRECOND( png_ptr ); 00236 CLAW_PRECOND( info_ptr ); 00237 00238 png_bytep data = 00239 (png_bytep)png_malloc( png_ptr, s_rgba_pixel_size * m_image.width() ); 00240 const png_byte color_type( png_get_color_type(png_ptr, info_ptr) ); 00241 00242 try 00243 { 00244 for (unsigned int y=0; y!=m_image.height(); ++y) 00245 { 00246 png_read_row(png_ptr, data, NULL); 00247 copy_pixel_line( color_type, data, y ); 00248 } 00249 } 00250 catch(...) 00251 { 00252 png_free(png_ptr, data); 00253 throw; 00254 } 00255 00256 png_free(png_ptr, data); 00257 } // png::reader::read_sequential_image() 00258 00259 /*----------------------------------------------------------------------------*/ 00266 void claw::graphic::png::reader::read_interlaced_image 00267 ( png_structp png_ptr, png_infop info_ptr, unsigned int passes ) 00268 { 00269 CLAW_PRECOND( passes > 1 ); 00270 CLAW_PRECOND( png_ptr ); 00271 CLAW_PRECOND( info_ptr ); 00272 00273 const unsigned int row_length = s_rgba_pixel_size * m_image.width(); 00274 png_bytepp data = 00275 (png_bytepp)png_malloc( png_ptr, sizeof(png_bytep) * m_image.height() ); 00276 unsigned int i=0; 00277 const png_byte color_type( png_get_color_type(png_ptr, info_ptr) ); 00278 00279 try 00280 { 00281 for (i=0; i!=m_image.height(); ++i) 00282 { 00283 data[i] = (png_bytep)png_malloc( png_ptr, row_length ); 00284 00285 if (!data[i]) 00286 throw std::bad_alloc(); 00287 00288 copy_pixel_line( color_type, data[i], i ); 00289 } 00290 00291 for (unsigned int p=0; p!=passes; ++p) 00292 png_read_rows( png_ptr, data, NULL, m_image.height() ); 00293 00294 for (unsigned int y=0; y!=m_image.height(); ++y) 00295 copy_pixel_line( color_type, data[y], y ); 00296 } 00297 catch(...) 00298 { 00299 for(unsigned int j=0; j!=i; ++j) 00300 png_free(png_ptr, data[j]); 00301 00302 png_free(png_ptr, data); 00303 throw; 00304 } 00305 00306 for(i=0; i!=m_image.height(); ++i) 00307 png_free(png_ptr, data[i]); 00308 00309 png_free(png_ptr, data); 00310 } // png::reader::read_interlaced_image() 00311 00312 /*----------------------------------------------------------------------------*/ 00319 void 00320 claw::graphic::png::reader::copy_pixel_line 00321 ( png_byte color_type, png_bytep data, unsigned int y ) 00322 { 00323 CLAW_PRECOND( data ); 00324 CLAW_PRECOND( y < m_image.height() ); 00325 00326 if ( color_type == PNG_COLOR_TYPE_GRAY_ALPHA ) 00327 // There is two bytes for each pixel in the line: the color and the opacity. 00328 for (unsigned int x=0; x!=m_image.width(); ++x, data += 2) 00329 { 00330 m_image[y][x].components.red = data[0]; 00331 m_image[y][x].components.green = data[0]; 00332 m_image[y][x].components.blue = data[0]; 00333 m_image[y][x].components.alpha = data[1]; 00334 } 00335 else 00336 // There is four bytes for each pixel in the line. 00337 for (unsigned int x=0; x!=m_image.width(); ++x, data+=s_rgba_pixel_size) 00338 { 00339 m_image[y][x].components.red = data[0]; 00340 m_image[y][x].components.green = data[1]; 00341 m_image[y][x].components.blue = data[2]; 00342 m_image[y][x].components.alpha = data[3]; 00343 } 00344 } // png::reader::copy_pixel_line() 00345 00346 /*----------------------------------------------------------------------------*/ 00352 void claw::graphic::png::reader::create_read_structures 00353 ( png_structp& png_ptr, png_infop& info_ptr ) const 00354 { 00355 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 00356 00357 if (png_ptr) 00358 { 00359 info_ptr = png_create_info_struct(png_ptr); 00360 00361 if (!info_ptr) 00362 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); 00363 } 00364 00365 if (!png_ptr || !info_ptr) 00366 throw CLAW_EXCEPTION("Can't create PNG read structures."); 00367 } // png::reader::create_read_structures()