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/pcx.hpp> 00031 #include <claw/exception.hpp> 00032 00033 #include <limits> 00034 00035 /*----------------------------------------------------------------------------*/ 00042 void claw::graphic::pcx::reader::converter_mono::operator() 00043 ( const std::vector<color_plane_type>& scanline, image& img, 00044 unsigned int y ) const 00045 { 00046 CLAW_PRECOND( scanline.size() == 1 ); 00047 00048 unsigned int x=0; 00049 00050 for ( unsigned int code=0; x!=img.width(); ++code ) 00051 { 00052 u_int_8 c = scanline[0][code]; // only one color plane for monochrome pcx 00053 00054 for( unsigned int i=0; (i!=8) && (x!=img.width()); ++x, ++i, c<<=1 ) 00055 if ( c & 0x80 ) 00056 img[y][x] = white_pixel; 00057 else 00058 img[y][x] = black_pixel; 00059 } 00060 } // pcx::reader::converter_mono::operator()() 00061 00062 /*----------------------------------------------------------------------------*/ 00067 claw::graphic::pcx::reader::converter_16::converter_16( const header& h ) 00068 : m_header(h) 00069 { 00070 00071 } // pcx::reader::converter_16::converter_16() 00072 00073 /*----------------------------------------------------------------------------*/ 00080 void claw::graphic::pcx::reader::converter_16::operator() 00081 ( const std::vector<color_plane_type>& scanline, image& img, 00082 unsigned int y ) const 00083 { 00084 CLAW_PRECOND( scanline.size() == 4 ); 00085 00086 unsigned int x=0; 00087 00088 for ( unsigned int code=0; x!=img.width(); ++code ) 00089 { 00090 u_int_8 c0 = scanline[0][code]; 00091 u_int_8 c1 = scanline[1][code]; 00092 u_int_8 c2 = scanline[2][code]; 00093 u_int_8 c3 = scanline[3][code]; 00094 00095 for( unsigned int i=0; (i!=8) && (x!=img.width()); ++x, ++i ) 00096 { 00097 unsigned int index = 00098 ( (c3 & 0x80) >> 4 ) 00099 | ( (c2 & 0x80) >> 5 ) 00100 | ( (c1 & 0x80) >> 6 ) 00101 | ( (c0 & 0x80) >> 7 ); 00102 00103 img[y][x] = m_header.color_map[index]; 00104 00105 c0 <<= 1; 00106 c1 <<= 1; 00107 c2 <<= 1; 00108 c3 <<= 1; 00109 } 00110 } 00111 } // pcx::reader::converter_16::operator()() 00112 00113 /*----------------------------------------------------------------------------*/ 00118 claw::graphic::pcx::reader::converter_256::converter_256 00119 ( const color_palette32& palette ) 00120 : m_palette(palette) 00121 { 00122 00123 } // pcx::reader::converter_256::converter_256() 00124 00125 /*----------------------------------------------------------------------------*/ 00132 void claw::graphic::pcx::reader::converter_256::operator() 00133 ( const std::vector<color_plane_type>& scanline, image& img, 00134 unsigned int y ) const 00135 { 00136 CLAW_PRECOND( scanline.size() == 1 ); 00137 00138 for ( unsigned int x=0; x!=img.width(); ++x ) 00139 img[y][x] = m_palette[ scanline[0][x] ]; 00140 } // pcx::reader::converter_256::operator()() 00141 00142 /*----------------------------------------------------------------------------*/ 00149 void claw::graphic::pcx::reader::converter_true_color::operator() 00150 ( const std::vector<color_plane_type>& scanline, image& img, 00151 unsigned int y ) const 00152 { 00153 CLAW_PRECOND( scanline.size() == 3 ); 00154 00155 for ( unsigned int x=0; x!=img.width(); ++x ) 00156 { 00157 img[y][x].components.red = scanline[0][x]; 00158 img[y][x].components.green = scanline[1][x]; 00159 img[y][x].components.blue = scanline[2][x]; 00160 img[y][x].components.alpha = 00161 std::numeric_limits<rgba_pixel_8::component_type>::max(); 00162 } 00163 } // pcx::reader::converter_true_color::operator()() 00164 00165 00166 00167 00168 /*----------------------------------------------------------------------------*/ 00174 claw::graphic::pcx::reader::rle_pcx_output_buffer::rle_pcx_output_buffer 00175 ( color_plane_type& result ) 00176 : m_result(result), m_position(0) 00177 { 00178 00179 } // pcx::reader::rle_pcx_output_buffer::rle_pcx_output_buffer() 00180 00181 /*----------------------------------------------------------------------------*/ 00187 void claw::graphic::pcx::reader::rle_pcx_output_buffer::fill 00188 ( unsigned int n, u_int_8 pattern ) 00189 { 00190 CLAW_PRECOND( m_position + n <= m_result.size() ); 00191 00192 for (unsigned int i=0; i!=n; ++i) 00193 m_result[m_position + i] = pattern; 00194 00195 m_position += n; 00196 } // pcx::reader::rle_pcx_output_buffer::fill() 00197 00198 /*----------------------------------------------------------------------------*/ 00204 void claw::graphic::pcx::reader::rle_pcx_output_buffer::copy 00205 ( unsigned int n, rle_pcx_input_buffer& buffer ) 00206 { 00207 CLAW_ASSERT( false, "This method should not have been called" ); 00208 } // pcx::reader::rle_pcx_output_buffer::copy() 00209 00210 /*----------------------------------------------------------------------------*/ 00214 bool claw::graphic::pcx::reader::rle_pcx_output_buffer::completed() const 00215 { 00216 return m_position == m_result.size(); 00217 } // pcx::reader::rle_pcx_output_buffer::completed() 00218 00219 00220 00221 00222 00223 /*----------------------------------------------------------------------------*/ 00229 void claw::graphic::pcx::reader::rle_pcx_decoder::read_mode 00230 ( input_buffer_type& input, output_buffer_type& output ) 00231 { 00232 this->m_mode = this->stop; 00233 bool ok = !output.completed(); 00234 00235 if ( ok && (input.remaining() < 1) ) 00236 ok = input.read_more(1); 00237 00238 if (ok) 00239 { 00240 unsigned char key = input.get_next(); 00241 this->m_mode = this->compressed; 00242 00243 if ( (key & 0xC0) == 0xC0 ) 00244 { 00245 this->m_count = key & 0x3F; 00246 00247 if ( input.remaining() < 1 ) 00248 input.read_more(1); 00249 00250 this->m_pattern = input.get_next(); 00251 } 00252 else 00253 { 00254 this->m_count = 1; 00255 this->m_pattern = key; 00256 } 00257 } 00258 } // pcx::reader::rle_pcx_decoder::read_mode() 00259 00260 00261 00262 00263 00264 00265 /*----------------------------------------------------------------------------*/ 00270 claw::graphic::pcx::reader::reader( image& img ) 00271 : m_image( img ) 00272 { 00273 00274 } // pcx::reader::reader() 00275 00276 /*----------------------------------------------------------------------------*/ 00283 claw::graphic::pcx::reader::reader( image& img, std::istream& f ) 00284 : m_image( img ) 00285 { 00286 load(f); 00287 } // pcx::reader::reader() 00288 00289 /*----------------------------------------------------------------------------*/ 00294 void claw::graphic::pcx::reader::load( std::istream& f ) 00295 { 00296 CLAW_PRECOND( !!f ); 00297 std::istream::pos_type init_pos = f.tellg(); 00298 00299 try 00300 { 00301 header h; 00302 00303 f.read( reinterpret_cast<char*>(&h), sizeof(header) ); 00304 00305 if ( f.rdstate() == std::ios_base::goodbit ) 00306 { 00307 check_if_pcx(h); 00308 00309 m_image.set_size( h.window.x_max - h.window.x_min + 1, 00310 h.window.y_max - h.window.y_min + 1 ); 00311 00312 bool supported_format = true; 00313 00314 switch(h.color_planes) 00315 { 00316 case 1: 00317 if (h.bpp == 1) 00318 load_mono(h, f); 00319 else if (h.bpp == 8) 00320 load_256_color_mapped(h, f); 00321 else 00322 supported_format = false; 00323 break; 00324 case 3: 00325 if (h.bpp == 8) 00326 load_true_color(h, f); 00327 else 00328 supported_format = false; 00329 break; 00330 case 4: 00331 if (h.bpp == 1) 00332 load_16_color_mapped(h, f); 00333 else 00334 supported_format = false; 00335 break; 00336 default : 00337 supported_format = false; 00338 } 00339 00340 if ( supported_format == false ) 00341 throw claw::bad_format 00342 ( "pcx::reader::pcx: unsupported image type" ); 00343 } 00344 else 00345 throw claw::bad_format 00346 ( "claw::pcx::reader::pcx: can't read header" ); 00347 } 00348 catch(...) 00349 { 00350 f.clear(); 00351 f.seekg( init_pos, std::ios_base::beg ); 00352 throw; 00353 } 00354 } // pcx::reader::load() 00355 00356 /*----------------------------------------------------------------------------*/ 00361 void claw::graphic::pcx::reader::check_if_pcx( const header& h ) const 00362 { 00363 if ( h.manufacturer != 0x0A ) 00364 throw CLAW_EXCEPTION( "Not a Pcx file." ); 00365 } // pcx::reader::check_if_pcx() 00366 00367 /*----------------------------------------------------------------------------*/ 00373 void claw::graphic::pcx::reader::load_mono( const header& h, std::istream& f ) 00374 { 00375 assert( h.color_planes == 1 ); 00376 00377 converter_mono convert; 00378 decompress( h, f, convert ); 00379 } // pcx::reader::load_mono() 00380 00381 /*----------------------------------------------------------------------------*/ 00387 void claw::graphic::pcx::reader::load_16_color_mapped 00388 ( const header& h, std::istream& f ) 00389 { 00390 assert( h.color_planes == 4 ); 00391 00392 converter_16 convert(h); 00393 decompress( h, f, convert ); 00394 } // pcx::reader::load_16_color_mapped() 00395 00396 /*----------------------------------------------------------------------------*/ 00402 void 00403 claw::graphic::pcx::reader::load_true_color( const header& h, std::istream& f ) 00404 { 00405 assert( h.color_planes == 3 ); 00406 00407 converter_true_color convert; 00408 decompress( h, f, convert ); 00409 } // pcx::reader::load_true_color() 00410 00411 /*----------------------------------------------------------------------------*/ 00417 void claw::graphic::pcx::reader::load_256_color_mapped 00418 ( const header& h, std::istream& f ) 00419 { 00420 assert( h.color_planes == 1 ); 00421 00422 // 256 RGB triplets 00423 const unsigned int palette_length = 256 * 3; 00424 00425 color_palette32 palette(256); 00426 std::istream::pos_type init_pos = f.tellg(); 00427 00428 // -1 for the check byte 00429 f.seekg( -(std::istream::off_type)palette_length - 1, std::ios_base::end ); 00430 00431 char check; 00432 f.read(&check, 1); 00433 00434 if ( check != 12 ) 00435 throw CLAW_EXCEPTION( "PCX: The color palette is missing." ); 00436 00437 char buffer[palette_length]; 00438 f.read(buffer, palette_length); 00439 00440 for (unsigned int i=0, j=0; i!=palette_length; i+=3, ++j) 00441 { 00442 palette[j].components.alpha = 255; 00443 palette[j].components.red = buffer[i]; 00444 palette[j].components.green = buffer[i+1]; 00445 palette[j].components.blue = buffer[i+2]; 00446 } 00447 00448 f.seekg( init_pos ); 00449 converter_256 convert(palette); 00450 decompress( h, f, convert ); 00451 } // pcx::reader::load_256_color_mapped() 00452 00453 /*----------------------------------------------------------------------------*/ 00459 void claw::graphic::pcx::reader::decompress_line 00460 ( std::istream& f, color_plane_type& scanline ) const 00461 { 00462 rle_pcx_input_buffer input(f); 00463 rle_pcx_output_buffer output(scanline); 00464 00465 rle_pcx_decoder decoder; 00466 00467 decoder.decode( input, output ); 00468 } // pcx::reader::decompress_line()