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/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 const pixel32 white(255, 255, 255, 255);
00049 const pixel32 black(0, 0, 0, 255);
00050
00051 unsigned int x=0;
00052
00053 for ( unsigned int code=0; x!=img.width(); ++code )
00054 {
00055 u_int_8 c = scanline[0][code];
00056
00057 for( unsigned int i=0; (i!=8) && (x!=img.width()); ++x, ++i, c<<=1 )
00058 if ( c & 0x80 )
00059 img[y][x] = white;
00060 else
00061 img[y][x] = black;
00062 }
00063 }
00064
00065
00070 claw::graphic::pcx::reader::converter_16::converter_16( const header& h )
00071 : m_header(h)
00072 {
00073
00074 }
00075
00076
00083 void claw::graphic::pcx::reader::converter_16::operator()
00084 ( const std::vector<color_plane_type>& scanline, image& img,
00085 unsigned int y ) const
00086 {
00087 CLAW_PRECOND( scanline.size() == 4 );
00088
00089 unsigned int x=0;
00090
00091 for ( unsigned int code=0; x!=img.width(); ++code )
00092 {
00093 u_int_8 c0 = scanline[0][code];
00094 u_int_8 c1 = scanline[1][code];
00095 u_int_8 c2 = scanline[2][code];
00096 u_int_8 c3 = scanline[3][code];
00097
00098 for( unsigned int i=0; (i!=8) && (x!=img.width()); ++x, ++i )
00099 {
00100 unsigned int index =
00101 ( (c3 & 0x80) >> 4 )
00102 | ( (c2 & 0x80) >> 5 )
00103 | ( (c1 & 0x80) >> 6 )
00104 | ( (c0 & 0x80) >> 7 );
00105
00106 img[y][x] = m_header.color_map[index];
00107
00108 c0 <<= 1;
00109 c1 <<= 1;
00110 c2 <<= 1;
00111 c3 <<= 1;
00112 }
00113 }
00114 }
00115
00116
00121 claw::graphic::pcx::reader::converter_256::converter_256
00122 ( const color_palette32& palette )
00123 : m_palette(palette)
00124 {
00125
00126 }
00127
00128
00135 void claw::graphic::pcx::reader::converter_256::operator()
00136 ( const std::vector<color_plane_type>& scanline, image& img,
00137 unsigned int y ) const
00138 {
00139 CLAW_PRECOND( scanline.size() == 1 );
00140
00141 for ( unsigned int x=0; x!=img.width(); ++x )
00142 img[y][x] = m_palette[ scanline[0][x] ];
00143 }
00144
00145
00152 void claw::graphic::pcx::reader::converter_true_color::operator()
00153 ( const std::vector<color_plane_type>& scanline, image& img,
00154 unsigned int y ) const
00155 {
00156 CLAW_PRECOND( scanline.size() == 3 );
00157
00158 for ( unsigned int x=0; x!=img.width(); ++x )
00159 {
00160 img[y][x].components.red = scanline[0][x];
00161 img[y][x].components.green = scanline[1][x];
00162 img[y][x].components.blue = scanline[2][x];
00163 img[y][x].components.alpha =
00164 std::numeric_limits<pixel32::component_type>::max();
00165 }
00166 }
00167
00168
00169
00170
00171
00177 claw::graphic::pcx::reader::rle_pcx_output_buffer::rle_pcx_output_buffer
00178 ( color_plane_type& result )
00179 : m_result(result), m_position(0)
00180 {
00181
00182 }
00183
00184
00190 void claw::graphic::pcx::reader::rle_pcx_output_buffer::fill
00191 ( unsigned int n, u_int_8 pattern )
00192 {
00193 CLAW_PRECOND( m_position + n <= m_result.size() );
00194
00195 for (unsigned int i=0; i!=n; ++i)
00196 m_result[m_position + i] = pattern;
00197
00198 m_position += n;
00199 }
00200
00201
00207 void claw::graphic::pcx::reader::rle_pcx_output_buffer::copy
00208 ( unsigned int n, rle_pcx_input_buffer& buffer )
00209 {
00210 CLAW_ASSERT( false, "This method should not have been called" );
00211 }
00212
00213
00217 bool claw::graphic::pcx::reader::rle_pcx_output_buffer::completed() const
00218 {
00219 return m_position == m_result.size();
00220 }
00221
00222
00223
00224
00225
00226
00232 void claw::graphic::pcx::reader::rle_pcx_decoder::read_mode
00233 ( rle_pcx_input_buffer& input, rle_pcx_output_buffer& output )
00234 {
00235 this->m_mode = this->stop;
00236 bool ok = !output.completed();
00237
00238 if ( ok && (input.remaining() < 1) )
00239 ok = input.read_more(1);
00240
00241 if (ok)
00242 {
00243 unsigned char key = input.get_next();
00244 this->m_mode = this->compressed;
00245
00246 if ( (key & 0xC0) == 0xC0 )
00247 {
00248 this->m_count = key & 0x3F;
00249
00250 if ( input.remaining() < 1 )
00251 input.read_more(1);
00252
00253 this->m_pattern = input.get_next();
00254 }
00255 else
00256 {
00257 this->m_count = 1;
00258 this->m_pattern = key;
00259 }
00260 }
00261 }
00262
00263
00264
00265
00266
00267
00268
00273 claw::graphic::pcx::reader::reader( image& img )
00274 : m_image( img )
00275 {
00276
00277 }
00278
00279
00286 claw::graphic::pcx::reader::reader( image& img, std::istream& f )
00287 : m_image( img )
00288 {
00289 load(f);
00290 }
00291
00292
00297 void claw::graphic::pcx::reader::load( std::istream& f )
00298 {
00299 CLAW_PRECOND( !!f );
00300 std::istream::pos_type init_pos = f.tellg();
00301
00302 try
00303 {
00304 header h;
00305
00306 f.read( reinterpret_cast<char*>(&h), sizeof(header) );
00307
00308 if ( f.rdstate() == std::ios_base::goodbit )
00309 {
00310 check_if_pcx(h);
00311
00312 m_image.set_size( h.window.x_max - h.window.x_min + 1,
00313 h.window.y_max - h.window.y_min + 1 );
00314
00315 bool supported_format = true;
00316
00317 switch(h.color_planes)
00318 {
00319 case 1:
00320 if (h.bpp == 1)
00321 load_mono(h, f);
00322 else if (h.bpp == 8)
00323 load_256_color_mapped(h, f);
00324 else
00325 supported_format = false;
00326 break;
00327 case 3:
00328 if (h.bpp == 8)
00329 load_true_color(h, f);
00330 else
00331 supported_format = false;
00332 break;
00333 case 4:
00334 if (h.bpp == 1)
00335 load_16_color_mapped(h, f);
00336 else
00337 supported_format = false;
00338 break;
00339 default :
00340 supported_format = false;
00341 }
00342
00343 if ( supported_format == false )
00344 throw claw::bad_format
00345 ( "pcx::reader::pcx: unsupported image type" );
00346 }
00347 else
00348 throw claw::bad_format
00349 ( "claw::pcx::reader::pcx: can't read header" );
00350 }
00351 catch(...)
00352 {
00353 f.clear();
00354 f.seekg( init_pos, std::ios_base::beg );
00355 throw;
00356 }
00357 }
00358
00359
00364 void claw::graphic::pcx::reader::check_if_pcx( const header& h ) const
00365 {
00366 if ( h.manufacturer != 0x0A )
00367 throw CLAW_EXCEPTION( "Not a Pcx file." );
00368 }
00369
00370
00376 void claw::graphic::pcx::reader::load_mono( const header& h, std::istream& f )
00377 {
00378 assert( h.color_planes == 1 );
00379
00380 converter_mono convert;
00381 decompress( h, f, convert );
00382 }
00383
00384
00390 void claw::graphic::pcx::reader::load_16_color_mapped
00391 ( const header& h, std::istream& f )
00392 {
00393 assert( h.color_planes == 4 );
00394
00395 converter_16 convert(h);
00396 decompress( h, f, convert );
00397 }
00398
00399
00405 void
00406 claw::graphic::pcx::reader::load_true_color( const header& h, std::istream& f )
00407 {
00408 assert( h.color_planes == 3 );
00409
00410 converter_true_color convert;
00411 decompress( h, f, convert );
00412 }
00413
00414
00420 void claw::graphic::pcx::reader::load_256_color_mapped
00421 ( const header& h, std::istream& f )
00422 {
00423 assert( h.color_planes == 1 );
00424
00425
00426 const unsigned int palette_length = 256 * 3;
00427
00428 color_palette32 palette(256);
00429 std::istream::pos_type init_pos = f.tellg();
00430
00431
00432 f.seekg( -(std::istream::off_type)palette_length - 1, std::ios_base::end );
00433
00434 char check;
00435 f.read(&check, 1);
00436
00437 if ( check != 12 )
00438 throw CLAW_EXCEPTION( "PCX: The color palette is missing." );
00439
00440 char buffer[palette_length];
00441 f.read(buffer, palette_length);
00442
00443 for (unsigned int i=0, j=0; i!=palette_length; i+=3, ++j)
00444 {
00445 palette[j].components.alpha = 255;
00446 palette[j].components.red = buffer[i];
00447 palette[j].components.green = buffer[i+1];
00448 palette[j].components.blue = buffer[i+2];
00449 }
00450
00451 f.seekg( init_pos );
00452 converter_256 convert(palette);
00453 decompress( h, f, convert );
00454 }
00455
00456
00462 void claw::graphic::pcx::reader::decompress_line
00463 ( std::istream& f, color_plane_type& scanline ) const
00464 {
00465 rle_pcx_input_buffer input(f);
00466 rle_pcx_output_buffer output(scanline);
00467
00468 rle_pcx_decoder decoder;
00469
00470 decoder.decode( input, output );
00471 }