claw  1.9.0
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@stuff-o-matic.com
24 */
30 #include <claw/graphic/bitmap.hpp>
31 
32 #include <algorithm>
33 
34 namespace claw
35 {
36  namespace graphic
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,
51  m_palette[pattern]);
52 
53  m_x += n;
54  }
55  }
56 }
57 
58 namespace claw
59 {
60  namespace graphic
61  {
68  template <>
69  void
70  bitmap::reader::rle_bitmap_output_buffer<true>::fill(unsigned int n,
71  unsigned char pattern)
72  {
73  assert(m_x + n <= m_image.width());
74 
75  for(unsigned int i = 0; i != n / 2; ++i, m_x += 2)
76  {
77  m_image[m_y][m_x] = m_palette[(pattern & 0xF0) >> 4];
78  m_image[m_y][m_x + 1] = m_palette[pattern & 0x0F];
79  }
80 
81  if(n % 2)
82  {
83  m_image[m_y][m_x] = m_palette[(pattern & 0xF0) >> 4];
84  ++m_x;
85  }
86  }
87  }
88 }
89 
90 namespace claw
91 {
92  namespace graphic
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  }
123  }
124 }
125 
126 namespace claw
127 {
128  namespace graphic
129  {
136  template <>
137  void bitmap::reader::rle_bitmap_output_buffer<true>::copy(
138  unsigned int n, file_input_buffer& buffer)
139  {
140  assert(m_x + n <= m_image.width());
141 
142  // RLE bitmap data is 2-bytes aligned
143  unsigned int bytes_needed = n / 2 + n % 2;
144 
145  if(bytes_needed % 2)
146  ++bytes_needed;
147 
148  if(buffer.remaining() < bytes_needed)
149  buffer.read_more(bytes_needed);
150 
151  assert(buffer.remaining() >= bytes_needed);
152 
153  const unsigned char* p
154  = reinterpret_cast<const unsigned char*>(buffer.get_buffer());
155  const unsigned char* last = p + n / 2;
156 
157  for(; p != last; ++p, m_x += 2)
158  {
159  m_image[m_y][m_x] = m_palette[(*p & 0xF0) >> 4];
160  m_image[m_y][m_x + 1] = m_palette[*p & 0x0F];
161  }
162 
163  if(n % 2)
164  {
165  m_image[m_y][m_x] = m_palette[(*p & 0xF0) >> 4];
166  ++m_x;
167  }
168 
169  buffer.move(bytes_needed);
170  }
171  }
172 }
173 
181 void claw::graphic::bitmap::reader::pixel1_to_pixel32::operator()(
182  scanline& dest, const char* src, const color_palette_type& palette) const
183 {
184  assert(palette.size() == 2);
185 
186  scanline::iterator it(dest.begin());
187  const unsigned int n = dest.size();
188  const unsigned int byte_size = 8; // 8 bits per byte
189  const unsigned int upper_bound = n / byte_size;
190 
191  for(unsigned int i = 0; i != upper_bound; ++i)
192  for(unsigned int j = 0; j != byte_size; ++j, ++it)
193  if(src[i] & (0x80 >> j))
194  *it = palette[1];
195  else
196  *it = palette[0];
197 
198  for(unsigned int j = 0; j != (n % byte_size); ++j, ++it)
199  if(src[upper_bound] & (0x80 >> j))
200  *it = palette[1];
201  else
202  *it = palette[0];
203 }
204 
212 void claw::graphic::bitmap::reader::pixel4_to_pixel32::operator()(
213  scanline& dest, const char* src, const color_palette_type& palette) const
214 {
215  assert(palette.size() == 16);
216 
217  scanline::iterator it(dest.begin());
218  const unsigned int upper_bound = dest.size() / 2;
219 
220  for(unsigned int i = 0; i != upper_bound; ++i, ++src)
221  {
222  *it = palette[(*src & 0xF0) >> 4];
223  ++it;
224  *it = palette[*src & 0x0F];
225  ++it;
226  }
227 
228  if(dest.size() % 2)
229  *it = palette[(*src & 0xF0) >> 4];
230 }
231 
239 void claw::graphic::bitmap::reader::pixel8_to_pixel32::operator()(
240  scanline& dest, const char* src, const color_palette_type& palette) const
241 {
242  assert(palette.size() == 256);
243 
244  const unsigned char* s = reinterpret_cast<const unsigned char*>(src);
245 
246  std::transform(s, s + dest.size(), dest.begin(), palette);
247 }
248 
255 void claw::graphic::bitmap::reader::pixel24_to_pixel32::operator()(
256  scanline& dest, const char* src, const color_palette_type& palette) const
257 {
258  scanline::iterator it(dest.begin());
259  const unsigned int upper_bound = 3 * dest.size();
260 
261  for(unsigned int i = 0; i != upper_bound; i += 3)
262  {
263  it->components.alpha = 255;
264  it->components.blue = src[i];
265  it->components.green = src[i + 1];
266  it->components.red = src[i + 2];
267 
268  ++it;
269  }
270 }
271 
277  : m_image(img)
278 {}
279 
287  : m_image(img)
288 {
289  load(f);
290 }
291 
298 {
299  CLAW_PRECOND(!!f);
300  std::istream::pos_type init_pos = f.tellg();
301 
302  try
303  {
304  header h;
305 
306  f.read(reinterpret_cast<char*>(&h), sizeof(header));
307 
308  if((h.id[0] == 'B') && (h.id[1] == 'M')
309  && (f.rdstate() == std::ios_base::goodbit))
310  {
311  m_image.set_size(h.width, h.height);
312 
313  switch(h.bpp)
314  {
315  case 1:
316  load_1bpp(h, f);
317  break;
318  case 4:
319  load_4bpp(h, f);
320  break;
321  case 8:
322  load_8bpp(h, f);
323  break;
324  // case 16 : load_16bpp(h, f); break;
325  case 24:
326  load_24bpp(h, f);
327  break;
328  default:
329  throw claw::bad_format(
330  "bitmap::bitmap: unsupported color depth.");
331  }
332  }
333  else
334  throw claw::bad_format("bitmap::bitmap: invalid header.");
335  }
336  catch(...)
337  {
338  f.clear();
339  f.seekg(init_pos, std::ios_base::beg);
340  throw;
341  }
342 }
343 
351 void claw::graphic::bitmap::reader::load_palette(
352  const header& h, std::istream& f, color_palette_type& palette) const
353 {
354  assert(h.bpp <= 8);
355 
356  switch(h.bpp)
357  {
358  case 1:
359  assert(palette.size() == 2);
360  break;
361  case 4:
362  assert(palette.size() == 16);
363  break;
364  case 8:
365  assert(palette.size() == 256);
366  break;
367  }
368 
369  const unsigned int sizeof_color = sizeof(color_palette_type::color_type);
370  const unsigned int buffer_size = sizeof_color * palette.size();
371  char* buffer = new char[buffer_size];
372 
373  f.read(buffer, buffer_size);
374 
375  for(unsigned int i = 0, j = 0; i != buffer_size; i += sizeof_color, ++j)
376  {
377  palette[j].components.alpha = 255;
378  palette[j].components.blue = buffer[i];
379  palette[j].components.green = buffer[i + 1];
380  palette[j].components.red = buffer[i + 2];
381  }
382 
383  delete[] buffer;
384 }
385 
392 void claw::graphic::bitmap::reader::load_1bpp(const header& h, std::istream& f)
393 {
394  assert(h.bpp == 1);
395  // assert(h.compression == BMP_COMPRESSION_BITFIELDS);
396 
397  color_palette_type palette(2);
398  unsigned int buffer_size = m_image.width() / (sizeof(char) * 8);
399 
400  if(m_image.width() % (sizeof(char) * 8))
401  ++buffer_size;
402 
403  load_palette(h, f, palette);
404  f.seekg(h.data_offset);
405 
406  load_rgb_data(f, buffer_size, palette, pixel1_to_pixel32());
407 }
408 
415 void claw::graphic::bitmap::reader::load_4bpp(const header& h, std::istream& f)
416 {
417  assert(h.bpp == 4);
418  assert((h.compression == BMP_COMPRESSION_RGB)
419  || (h.compression == BMP_COMPRESSION_RLE4));
420 
421  color_palette_type palette(16);
422  load_palette(h, f, palette);
423 
424  if(h.compression == BMP_COMPRESSION_RLE4)
425  load_4bpp_rle(h, f, palette);
426  else
427  load_4bpp_rgb(h, f, palette);
428 }
429 
436 void claw::graphic::bitmap::reader::load_8bpp(const header& h, std::istream& f)
437 {
438  assert(h.bpp == 8);
439  assert((h.compression == BMP_COMPRESSION_RGB)
440  || (h.compression == BMP_COMPRESSION_RLE8));
441 
442  color_palette_type palette(256);
443  load_palette(h, f, palette);
444 
445  if(h.compression == BMP_COMPRESSION_RLE8)
446  load_8bpp_rle(h, f, palette);
447  else
448  load_8bpp_rgb(h, f, palette);
449 }
450 
457 void claw::graphic::bitmap::reader::load_24bpp(const header& h,
458  std::istream& f)
459 {
460  assert(h.bpp == 24);
461 
462  unsigned int buffer_size = m_image.width() * 3;
463  color_palette_type palette(0);
464 
465  f.seekg(h.data_offset);
466 
467  load_rgb_data(f, buffer_size, palette, pixel24_to_pixel32());
468 }
469 
478 void claw::graphic::bitmap::reader::load_4bpp_rle(
479  const header& h, std::istream& f, const color_palette_type& palette)
480 {
481  assert(h.bpp == 4);
482  assert(h.compression == BMP_COMPRESSION_RLE4);
483  assert(palette.size() == 16);
484 
485  f.seekg(h.data_offset);
486 
487  rle4_decoder decoder;
488  rle4_decoder::output_buffer_type output_buffer(palette, m_image);
489  file_input_buffer input_buffer(f);
490 
491  decoder.decode(input_buffer, output_buffer);
492 }
493 
502 void claw::graphic::bitmap::reader::load_4bpp_rgb(
503  const header& h, std::istream& f, const color_palette_type& palette)
504 {
505  assert(h.bpp == 4);
506  assert(h.compression == BMP_COMPRESSION_RGB);
507  assert(palette.size() == 16);
508 
509  unsigned int buffer_size = m_image.width() / 2 + m_image.width() % 2;
510 
511  f.seekg(h.data_offset);
512 
513  load_rgb_data(f, buffer_size, palette, pixel4_to_pixel32());
514 }
515 
524 void claw::graphic::bitmap::reader::load_8bpp_rle(
525  const header& h, std::istream& f, const color_palette_type& palette)
526 {
527  assert(h.bpp == 8);
528  assert(h.compression == BMP_COMPRESSION_RLE8);
529  assert(palette.size() == 256);
530 
531  f.seekg(h.data_offset);
532 
533  rle8_decoder decoder;
534  rle8_decoder::output_buffer_type output_buffer(palette, m_image);
535  file_input_buffer input_buffer(f);
536 
537  decoder.decode(input_buffer, output_buffer);
538 }
539 
548 void claw::graphic::bitmap::reader::load_8bpp_rgb(
549  const header& h, std::istream& f, const color_palette_type& palette)
550 {
551  assert(h.bpp == 8);
552  assert(h.compression == BMP_COMPRESSION_RGB);
553  assert(palette.size() == 256);
554 
555  unsigned int buffer_size = m_image.width();
556 
557  f.seekg(h.data_offset);
558 
559  load_rgb_data(f, buffer_size, palette, pixel8_to_pixel32());
560 }
char id[2]
File identifier (must be &#39;BM&#39;).
Definition: bitmap.hpp:81
unsigned int width
Image&#39;s width.
Definition: bitmap.hpp:96
unsigned short bpp
Bits per pixel.
Definition: bitmap.hpp:105
reader(image &img)
Constructor.
A class for bitmap pictures.
void load(std::istream &f)
Load the image data from a stream.
unsigned int height
Image&#39;s height.
Definition: bitmap.hpp:99
A class to deal with images.
Definition: image.hpp:50
This is the main namespace.
Definition: application.hpp:49
#define CLAW_PRECOND(b)
Abort the program if a precondition is not true.
Definition: assert.hpp:94
Exception thrown when accessing bad formated data.
Definition: exception.hpp:73