Claw 1.7.3
bitmap_reader.cpp
Go to the documentation of this file.
1/*
2 CLAW - a C++ Library Absolutely Wonderful
3
4 CLAW is a free library without any particular aim but being useful to
5 anyone.
6
7 Copyright (C) 2005-2011 Julien Jorge
8
9 This library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Lesser General Public
11 License as published by the Free Software Foundation; either
12 version 2.1 of the License, or (at your option) any later version.
13
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public
20 License along with this library; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22
23 contact: julien.jorge@gamned.org
24*/
30#include <claw/bitmap.hpp>
31#include <algorithm>
32
33namespace claw
34{
35 namespace graphic
36 {
37 /*------------------------------------------------------------------------*/
44 template<>
45 void bitmap::reader::rle_bitmap_output_buffer<false>::fill
46 ( unsigned int n, unsigned char pattern )
47 {
48 assert( m_x + n <= m_image.width() );
49
50 std::fill(&m_image[m_y][m_x], &m_image[m_y][m_x] + n, m_palette[pattern]);
51
52 m_x += n;
53 } // bitmap::reader::rle_bitmap_output_buffer<false>::fill()
54 } // namespace graphic
55} // namespace claw
56
57namespace claw
58{
59 namespace graphic
60 {
61 /*------------------------------------------------------------------------*/
68 template<>
69 void bitmap::reader::rle_bitmap_output_buffer<true>::fill
70 ( unsigned int n, unsigned char pattern )
71 {
72 assert( m_x + n <= m_image.width() );
73
74 for (unsigned int i = 0; i != n / 2; ++i, m_x += 2)
75 {
76 m_image[m_y][m_x] = m_palette[ (pattern & 0xF0) >> 4 ];
77 m_image[m_y][m_x+1] = m_palette[ pattern & 0x0F ];
78 }
79
80 if ( n % 2 )
81 {
82 m_image[m_y][m_x] = m_palette[ (pattern & 0xF0) >> 4 ];
83 ++m_x;
84 }
85 } // bitmap::reader::rle_bitmap_output_buffer<false>::fill()
86 } // namespace graphic
87} // namespace claw
88
89namespace claw
90{
91 namespace graphic
92 {
93 /*------------------------------------------------------------------------*/
100 template<>
101 void bitmap::reader::rle_bitmap_output_buffer<false>::copy
102 ( unsigned int n, file_input_buffer& buffer )
103 {
104 assert( m_x + n <= m_image.width() );
105
106 // RLE bitmap data is 2-bytes aligned
107 const unsigned int bytes_needed = n + n % 2;
108
109 if ( buffer.remaining() < bytes_needed )
110 buffer.read_more(bytes_needed);
111
112 assert( buffer.remaining() >= bytes_needed );
113
114 const unsigned char* p =
115 reinterpret_cast<const unsigned char*>(buffer.get_buffer());
116
117 std::transform( p, p + n, &m_image[m_y][m_x], m_palette );
118
119 m_x += n;
120
121 buffer.move(bytes_needed);
122 } // bitmap::reader::rle_bitmap_output_buffer<false>::copy()
123 } // namespace graphic
124} // namespace claw
125
126namespace claw
127{
128 namespace graphic
129 {
130 /*------------------------------------------------------------------------*/
137 template<>
138 void bitmap::reader::rle_bitmap_output_buffer<true>::copy
139 ( unsigned int n, file_input_buffer& buffer )
140 {
141 assert( m_x + n <= m_image.width() );
142
143 // RLE bitmap data is 2-bytes aligned
144 unsigned int bytes_needed = n / 2 + n % 2;
145
146 if ( bytes_needed % 2 )
147 ++bytes_needed;
148
149 if ( buffer.remaining() < bytes_needed )
150 buffer.read_more( bytes_needed );
151
152 assert( buffer.remaining() >= bytes_needed );
153
154 const unsigned char* p =
155 reinterpret_cast<const unsigned char*>(buffer.get_buffer());
156 const unsigned char* last = p + n / 2;
157
158 for ( ; p != last; ++p, m_x += 2)
159 {
160 m_image[m_y][m_x] = m_palette[ (*p & 0xF0) >> 4 ];
161 m_image[m_y][m_x+1] = m_palette[ *p & 0x0F ];
162 }
163
164 if ( n % 2 )
165 {
166 m_image[m_y][m_x] = m_palette[ (*p & 0xF0) >> 4 ];
167 ++m_x;
168 }
169
170 buffer.move( bytes_needed );
171 } // bitmap::reader::rle_bitmap_output_buffer<true>::copy()
172 } // namespace graphic
173} // namespace claw
174
175
176
177/*----------------------------------------------------------------------------*/
185void claw::graphic::bitmap::reader::pixel1_to_pixel32::operator()
186 ( scanline& dest, const char* src, const color_palette_type& palette ) const
187{
188 assert(palette.size() == 2);
189
190 scanline::iterator it( dest.begin() );
191 const unsigned int n = dest.size();
192 const unsigned int byte_size = 8; // 8 bits per byte
193 const unsigned int upper_bound = n / byte_size;
194
195 for (unsigned int i=0; i!=upper_bound; ++i)
196 for (unsigned int j=0; j!=byte_size; ++j, ++it)
197 if ( src[i] & (0x80 >> j) )
198 *it = palette[1];
199 else
200 *it = palette[0];
201
202 for (unsigned int j = 0; j != (n % byte_size); ++j, ++it)
203 if ( src[upper_bound] & (0x80 >> j) )
204 *it = palette[1];
205 else
206 *it = palette[0];
207} // bitmap::reader::pixel1_to_pixel32()
208
209/*----------------------------------------------------------------------------*/
217void claw::graphic::bitmap::reader::pixel4_to_pixel32::operator()
218 ( scanline& dest, const char* src, const color_palette_type& palette ) const
219{
220 assert(palette.size() == 16);
221
222 scanline::iterator it( dest.begin() );
223 const unsigned int upper_bound = dest.size() / 2;
224
225 for (unsigned int i=0; i!=upper_bound; ++i, ++src)
226 {
227 *it = palette[ (*src & 0xF0) >> 4 ];
228 ++it;
229 *it = palette[ *src & 0x0F ];
230 ++it;
231 }
232
233 if (dest.size() % 2)
234 *it = palette[ (*src & 0xF0) >> 4 ];
235} // bitmap::reader::pixel4_to_pixel32()
236
237/*----------------------------------------------------------------------------*/
245void claw::graphic::bitmap::reader::pixel8_to_pixel32::operator()
246 ( scanline& dest, const char* src, const color_palette_type& palette ) const
247{
248 assert(palette.size() == 256);
249
250 const unsigned char* s = reinterpret_cast<const unsigned char*>(src);
251
252 std::transform(s, s + dest.size(), dest.begin(), palette);
253} // bitmap::reader::pixel8_to_pixel32()
254
255/*----------------------------------------------------------------------------*/
262void claw::graphic::bitmap::reader::pixel24_to_pixel32::operator()
263 ( scanline& dest, const char* src, const color_palette_type& palette ) const
264{
265 scanline::iterator it( dest.begin() );
266 const unsigned int upper_bound = 3 * dest.size();
267
268 for (unsigned int i=0; i!=upper_bound; i+=3)
269 {
270 it->components.alpha = 255;
271 it->components.blue = src[i];
272 it->components.green = src[i+1];
273 it->components.red = src[i+2];
274
275 ++it;
276 }
277} // bitmap::reader::pixel24_to_pixel32()
278
279
280
281
282/*----------------------------------------------------------------------------*/
288 : m_image( img )
289{
290
291} // bitmap::reader::reader()
292
293/*----------------------------------------------------------------------------*/
301 : m_image( img )
302{
303 load(f);
304} // bitmap::reader::reader()
305
306/*----------------------------------------------------------------------------*/
313{
314 CLAW_PRECOND( !!f );
315 std::istream::pos_type init_pos = f.tellg();
316
317 try
318 {
319 header h;
320
321 f.read( reinterpret_cast<char*>(&h), sizeof(header) );
322
323 if ( (h.id[0] == 'B') && (h.id[1] == 'M')
324 && (f.rdstate() == std::ios_base::goodbit) )
325 {
326 m_image.set_size(h.width, h.height);
327
328 switch(h.bpp)
329 {
330 case 1 : load_1bpp(h, f); break;
331 case 4 : load_4bpp(h, f); break;
332 case 8 : load_8bpp(h, f); break;
333 //case 16 : load_16bpp(h, f); break;
334 case 24 : load_24bpp(h, f); break;
335 default :
336 throw claw::bad_format
337 ("bitmap::bitmap: unsupported color depth.");
338 }
339 }
340 else
341 throw claw::bad_format( "bitmap::bitmap: invalid header." );
342 }
343 catch(...)
344 {
345 f.clear();
346 f.seekg( init_pos, std::ios_base::beg );
347 throw;
348 }
349} // bitmap::reader::load()
350
351/*----------------------------------------------------------------------------*/
359void claw::graphic::bitmap::reader::load_palette
360( const header& h, std::istream& f, color_palette_type& palette ) const
361{
362 assert(h.bpp <= 8);
363
364 switch(h.bpp)
365 {
366 case 1 : assert( palette.size() == 2 ); break;
367 case 4 : assert( palette.size() == 16 ); break;
368 case 8 : assert( palette.size() == 256 ); break;
369 }
370
371 const unsigned int sizeof_color = sizeof(color_palette_type::color_type);
372 const unsigned int buffer_size = sizeof_color * palette.size();
373 char* buffer = new char[buffer_size];
374
375 f.read(buffer, buffer_size);
376
377 for (unsigned int i=0, j=0; i!=buffer_size; i+=sizeof_color, ++j)
378 {
379 palette[j].components.alpha = 255;
380 palette[j].components.blue = buffer[i];
381 palette[j].components.green = buffer[i+1];
382 palette[j].components.red = buffer[i+2];
383 }
384
385 delete[] buffer;
386} // bitmap::reader::load_palette()
387
388/*----------------------------------------------------------------------------*/
395void
396claw::graphic::bitmap::reader::load_1bpp( const header& h, std::istream& f )
397{
398 assert(h.bpp == 1);
399 //assert(h.compression == BMP_COMPRESSION_BITFIELDS);
400
401 color_palette_type palette(2);
402 unsigned int buffer_size = m_image.width() / (sizeof(char) * 8);
403
404 if ( m_image.width() % (sizeof(char) * 8) )
405 ++buffer_size;
406
407 load_palette(h, f, palette);
408 f.seekg(h.data_offset);
409
410 load_rgb_data(f, buffer_size, palette, pixel1_to_pixel32());
411} // bitmap::reader::load_1bpp()
412
413/*----------------------------------------------------------------------------*/
420void
421claw::graphic::bitmap::reader::load_4bpp( const header& h, std::istream& f )
422{
423 assert(h.bpp == 4);
424 assert( (h.compression == BMP_COMPRESSION_RGB)
425 || (h.compression == BMP_COMPRESSION_RLE4) );
426
427 color_palette_type palette(16);
428 load_palette(h, f, palette);
429
430 if (h.compression == BMP_COMPRESSION_RLE4)
431 load_4bpp_rle(h, f, palette);
432 else
433 load_4bpp_rgb(h, f, palette);
434} // bitmap::reader::load_4bpp()
435
436/*----------------------------------------------------------------------------*/
443void
444claw::graphic::bitmap::reader::load_8bpp( const header& h, std::istream& f )
445{
446 assert(h.bpp == 8);
447 assert( (h.compression == BMP_COMPRESSION_RGB)
448 || (h.compression == BMP_COMPRESSION_RLE8) );
449
450 color_palette_type palette(256);
451 load_palette(h, f, palette);
452
453 if (h.compression == BMP_COMPRESSION_RLE8)
454 load_8bpp_rle(h, f, palette);
455 else
456 load_8bpp_rgb(h, f, palette);
457} // bitmap::reader::load_8bpp()
458
459/*----------------------------------------------------------------------------*/
466void
467claw::graphic::bitmap::reader::load_24bpp( const header& h, std::istream& f )
468{
469 assert(h.bpp == 24);
470
471 unsigned int buffer_size = m_image.width() * 3;
472 color_palette_type palette(0);
473
474 f.seekg(h.data_offset);
475
476 load_rgb_data(f, buffer_size, palette, pixel24_to_pixel32());
477} // bitmap::reader::load_24bpp()
478
479/*----------------------------------------------------------------------------*/
488void claw::graphic::bitmap::reader::load_4bpp_rle
489( const header& h, std::istream& f, const color_palette_type& palette )
490{
491 assert(h.bpp == 4);
492 assert(h.compression == BMP_COMPRESSION_RLE4);
493 assert(palette.size() == 16);
494
495 f.seekg(h.data_offset);
496
497 rle4_decoder decoder;
498 rle4_decoder::output_buffer_type output_buffer( palette, m_image );
499 file_input_buffer input_buffer(f);
500
501 decoder.decode( input_buffer, output_buffer );
502} // bitmap::reader::load_4bpp_rle()
503
504/*----------------------------------------------------------------------------*/
513void claw::graphic::bitmap::reader::load_4bpp_rgb
514( const header& h, std::istream& f, const color_palette_type& palette )
515{
516 assert(h.bpp == 4);
517 assert(h.compression == BMP_COMPRESSION_RGB);
518 assert(palette.size() == 16);
519
520 unsigned int buffer_size = m_image.width() / 2 + m_image.width() % 2;
521
522 f.seekg(h.data_offset);
523
524 load_rgb_data(f, buffer_size, palette, pixel4_to_pixel32());
525} // bitmap::reader::load_4bpp_rgb()
526
527/*----------------------------------------------------------------------------*/
536void claw::graphic::bitmap::reader::load_8bpp_rle
537( const header& h, std::istream& f, const color_palette_type& palette )
538{
539 assert(h.bpp == 8);
540 assert(h.compression == BMP_COMPRESSION_RLE8);
541 assert(palette.size() == 256);
542
543 f.seekg(h.data_offset);
544
545 rle8_decoder decoder;
546 rle8_decoder::output_buffer_type output_buffer( palette, m_image );
547 file_input_buffer input_buffer(f);
548
549 decoder.decode( input_buffer, output_buffer );
550} // bitmap::reader::load_8bpp_rle()
551
552/*----------------------------------------------------------------------------*/
561void claw::graphic::bitmap::reader::load_8bpp_rgb
562( const header& h, std::istream& f, const color_palette_type& palette )
563{
564 assert(h.bpp == 8);
565 assert(h.compression == BMP_COMPRESSION_RGB);
566 assert(palette.size() == 256);
567
568 unsigned int buffer_size = m_image.width();
569
570 f.seekg(h.data_offset);
571
572 load_rgb_data(f, buffer_size, palette, pixel8_to_pixel32());
573} // bitmap::reader::load_8bpp_rgb()
#define CLAW_PRECOND(b)
Abort the program if a precondition is not true.
Definition assert.hpp:98
A class for bitmap pictures.
Exception thrown when accessing bad formated data.
Definition exception.hpp:72
reader(image &img)
Constructor.
void load(std::istream &f)
Load the image data from a stream.
A class to deal with images.
Definition image.hpp:50
This is the main namespace.
Definition algorithm.hpp:34
unsigned short bpp
Bits per pixel.
Definition bitmap.hpp:103
unsigned int height
Image's height.
Definition bitmap.hpp:97
char id[2]
File identifier (must be 'BM').
Definition bitmap.hpp:79