~ubuntu-branches/ubuntu/oneiric/libclaw/oneiric

« back to all changes in this revision

Viewing changes to claw/code/png_reader.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Julien Jorge
  • Date: 2008-05-17 15:36:57 UTC
  • Revision ID: james.westby@ubuntu.com-20080517153657-0b1204j754ykoz48
Tags: upstream-1.5.2b
ImportĀ upstreamĀ versionĀ 1.5.2b

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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-2008 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@yahoo.fr
 
24
*/
 
25
/**
 
26
 * \file png_reader.cpp
 
27
 * \brief Implementation of the claw::graphic::png::reader class.
 
28
 * \author Julien Jorge
 
29
 */
 
30
#include <claw/png.hpp>
 
31
 
 
32
#include <claw/exception.hpp>
 
33
#include <claw/assert.hpp>
 
34
 
 
35
/*----------------------------------------------------------------------------*/
 
36
/**
 
37
 * \brief Read data from the input stream.
 
38
 * \param png_ptr Informations about the PNG we are reading.
 
39
 * \param data (out) Array of the bytes we have read.
 
40
 * \param length Number of bytes to read.
 
41
 */
 
42
void claw__graphic__png__source_manager__read
 
43
( png_structp png_ptr, png_bytep data, png_size_t length )
 
44
{
 
45
  claw::graphic::png::reader::source_manager* self =
 
46
    (claw::graphic::png::reader::source_manager*)png_get_io_ptr(png_ptr);
 
47
 
 
48
  self->read(data, length);
 
49
} // claw__graphic__png__source_manager__read()
 
50
 
 
51
 
 
52
 
 
53
 
 
54
/*----------------------------------------------------------------------------*/
 
55
/**
 
56
 * \brief Constructor.
 
57
 * \param is The stream we read from.
 
58
 */
 
59
claw::graphic::png::reader::source_manager::source_manager( std::istream& is )
 
60
  : m_input(is)
 
61
{
 
62
  CLAW_PRECOND( !!is );
 
63
} // png::reader::source_manager::source_manager()
 
64
 
 
65
/*----------------------------------------------------------------------------*/
 
66
/**
 
67
 * \brief Read data from the input stream.
 
68
 * \param data (out) Array of the bytes we have read.
 
69
 * \param length Number of bytes to read.
 
70
 */
 
71
void claw::graphic::png::reader::source_manager::read
 
72
( png_bytep data, png_size_t length )
 
73
{
 
74
  m_input.read( (char*)data, length * sizeof(png_byte) );
 
75
} // png::reader::source_manager::read()
 
76
 
 
77
 
 
78
 
 
79
 
 
80
/*----------------------------------------------------------------------------*/
 
81
const unsigned int claw::graphic::png::reader::s_rgba_pixel_size = 4;
 
82
 
 
83
/*----------------------------------------------------------------------------*/
 
84
/**
 
85
 * \brief Constructor.
 
86
 * \param img The image in which the data will be stored.
 
87
 */
 
88
claw::graphic::png::reader::reader( image& img )
 
89
  : m_image( img )
 
90
{
 
91
 
 
92
} // png::reader::reader()
 
93
 
 
94
/*----------------------------------------------------------------------------*/
 
95
/**
 
96
 * \brief Constructor.
 
97
 * \param img The image in which the data will be stored.
 
98
 * \param f The file from which we read the data.
 
99
 * \post img contains the data from \a f.
 
100
 */
 
101
claw::graphic::png::reader::reader( image& img, std::istream& f )
 
102
  : m_image( img )
 
103
{
 
104
  load(f);
 
105
} // png::reader::reader()
 
106
 
 
107
/*----------------------------------------------------------------------------*/
 
108
/**
 
109
 * \brief Load an image from a png file.
 
110
 * \param f PNG file.
 
111
 */
 
112
void claw::graphic::png::reader::load( std::istream& f )
 
113
{
 
114
  CLAW_PRECOND( !!f );
 
115
 
 
116
  std::istream::pos_type init_pos = f.tellg();
 
117
 
 
118
  try
 
119
    {
 
120
      read_from_file(f);
 
121
    }
 
122
  catch(...)
 
123
    {
 
124
      f.clear();
 
125
      f.seekg( init_pos, std::ios_base::beg );
 
126
      throw;
 
127
    }
 
128
} // png::reader::load()
 
129
 
 
130
/*----------------------------------------------------------------------------*/
 
131
/**
 
132
 * \brief Load an image from a png file.
 
133
 * \param f PNG file.
 
134
 */
 
