claw  1.9.0
pcx_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/pcx.hpp>
31 
32 #include <claw/exception.hpp>
33 
34 #include <limits>
35 
42 void claw::graphic::pcx::reader::converter_mono::operator()(
43  const std::vector<color_plane_type>& scanline, image& img,
44  unsigned int y) const
45 {
46  CLAW_PRECOND(scanline.size() == 1);
47 
48  unsigned int x = 0;
49 
50  for(unsigned int code = 0; x != img.width(); ++code)
51  {
52  u_int_8 c = scanline[0][code]; // only one color plane for monochrome pcx
53 
54  for(unsigned int i = 0; (i != 8) && (x != img.width());
55  ++x, ++i, c <<= 1)
56  if(c & 0x80)
57  img[y][x] = white_pixel;
58  else
59  img[y][x] = black_pixel;
60  }
61 }
62 
67 claw::graphic::pcx::reader::converter_16::converter_16(const header& h)
68  : m_header(h)
69 {}
70 
77 void claw::graphic::pcx::reader::converter_16::operator()(
78  const std::vector<color_plane_type>& scanline, image& img,
79  unsigned int y) const
80 {
81  CLAW_PRECOND(scanline.size() == 4);
82 
83  unsigned int x = 0;
84 
85  for(unsigned int code = 0; x != img.width(); ++code)
86  {
87  u_int_8 c0 = scanline[0][code];
88  u_int_8 c1 = scanline[1][code];
89  u_int_8 c2 = scanline[2][code];
90  u_int_8 c3 = scanline[3][code];
91 
92  for(unsigned int i = 0; (i != 8) && (x != img.width()); ++x, ++i)
93  {
94  unsigned int index = ((c3 & 0x80) >> 4) | ((c2 & 0x80) >> 5)
95  | ((c1 & 0x80) >> 6) | ((c0 & 0x80) >> 7);
96 
97  img[y][x] = m_header.color_map[index];
98 
99  c0 <<= 1;
100  c1 <<= 1;
101  c2 <<= 1;
102  c3 <<= 1;
103  }
104  }
105 }
106 
111 claw::graphic::pcx::reader::converter_256::converter_256(
112  const color_palette32& palette)
113  : m_palette(palette)
114 {}
115 
122 void claw::graphic::pcx::reader::converter_256::operator()(
123  const std::vector<color_plane_type>& scanline, image& img,
124  unsigned int y) const
125 {
126  CLAW_PRECOND(scanline.size() == 1);
127 
128  for(unsigned int x = 0; x != img.width(); ++x)
129  img[y][x] = m_palette[scanline[0][x]];
130 }
131 
138 void claw::graphic::pcx::reader::converter_true_color::operator()(
139  const std::vector<color_plane_type>& scanline, image& img,
140  unsigned int y) const
141 {
142  CLAW_PRECOND(scanline.size() == 3);
143 
144  for(unsigned int x = 0; x != img.width(); ++x)
145  {
146  img[y][x].components.red = scanline[0][x];
147  img[y][x].components.green = scanline[1][x];
148  img[y][x].components.blue = scanline[2][x];
149  img[y][x].components.alpha
150  = std::numeric_limits<rgba_pixel_8::component_type>::max();
151  }
152 }
153 
159 claw::graphic::pcx::reader::rle_pcx_output_buffer::rle_pcx_output_buffer(
160  color_plane_type& result)
161  : m_result(result)
162  , m_position(0)
163 {}
164 
170 void claw::graphic::pcx::reader::rle_pcx_output_buffer::fill(unsigned int n,
171  u_int_8 pattern)
172 {
173  CLAW_PRECOND(m_position + n <= m_result.size());
174 
175  for(unsigned int i = 0; i != n; ++i)
176  m_result[m_position + i] = pattern;
177 
178  m_position += n;
179 }
180 
186 void claw::graphic::pcx::reader::rle_pcx_output_buffer::copy(
187  unsigned int n, rle_pcx_input_buffer& buffer)
188 {
189  CLAW_ASSERT(false, "This method should not have been called");
190 }
191 
195 bool claw::graphic::pcx::reader::rle_pcx_output_buffer::completed() const
196 {
197  return m_position == m_result.size();
198 }
199 
205 void claw::graphic::pcx::reader::rle_pcx_decoder::read_mode(
206  input_buffer_type& input, output_buffer_type& output)
207 {
208  this->m_mode = this->stop;
209  bool ok = !output.completed();
210 
211  if(ok && (input.remaining() < 1))
212  ok = input.read_more(1);
213 
214  if(ok)
215  {
216  unsigned char key = input.get_next();
217  this->m_mode = this->compressed;
218 
219  if((key & 0xC0) == 0xC0)
220  {
221  this->m_count = key & 0x3F;
222 
223  if(input.remaining() < 1)
224  input.read_more(1);
225 
226  this->m_pattern = input.get_next();
227  }
228  else
229  {
230  this->m_count = 1;
231  this->m_pattern = key;
232  }
233  }
234 }
235 
241  : m_image(img)
242 {}
243 
251  : m_image(img)
252 {
253  load(f);
254 }
255 
260 void claw::graphic::pcx::reader::load(std::istream& f)
261 {
262  CLAW_PRECOND(!!f);
263  std::istream::pos_type init_pos = f.tellg();
264 
265  try
266  {
267  header h;
268 
269  f.read(reinterpret_cast<char*>(&h), sizeof(header));
270 
271  if(f.rdstate() == std::ios_base::goodbit)
272  {
273  check_if_pcx(h);
274 
275  m_image.set_size(h.window.x_max - h.window.x_min + 1,
276  h.window.y_max - h.window.y_min + 1);
277 
278  bool supported_format = true;
279 
280  switch(h.color_planes)
281  {
282  case 1:
283  if(h.bpp == 1)
284  load_mono(h, f);
285  else if(h.bpp == 8)
286  load_256_color_mapped(h, f);
287  else
288  supported_format = false;
289  break;
290  case 3:
291  if(h.bpp == 8)
292  load_true_color(h, f);
293  else
294  supported_format = false;
295  break;
296  case 4:
297  if(h.bpp == 1)
298  load_16_color_mapped(h, f);
299  else
300  supported_format = false;
301  break;
302  default:
303  supported_format = false;
304  }
305 
306  if(supported_format == false)
307  throw claw::bad_format("pcx::reader::pcx: unsupported image type");
308  }
309  else
310  throw claw::bad_format("claw::pcx::reader::pcx: can't read header");
311  }
312  catch(...)
313  {
314  f.clear();
315  f.seekg(init_pos, std::ios_base::beg);
316  throw;
317  }
318 }
319 
324 void claw::graphic::pcx::reader::check_if_pcx(const header& h) const
325 {
326  if(h.manufacturer != 0x0A)
327  throw CLAW_EXCEPTION("Not a Pcx file.");
328 }
329 
335 void claw::graphic::pcx::reader::load_mono(const header& h, std::istream& f)
336 {
337  assert(h.color_planes == 1);
338 
339  converter_mono convert;
340  decompress(h, f, convert);
341 }
342 
348 void claw::graphic::pcx::reader::load_16_color_mapped(const header& h,
349  std::istream& f)
350 {
351  assert(h.color_planes == 4);
352 
353  converter_16 convert(h);
354  decompress(h, f, convert);
355 }
356 
362 void claw::graphic::pcx::reader::load_true_color(const header& h,
363  std::istream& f)
364 {
365  assert(h.color_planes == 3);
366 
367  converter_true_color convert;
368  decompress(h, f, convert);
369 }
370 
376 void claw::graphic::pcx::reader::load_256_color_mapped(const header& h,
377  std::istream& f)
378 {
379  assert(h.color_planes == 1);
380 
381  // 256 RGB triplets
382  const unsigned int palette_length = 256 * 3;
383 
384  color_palette32 palette(256);
385  std::istream::pos_type init_pos = f.tellg();
386 
387  // -1 for the check byte
388  f.seekg(-(std::istream::off_type)palette_length - 1, std::ios_base::end);
389 
390  char check;
391  f.read(&check, 1);
392 
393  if(check != 12)
394  throw CLAW_EXCEPTION("PCX: The color palette is missing.");
395 
396  char buffer[palette_length];
397  f.read(buffer, palette_length);
398 
399  for(unsigned int i = 0, j = 0; i != palette_length; i += 3, ++j)
400  {
401  palette[j].components.alpha = 255;
402  palette[j].components.red = buffer[i];
403  palette[j].components.green = buffer[i + 1];
404  palette[j].components.blue = buffer[i + 2];
405  }
406 
407  f.seekg(init_pos);
408  converter_256 convert(palette);
409  decompress(h, f, convert);
410 }
411 
417 void claw::graphic::pcx::reader::decompress_line(
418  std::istream& f, color_plane_type& scanline) const
419 {
420  rle_pcx_input_buffer input(f);
421  rle_pcx_output_buffer output(scanline);
422 
423  rle_pcx_decoder decoder;
424 
425  decoder.decode(input, output);
426 }
rgba_pixel black_pixel
The black color.
reader(image &img)
Constructor.
Definition: pcx_reader.cpp:240
unsigned_integer_of_size< 8 >::type u_int_8
An unsigned integer on 8 bits.
Definition: types.hpp:132
#define CLAW_ASSERT(b, s)
Print a message on std::cerr and stop the program if a condition is not true.
Definition: assert.hpp:88
A class for pcx pictures.
A simple class to use as exception with string message.
A class to deal with images.
Definition: image.hpp:50
rgba_pixel white_pixel
The white color.
void load(std::istream &f)
Load an image from a pcx file.
Definition: pcx_reader.cpp:260
#define CLAW_EXCEPTION(m)
Create an exception and add the name of the current function to the message.
Definition: exception.hpp:92
#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