SLIP  1.4
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PngReader.hpp
Go to the documentation of this file.
1 
10 #ifndef PNGREADER_HPP_
11 #define PNGREADER_HPP_
12 
13 #include <iostream>
14 #include <sstream>
15 
16 
17 #include "PngDef.hpp"
18 #include "error.hpp"
19 #include "ContainerReader.hpp"
20 
21 namespace slip {
22 
39 template<class Container2d, typename T, std::size_t Nb_components, std::size_t Nb_block>
40 class PngReader: public ContainerReader<Container2d,T,Nb_block> {
41 public:
42  typedef Container2d container_type;
43  typedef T value_type;
45 
50 
55  :base(),png_ptr(NULL),info_ptr(NULL),sig_read(0),width(0),height(0),bit_depth(0),color_type(0),
56  interlace_type(0), number_passes(0),infile(NULL),row_stride(0),
57  block_ind(1),block_size(0),last_block_size(0),last_it(0),finished(0),initialized(0)
58  {}
59 
65  PngReader(std::string data_filename)
66  :base(data_filename),png_ptr(NULL),info_ptr(NULL),sig_read(0),width(0),height(0),bit_depth(0),color_type(0),
67  interlace_type(0), number_passes(0),infile(NULL),row_stride(0),
68  block_ind(1),block_size(0),last_block_size(0),last_it(0),finished(0),initialized(0)
69  {initialize();}
70 
75  virtual ~PngReader()
76  {
77  if(initialized){
78  release();
79  }
80  }
81 
88  void initialize();
89 
94  void release();
95 
105  int read(Container2d & in);
106 
107 private :
108  //libpng variables (see example.c provided with png.h)
109  png_structp png_ptr;
110  png_infop info_ptr;
111  unsigned int sig_read;
112  png_uint_32 width, height;
113  int bit_depth, color_type, interlace_type, number_passes;
114  png_bytep row_pointers[1];//buffer
115  FILE* infile;//input file stream
116 
117  int row_stride; /* physical row width in output buffer */
118  int block_ind;/*current read block indice*/
119  int block_size;/*block size*/
120  int last_block_size;/*last block size*/
121  bool last_it;/*indicates that the current read is the last.*/
122  bool finished;/*indicates that the last read has been done and no more data are available.*/
123  bool initialized;/*indicates that the reader has been initialized*/
124 
125 };
126 
127 }
130 namespace slip {
131 
132 template<class Container2d, typename T, std::size_t Nb_components, std::size_t Nb_block>
133 inline
135  if (!initialized){
136  if (Nb_components != 1 && Nb_components != 3){
137  std::ostringstream err;
138  err << FILE_READ_ERROR << this->data_filename_ << " | Nb_components should be 1 or 3.";
139  slip::slip_exception exc(std::string("slip"), std::string("PngReader::initialize()"), err.str());
140  throw (exc);
141  }
142 
143  if ((infile = fopen(this->data_filename_.c_str(), "rb")) == NULL) {
144  std::ostringstream err;
145  err << FILE_OPEN_ERROR << this->data_filename_;
146  slip::slip_exception exc(std::string("slip"), std::string("PngReader::initialize()"), err.str());
147  throw (exc);
148  }
149 
150  /* Create and initialize the png_struct with the desired error handler
151  * functions. If you want to use the default stderr and longjump method,
152  * you can supply NULL for the last three parameters. We also supply the
153  * the compiler header file version, so that we know if the application
154  * was compiled with a compatible version of the library. REQUIRED
155  */
156  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
157 
158  if (png_ptr == NULL)
159  {
160  std::ostringstream err;
161  err << FILE_READ_ERROR << this->data_filename_ << " | png_struct initialization failed.";
162  slip::slip_exception exc(std::string("slip"), std::string("PngReader::initialize()"), err.str());
163  fclose(infile);
164  throw (exc);
165  }
166 
167  /* Allocate/initialize the memory for image information. REQUIRED. */
168  info_ptr = png_create_info_struct(png_ptr);
169  if (info_ptr == NULL)
170  {
171  png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
172  fclose(infile);
173  std::ostringstream err;
174  err << FILE_READ_ERROR << this->data_filename_ << " | info_ptr initialization failed.";
175  slip::slip_exception exc(std::string("slip"), std::string("PngReader::initialize()"), err.str());
176  throw (exc);
177  }
178 
179  /* Set error handling if you are using the setjmp/longjmp method (this is
180  * the normal method of doing things with libpng). REQUIRED unless you
181  * set up your own error handlers in the png_create_read_struct() earlier.
182  */
183 
184  if (setjmp(png_jmpbuf(png_ptr)))
185  {
186  /* Free all of the memory associated with the png_ptr and info_ptr */
187  png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
188  fclose(infile);
189  /* If we get here, we had a problem reading the file */
190  std::ostringstream err;
191  err << FILE_READ_ERROR << this->data_filename_ << " | PNG library has signaled an error";
192  slip::slip_exception exc(std::string("slip"), std::string("PngReader::initialize()"), err.str());
193  throw (exc);
194  }
195 
196  /* I/O initialization */
197  png_init_io(png_ptr, infile);
198 
199  /* If we have already read some of the signature */
200  png_set_sig_bytes(png_ptr, sig_read);
201 
202  /* The call to png_read_info() gives us all of the information from the
203  * PNG file before the first IDAT (image data chunk). REQUIRED
204  */
205  png_read_info(png_ptr, info_ptr);
206 
207  png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
208  &interlace_type, int_p_NULL, int_p_NULL);
209 
210  if(png_ptr->channels != Nb_components){
211  fclose(infile);
212  std::ostringstream err;
213  err << FILE_READ_ERROR << this->data_filename_ << " | Nb_components does not match.";
214  slip::slip_exception exc(std::string("slip"), std::string("PngReader::initialize()"), err.str());
215  throw(exc);
216  }
217 
218  /* Set up the data transformations you want. Note that these are all
219  * optional. Only call them if you want/need them. Many of the
220  * transformations only work on specific types of images, and many
221  * are mutually exclusive.
222  */
223 
224  /* Tell libpng to strip 16 bit/color files down to 8 bits/color */
225  png_set_strip_16(png_ptr);
226 
227  /* Strip alpha bytes from the input data without combining with the
228  * background (not recommended).
229  */
230  //png_set_strip_alpha(png_ptr);
231 
232  /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
233  * byte into separate bytes (useful for paletted and grayscale images).
234  */
235  png_set_packing(png_ptr);
236 
237  /* Change the order of packed pixels to least significant bit first
238  * (not useful if you are using png_set_packing). */
239  png_set_packswap(png_ptr);
240 
241 
242  /* Expand paletted colors into true RGB triplets */
243  if (color_type == PNG_COLOR_TYPE_PALETTE){
244  png_set_palette_to_rgb(png_ptr);
245  }
246 
247  /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
248  if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8){
249  png_set_expand_gray_1_2_4_to_8(png_ptr);
250  }
251 
252  /* Swap bytes of 16 bit files to least significant byte first */
253  png_set_swap(png_ptr);
254 
255  /* Turn on interlace handling. REQUIRED if you are not using
256  * png_read_image(). To see how to handle interlacing passes,
257  * see the png_read_row() method below:
258  */
259  number_passes = png_set_interlace_handling(png_ptr);
260 
261  /* Clear the pointer array */
262  row_pointers[0] = NULL;
263 
264  // for (row = 0; row < height; row++)
265  row_pointers[0] = reinterpret_cast<png_bytep>(png_malloc(png_ptr, png_get_rowbytes(png_ptr,info_ptr)));
266 
267  /*samples per row in output buffer */
268  row_stride = png_get_rowbytes(png_ptr,info_ptr);
269  block_size = static_cast<int>(height) / Nb_block;
270  last_block_size = static_cast<int>(height) % Nb_block;
271  last_block_size = (last_block_size == 0 ? block_size : block_size+last_block_size);
272  last_it = (Nb_block == 1);
273  finished = (last_it && last_block_size == 0);
274  initialized = true;
275  }
276 }
277 
278 template<class Container2d, typename T, std::size_t Nb_components, std::size_t Nb_block>
280  if(!initialized){
281  std::ostringstream err;
282  err << FILE_READ_ERROR << this->data_filename_ << " | The reader needs to be initialized before reading.";
283  slip::slip_exception exc(std::string("slip"), std::string("PngReader::read()"), err.str());
284  throw (exc);
285  }
286  if (finished)
287  return 0;
288 
289  if (last_it)
290  in.resize(last_block_size,static_cast<std::size_t>(width),T());
291  else{
292  in.resize(block_size,static_cast<std::size_t>(width),T());
293  }
294  if(static_cast<std::size_t>(height) - static_cast<std::size_t>(png_ptr->row_number)< in.height()){
295  std::ostringstream err;
296  err << FILE_READ_ERROR << this->data_filename_ << " | Bad image dimensions.";
297  slip::slip_exception exc(std::string("slip"), std::string("PngReader::read()"), err.str());
298  throw (exc);
299  }
300 
301  /* If the image is interlaced, number_passes readings of the same row has to be done*/
302  //std::cerr << "row_nb = " << png_ptr->row_number << "\n";
303  for (int pass = 0; pass < number_passes; pass++)
304  {
305  /* Read the image a single row at a time */
306  for(unsigned int i=0; i < in.height(); ++i)
307  {
308  png_read_rows(png_ptr, &row_pointers[0], png_bytepp_NULL, 1);
309  T * ptr_i = reinterpret_cast<T *>(in[i]);
310  std::copy(row_pointers[0],row_pointers[0]+row_stride,ptr_i);
311  }
312  }
313 
314  block_ind++;
315  if (last_it){
316  /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */
317  png_read_end(png_ptr, info_ptr);
318  finished = true;
319  }
320  else
321  last_it = (block_ind == Nb_block);
322  return (!finished);
323 }
324 
325 template<class Container2d, typename T, std::size_t Nb_components, std::size_t Nb_block>
327  if(initialized){
328  /* At this point you have read the entire image */
329 
330  /* Clean up after the read, and free any memory allocated - REQUIRED */
331  png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
332 
333  /* Close the file */
334  if (infile != NULL)
335  fclose(infile);
336  /* That's it */
337  if (row_pointers[0])
338  free(row_pointers[0]);
339  sig_read = 0;
340  width = 0;
341  height = 0;
342  bit_depth = 0;
343  color_type = 0;
344  interlace_type = 0;
345  number_passes = 0;
346  row_stride = 0;
347  block_ind = 1;
348  block_size = 0;
349  last_block_size = 0;
350  last_it = false;
351  finished = false;
352  initialized = false;
353  }
354 }
355 
356 }
358 #endif /* PNGREADER_HPP_ */
virtual ~PngReader()
Destructor.
Definition: PngReader.hpp:75
Contains the container reader base class.
int read(Container2d &in)
virtual read function. If Nb_block is more than one, it reads only one container, and returns 0...
Definition: PngReader.hpp:279
standard exception extension name have been changed to eliminate conflicts with QT ...
Definition: error.hpp:106
PngReader()
Default constructor.
Definition: PngReader.hpp:54
Some definitions specific to libpng.
const std::string FILE_OPEN_ERROR
Definition: error.hpp:82
ContainerReader is the base class of the readers classes. All readers are working the same way: ...
void copy(_II first, _II last, _OI output_first)
Copy algorithm optimized for slip iterators.
Definition: copy_ext.hpp:177
void release()
release the reading process.
Definition: PngReader.hpp:326
Provides SLIP error messages.
void initialize()
initialized the reading process.
Definition: PngReader.hpp:134
PngReader(std::string data_filename)
Definition: PngReader.hpp:65
PngReader, inherited from ContainerReader, is a reader for png images.
Definition: PngReader.hpp:40
Container2d container_type
Definition: PngReader.hpp:42
ContainerReader< Container2d, T, Nb_block > base
Definition: PngReader.hpp:44
const std::string FILE_READ_ERROR
Definition: error.hpp:90