135
void claw::graphic::png::reader::read_from_file( std::istream& f )
 
136
{
 
137
  source_manager infile(f);
 
138
  png_structp png_ptr;
 
139
  png_infop info_ptr;
 
140
 
 
141
  create_read_structures(png_ptr, info_ptr);
 
142
 
 
143
  if (setjmp(png_jmpbuf(png_ptr)))
 
144
    {
 
145
      /* If we get here, we had a problem reading the file */
 
146
      /* Free all of the memory associated with the png_ptr and info_ptr */
 
147
      png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
 
148
      throw CLAW_EXCEPTION("Invalid PNG file.");
 
149
    }
 
150
      
 
151
  check_if_png( png_ptr, f );
 
152
 
 
153
  png_set_read_fn( png_ptr, (void *)&infile,
 
154
                   claw__graphic__png__source_manager__read );
 
155
 
 
156
  png_set_strip_16(png_ptr);
 
157
  png_set_gray_1_2_4_to_8(png_ptr);
 
158
  png_set_packing(png_ptr);
 
159
 
 
160
  // transform palette index into RGB value
 
161
  png_set_palette_to_rgb(png_ptr);
 
162
 
 
163
  // add an alpha value if none
 
164
  png_set_filler( png_ptr, std::numeric_limits<pixel32::component_type>::max(),
 
165
                  PNG_FILLER_AFTER );
 
166
 
 
167
  png_read_info(png_ptr, info_ptr);
 
168
  read_image( png_ptr, info_ptr );
 
169
      
 
170
  png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
 
171
} // png::reader::read_from_file()
 
172
 
 
173
/*----------------------------------------------------------------------------*/
 
174
/**
 
175
 * \brief Check that the stream contains a PNG file.
 
176
 * \param png_ptr PNG file description.
 
177
 * \param f The stream to read from.
 
178
 */
 
179
void claw::graphic::png::reader::check_if_png
 
180
( png_structp png_ptr, std::istream& f ) const
 
181
{
 
182
  CLAW_PRECOND( !!f );
 
183
 
 
184
  const unsigned int bytes_to_check = 8;
 
185
  png_byte buffer[bytes_to_check];
 
186
 
 
187
  /* Read in some of the signature bytes */
 
188
  f.read( (char*)buffer, bytes_to_check * sizeof(png_byte) );
 
189
 
 
190
  if ( (png_sig_cmp(buffer, (png_size_t)0, bytes_to_check) != 0) || !f )
 
191
    throw CLAW_EXCEPTION( "Not a PNG file." );
 
192
 
 
193
  png_set_sig_bytes(png_ptr, bytes_to_check);
 
194
} // png::reader::check_if_png()
 
195
 
 
196
/*----------------------------------------------------------------------------*/
 
197
/**
 
198
 * \brief Read the image data of the PNG.
 
199
 * \param png_ptr PNG file description.
 
200
 * \param info_ptr PNG file informations.
 
201
 */
 
202
void claw::graphic::png::reader::read_image
 
203
( png_structp png_ptr, png_infop info_ptr )
 
204
{
 
205
  CLAW_PRECOND( png_ptr );
 
206
  CLAW_PRECOND( info_ptr );
 
207
 
 
208
  m_image.set_size( png_get_image_width(png_ptr, info_ptr),
 
209
                    png_get_image_height(png_ptr, info_ptr) );
 
210
 
 
211
  if ( png_get_interlace_type(png_ptr, info_ptr) == PNG_INTERLACE_NONE )
 
212
    read_sequential_image(png_ptr, info_ptr);
 
213
  else
 
214
    read_interlaced_image( png_ptr, info_ptr,
 
215
                           png_set_interlace_handling(png_ptr) );
 
216
} // png::reader::read_image()
 
217
 
 
218
/*----------------------------------------------------------------------------*/
 
219
/**
 
220
 * \brief Read the image data of a non interlaced PNG.
 
221
 * \param png_ptr PNG file description.
 
222
 * \param info_ptr PNG file informations.
 
223
 */
 
224
void claw::graphic::png::reader::read_sequential_image
 
225
( png_structp png_ptr, png_infop info_ptr )
 
226
{
 
227
  CLAW_PRECOND( png_ptr );
 
228
  CLAW_PRECOND( info_ptr );
 
229
 
 
230
  png_bytep data =
 
231
    (png_bytep)png_malloc( png_ptr, s_rgba_pixel_size * m_image.width() );
 
232
 
 
233
  try
 
234
    {
 
235
      for (unsigned int y=0; y!=m_image.height(); ++y)
 
236
        {
 
237
          png_read_row(png_ptr, data, NULL);
 
238
          copy_pixel_line( data, y );
 
239
        }
 
240
    }
 
241
  catch(...)
 
242
    {
 
243
      png_free(png_ptr, data);
 
244
      throw;
 
245
    }
 
246
 
 
247
  png_free(png_ptr, data);
 
248
} // png::reader::read_sequential_image()
 
249
 
 
250
/*----------------------------------------------------------------------------*/
 
251
/**
 
252
 * \brief Read the image data of an interlaced PNG.
 
253
 * \param png_ptr PNG file description.
 
254
 * \param info_ptr PNG file informations.
 
255
 * \param passes Number of passes (for interlaced images).
 
256
 */
 
257
void claw::graphic::png::reader::read_interlaced_image
 
258
( png_structp png_ptr, png_infop info_ptr, unsigned int passes )
 
259
{
 
260
  CLAW_PRECOND( passes > 1 );
 
261
  CLAW_PRECOND( png_ptr );
 
262
  CLAW_PRECOND( info_ptr );
 
263
 
 
264
  const unsigned int row_length = s_rgba_pixel_size * m_image.width();
 
265
  png_bytepp data =
 
266
    (png_bytepp)png_malloc( png_ptr, sizeof(png_bytep) * m_image.height() );
 
267
  unsigned int i=0;
 
268
 
 
269
  try
 
270
    {
 
271
      for (i=0; i!=m_image.height(); ++i)
 
272
        {
 
273
          data[i] = (png_bytep)png_malloc( png_ptr, row_length );
 
274
 
 
275
          if (!data[i])
 
276
            throw std::bad_alloc();
 
277
 
 
278
          copy_pixel_line( data[i], i );
 
279
        }
 
280
 
 
281
      for (unsigned int p=0; p!=passes; ++p)
 
282
        png_read_rows( png_ptr, data, NULL, m_image.height() );
 
283
 
 
284
      for (unsigned int y=0; y!=m_image.height(); ++y)
 
285
        copy_pixel_line( data[y], y );
 
286
    }
 
287
  catch(...)
 
288
    {
 
289
      for(unsigned int j=0; j!=i; ++j)
 
290
        png_free(png_ptr, data[j]);
 
291
 
 
292
      png_free(png_ptr, data);
 
293
      throw;
 
294
    }
 
295
 
 
296
  for(i=0; i!=m_image.height(); ++i)
 
297
    png_free(png_ptr, data[i]);
 
298
 
 
299
  png_free(png_ptr, data);
 
300
} // png::reader::read_interlaced_image()
 
301
 
 
302
/*----------------------------------------------------------------------------*/
 
303
/**
 
304
 * \brief Copy the pixels taken from the PNG to the image.
 
305
 * \param data the pixels from the PNG image.
 
306
 * \param y Index of the line of the image in which we copy the pixels.
 
307
 */
 
308
void
 
309
claw::graphic::png::reader::copy_pixel_line( png_bytep data, unsigned int y )
 
310
{
 
311
  CLAW_PRECOND( data );
 
312
  CLAW_PRECOND( y < m_image.height() );
 
313
 
 
314
  // four bytes for each pixel in the line
 
315
  for (unsigned int x=0; x!=m_image.width(); ++x, data+=s_rgba_pixel_size)
 
316
    {
 
317
      m_image[y][x].components.red   = data[0];
 
318
      m_image[y][x].components.green = data[1];
 
319
      m_image[y][x].components.blue  = data[2];
 
320
      m_image[y][x].components.alpha = data[3];
 
321
    }
 
322
} // png::reader::copy_pixel_line()
 
323
 
 
324
/*----------------------------------------------------------------------------*/
 
325
/**
 
326
 * \brief Initialize the png read structures.
 
327
 * \param png_ptr PNG file description.
 
328
 * \param info_ptr PNG file informations.
 
329
 */
 
330
void claw::graphic::png::reader::create_read_structures
 
331
( png_structp& png_ptr, png_infop& info_ptr ) const
 
332
{
 
333
  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
 
334
 
 
335
  if (png_ptr)
 
336
    {
 
337
      info_ptr = png_create_info_struct(png_ptr);
 
338
 
 
339
      if (!info_ptr)
 
340
        png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
 
341
    }
 
342
 
 
343
  if (!png_ptr || !info_ptr)
 
344
    throw CLAW_EXCEPTION("Can't create PNG read structures.");
 
345
} // png::reader::create_read_structures()