Visual Servoing Platform  version 3.5.0 under development (2022-02-15)
vpImageIoLibpng.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2022 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See http://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Libpng backend for PNG image I/O operations.
33  *
34  *****************************************************************************/
35 
41 #include "vpImageIoBackend.h"
42 #include <visp3/core/vpImageConvert.h>
43 
44 #if defined(VISP_HAVE_PNG)
45 #include <png.h>
46 #endif
47 
48 
49 //--------------------------------------------------------------------------
50 // PNG
51 //--------------------------------------------------------------------------
52 
53 #if defined(VISP_HAVE_PNG)
54 
62 void writePNGLibpng(const vpImage<unsigned char> &I, const std::string &filename)
63 {
64  FILE *file;
65 
66  // Test the filename
67  if (filename.empty()) {
68  throw(vpImageException(vpImageException::ioError, "Cannot create PNG file: filename empty"));
69  }
70 
71  file = fopen(filename.c_str(), "wb");
72 
73  if (file == NULL) {
74  throw(vpImageException(vpImageException::ioError, "Cannot create PNG file \"%s\"", filename.c_str()));
75  }
76 
77  /* create a png info struct */
78  png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
79  if (!png_ptr) {
80  fclose(file);
81  vpERROR_TRACE("Error during png_create_write_struct()\n");
82  throw(vpImageException(vpImageException::ioError, "PNG write error"));
83  }
84 
85  png_infop info_ptr = png_create_info_struct(png_ptr);
86  if (!info_ptr) {
87  fclose(file);
88  png_destroy_write_struct(&png_ptr, NULL);
89  vpERROR_TRACE("Error during png_create_info_struct()\n");
90  throw(vpImageException(vpImageException::ioError, "PNG write error"));
91  }
92 
93  /* initialize the setjmp for returning properly after a libpng error occured
94  */
95  if (setjmp(png_jmpbuf(png_ptr))) {
96  fclose(file);
97  png_destroy_write_struct(&png_ptr, &info_ptr);
98  vpERROR_TRACE("Error during init_io\n");
99  throw(vpImageException(vpImageException::ioError, "PNG write error"));
100  }
101 
102  /* setup libpng for using standard C fwrite() function with our FILE pointer
103  */
104  png_init_io(png_ptr, file);
105 
106  unsigned int width = I.getWidth();
107  unsigned int height = I.getHeight();
108  int bit_depth = 8;
109  int color_type = PNG_COLOR_TYPE_GRAY;
110  /* set some useful information from header */
111 
112  if (setjmp(png_jmpbuf(png_ptr))) {
113  fclose(file);
114  png_destroy_write_struct(&png_ptr, &info_ptr);
115  vpERROR_TRACE("Error during write header\n");
116  throw(vpImageException(vpImageException::ioError, "PNG write error"));
117  }
118 
119  png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
120  PNG_FILTER_TYPE_BASE);
121 
122  png_write_info(png_ptr, info_ptr);
123 
124  png_bytep *row_ptrs = new png_bytep[height];
125  for (unsigned int i = 0; i < height; i++)
126  row_ptrs[i] = new png_byte[width];
127 
128  unsigned char *input = (unsigned char *)I.bitmap;
129 
130  for (unsigned int i = 0; i < height; i++) {
131  png_byte *row = row_ptrs[i];
132  for (unsigned int j = 0; j < width; j++) {
133  row[j] = *(input);
134  input++;
135  }
136  }
137 
138  png_write_image(png_ptr, row_ptrs);
139 
140  png_write_end(png_ptr, NULL);
141 
142  for (unsigned int j = 0; j < height; j++)
143  delete[] row_ptrs[j];
144 
145  delete[] row_ptrs;
146 
147  png_destroy_write_struct(&png_ptr, &info_ptr);
148 
149  fclose(file);
150 }
151 
159 void writePNGLibpng(const vpImage<vpRGBa> &I, const std::string &filename)
160 {
161  FILE *file;
162 
163  // Test the filename
164  if (filename.empty()) {
165  throw(vpImageException(vpImageException::ioError, "Cannot create PNG file: filename empty"));
166  }
167 
168  file = fopen(filename.c_str(), "wb");
169 
170  if (file == NULL) {
171  throw(vpImageException(vpImageException::ioError, "Cannot create PNG file \"%s\"", filename.c_str()));
172  }
173 
174  /* create a png info struct */
175  png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
176  if (!png_ptr) {
177  fclose(file);
178  vpERROR_TRACE("Error during png_create_write_struct()\n");
179  throw(vpImageException(vpImageException::ioError, "PNG write error"));
180  }
181 
182  png_infop info_ptr = png_create_info_struct(png_ptr);
183  if (!info_ptr) {
184  fclose(file);
185  png_destroy_write_struct(&png_ptr, NULL);
186  vpERROR_TRACE("Error during png_create_info_struct()\n");
187  throw(vpImageException(vpImageException::ioError, "PNG write error"));
188  }
189 
190  /* initialize the setjmp for returning properly after a libpng error occured
191  */
192  if (setjmp(png_jmpbuf(png_ptr))) {
193  fclose(file);
194  png_destroy_write_struct(&png_ptr, &info_ptr);
195  vpERROR_TRACE("Error during init_io\n");
196  throw(vpImageException(vpImageException::ioError, "PNG write error"));
197  }
198 
199  /* setup libpng for using standard C fwrite() function with our FILE pointer
200  */
201  png_init_io(png_ptr, file);
202 
203  unsigned int width = I.getWidth();
204  unsigned int height = I.getHeight();
205  int bit_depth = 8;
206  int color_type = PNG_COLOR_TYPE_RGB;
207  /* set some useful information from header */
208 
209  if (setjmp(png_jmpbuf(png_ptr))) {
210  fclose(file);
211  png_destroy_write_struct(&png_ptr, &info_ptr);
212  vpERROR_TRACE("Error during write header\n");
213  throw(vpImageException(vpImageException::ioError, "PNG write error"));
214  }
215 
216  png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
217  PNG_FILTER_TYPE_BASE);
218 
219  png_write_info(png_ptr, info_ptr);
220 
221  png_bytep *row_ptrs = new png_bytep[height];
222  for (unsigned int i = 0; i < height; i++)
223  row_ptrs[i] = new png_byte[3 * width];
224 
225  unsigned char *input = (unsigned char *)I.bitmap;
226 
227  for (unsigned int i = 0; i < height; i++) {
228  png_byte *row = row_ptrs[i];
229  for (unsigned int j = 0; j < width; j++) {
230  row[3 * j] = *(input);
231  input++;
232  row[3 * j + 1] = *(input);
233  input++;
234  row[3 * j + 2] = *(input);
235  input++;
236  input++;
237  }
238  }
239 
240  png_write_image(png_ptr, row_ptrs);
241 
242  png_write_end(png_ptr, NULL);
243 
244  for (unsigned int j = 0; j < height; j++)
245  delete[] row_ptrs[j];
246 
247  delete[] row_ptrs;
248 
249  png_destroy_write_struct(&png_ptr, &info_ptr);
250 
251  fclose(file);
252 }
253 
269 void readPNGLibpng(vpImage<unsigned char> &I, const std::string &filename)
270 {
271  FILE *file;
272  png_byte magic[8];
273  // Test the filename
274  if (filename.empty()) {
275  throw(vpImageException(vpImageException::ioError, "Cannot read PNG image: filename empty"));
276  }
277 
278  file = fopen(filename.c_str(), "rb");
279 
280  if (file == NULL) {
281  throw(vpImageException(vpImageException::ioError, "Cannot read file \"%s\"", filename.c_str()));
282  }
283 
284  /* read magic number */
285  if (fread(magic, 1, sizeof(magic), file) != sizeof(magic)) {
286  fclose(file);
287  throw(vpImageException(vpImageException::ioError, "Cannot read magic number in file \"%s\"", filename.c_str()));
288  }
289 
290  /* check for valid magic number */
291  if (png_sig_cmp(magic, 0, sizeof(magic))) {
292  fclose(file);
293  throw(vpImageException(vpImageException::ioError, "Cannot read PNG file: \"%s\" is not a valid PNG image",
294  filename.c_str()));
295  }
296 
297  /* create a png read struct */
298  // printf("version %s\n", PNG_LIBPNG_VER_STRING);
299  png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
300  if (png_ptr == NULL) {
301  fprintf(stderr, "error: can't create a png read structure!\n");
302  fclose(file);
303  throw(vpImageException(vpImageException::ioError, "error reading png file"));
304  }
305 
306  /* create a png info struct */
307  png_infop info_ptr = png_create_info_struct(png_ptr);
308  if (info_ptr == NULL) {
309  fprintf(stderr, "error: can't create a png info structure!\n");
310  fclose(file);
311  png_destroy_read_struct(&png_ptr, NULL, NULL);
312  throw(vpImageException(vpImageException::ioError, "error reading png file"));
313  }
314 
315  /* initialize the setjmp for returning properly after a libpng error occured
316  */
317  if (setjmp(png_jmpbuf(png_ptr))) {
318  fclose(file);
319  png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
320  vpERROR_TRACE("Error during init io\n");
321  throw(vpImageException(vpImageException::ioError, "PNG read error"));
322  }
323 
324  /* setup libpng for using standard C fread() function with our FILE pointer
325  */
326  png_init_io(png_ptr, file);
327 
328  /* tell libpng that we have already read the magic number */
329  png_set_sig_bytes(png_ptr, sizeof(magic));
330 
331  /* read png info */
332  png_read_info(png_ptr, info_ptr);
333 
334  unsigned int width = png_get_image_width(png_ptr, info_ptr);
335  unsigned int height = png_get_image_height(png_ptr, info_ptr);
336 
337  unsigned int bit_depth, channels, color_type;
338  /* get some useful information from header */
339  bit_depth = png_get_bit_depth(png_ptr, info_ptr);
340  channels = png_get_channels(png_ptr, info_ptr);
341  color_type = png_get_color_type(png_ptr, info_ptr);
342 
343  /* convert index color images to RGB images */
344  if (color_type == PNG_COLOR_TYPE_PALETTE)
345  png_set_palette_to_rgb(png_ptr);
346 
347  /* convert 1-2-4 bits grayscale images to 8 bits grayscale. */
348  if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
349  png_set_expand(png_ptr);
350 
351  // if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
352  // png_set_tRNS_to_alpha (png_ptr);
353 
354  if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
355  png_set_strip_alpha(png_ptr);
356 
357  if (bit_depth == 16)
358  png_set_strip_16(png_ptr);
359  else if (bit_depth < 8)
360  png_set_packing(png_ptr);
361 
362  /* update info structure to apply transformations */
363  png_read_update_info(png_ptr, info_ptr);
364 
365  channels = png_get_channels(png_ptr, info_ptr);
366 
367  if ((width != I.getWidth()) || (height != I.getHeight()))
368  I.resize(height, width);
369 
370  png_bytep *rowPtrs = new png_bytep[height];
371 
372  unsigned int stride = png_get_rowbytes(png_ptr, info_ptr);
373  unsigned char *data = new unsigned char[stride * height];
374 
375  for (unsigned int i = 0; i < height; i++)
376  rowPtrs[i] = (png_bytep)data + (i * stride);
377 
378  png_read_image(png_ptr, rowPtrs);
379 
380  vpImage<vpRGBa> Ic(height, width);
381  unsigned char *output;
382 
383  switch (channels) {
384  case 1:
385  output = (unsigned char *)I.bitmap;
386  for (unsigned int i = 0; i < width * height; i++) {
387  *(output++) = data[i];
388  }
389  break;
390 
391  case 2:
392  output = (unsigned char *)I.bitmap;
393  for (unsigned int i = 0; i < width * height; i++) {
394  *(output++) = data[i * 2];
395  }
396  break;
397 
398  case 3:
399  output = (unsigned char *)Ic.bitmap;
400  for (unsigned int i = 0; i < width * height; i++) {
401  *(output++) = data[i * 3];
402  *(output++) = data[i * 3 + 1];
403  *(output++) = data[i * 3 + 2];
404  *(output++) = vpRGBa::alpha_default;
405  }
407  break;
408 
409  case 4:
410  output = (unsigned char *)Ic.bitmap;
411  for (unsigned int i = 0; i < width * height; i++) {
412  *(output++) = data[i * 4];
413  *(output++) = data[i * 4 + 1];
414  *(output++) = data[i * 4 + 2];
415  *(output++) = data[i * 4 + 3];
416  }
418  break;
419  }
420 
421  delete[](png_bytep) rowPtrs;
422  delete[] data;
423  png_read_end(png_ptr, NULL);
424  png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
425  fclose(file);
426 }
427 
446 void readPNGLibpng(vpImage<vpRGBa> &I, const std::string &filename)
447 {
448  FILE *file;
449  png_byte magic[8];
450 
451  // Test the filename
452  if (filename.empty()) {
453  throw(vpImageException(vpImageException::ioError, "Cannot read PNG image: filename empty"));
454  }
455 
456  file = fopen(filename.c_str(), "rb");
457 
458  if (file == NULL) {
459  throw(vpImageException(vpImageException::ioError, "Cannot read file \"%s\"", filename.c_str()));
460  }
461 
462  /* read magic number */
463  if (fread(magic, 1, sizeof(magic), file) != sizeof(magic)) {
464  fclose(file);
465  throw(vpImageException(vpImageException::ioError, "Cannot read magic number in file \"%s\"", filename.c_str()));
466  }
467 
468  /* check for valid magic number */
469  if (png_sig_cmp(magic, 0, sizeof(magic))) {
470  fclose(file);
471  throw(vpImageException(vpImageException::ioError, "Cannot read PNG file: \"%s\" is not a valid PNG image",
472  filename.c_str()));
473  }
474 
475  /* create a png read struct */
476  png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
477  if (!png_ptr) {
478  fclose(file);
479  vpERROR_TRACE("Error during png_create_read_struct()\n");
480  throw(vpImageException(vpImageException::ioError, "PNG read error"));
481  }
482 
483  /* create a png info struct */
484  png_infop info_ptr = png_create_info_struct(png_ptr);
485  if (!info_ptr) {
486  fclose(file);
487  png_destroy_read_struct(&png_ptr, NULL, NULL);
488  vpERROR_TRACE("Error during png_create_info_struct()\n");
489  throw(vpImageException(vpImageException::ioError, "PNG read error"));
490  }
491 
492  /* initialize the setjmp for returning properly after a libpng error occured
493  */
494  if (setjmp(png_jmpbuf(png_ptr))) {
495  fclose(file);
496  png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
497  vpERROR_TRACE("Error during init io\n");
498  throw(vpImageException(vpImageException::ioError, "PNG read error"));
499  }
500 
501  /* setup libpng for using standard C fread() function with our FILE pointer
502  */
503  png_init_io(png_ptr, file);
504 
505  /* tell libpng that we have already read the magic number */
506  png_set_sig_bytes(png_ptr, sizeof(magic));
507 
508  /* read png info */
509  png_read_info(png_ptr, info_ptr);
510 
511  unsigned int width = png_get_image_width(png_ptr, info_ptr);
512  unsigned int height = png_get_image_height(png_ptr, info_ptr);
513 
514  unsigned int bit_depth, channels, color_type;
515  /* get some useful information from header */
516  bit_depth = png_get_bit_depth(png_ptr, info_ptr);
517  channels = png_get_channels(png_ptr, info_ptr);
518  color_type = png_get_color_type(png_ptr, info_ptr);
519 
520  /* convert index color images to RGB images */
521  if (color_type == PNG_COLOR_TYPE_PALETTE)
522  png_set_palette_to_rgb(png_ptr);
523 
524  /* convert 1-2-4 bits grayscale images to 8 bits grayscale. */
525  if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
526  png_set_expand(png_ptr);
527 
528  // if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
529  // png_set_tRNS_to_alpha (png_ptr);
530 
531  if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
532  png_set_strip_alpha(png_ptr);
533 
534  if (bit_depth == 16)
535  png_set_strip_16(png_ptr);
536  else if (bit_depth < 8)
537  png_set_packing(png_ptr);
538 
539  /* update info structure to apply transformations */
540  png_read_update_info(png_ptr, info_ptr);
541 
542  channels = png_get_channels(png_ptr, info_ptr);
543 
544  if ((width != I.getWidth()) || (height != I.getHeight()))
545  I.resize(height, width);
546 
547  png_bytep *rowPtrs = new png_bytep[height];
548 
549  unsigned int stride = png_get_rowbytes(png_ptr, info_ptr);
550  unsigned char *data = new unsigned char[stride * height];
551 
552  for (unsigned int i = 0; i < height; i++)
553  rowPtrs[i] = (png_bytep)data + (i * stride);
554 
555  png_read_image(png_ptr, rowPtrs);
556 
557  vpImage<unsigned char> Ig(height, width);
558  unsigned char *output;
559 
560  switch (channels) {
561  case 1:
562  output = (unsigned char *)Ig.bitmap;
563  for (unsigned int i = 0; i < width * height; i++) {
564  *(output++) = data[i];
565  }
567  break;
568 
569  case 2:
570  output = (unsigned char *)Ig.bitmap;
571  for (unsigned int i = 0; i < width * height; i++) {
572  *(output++) = data[i * 2];
573  }
575  break;
576 
577  case 3:
578  output = (unsigned char *)I.bitmap;
579  for (unsigned int i = 0; i < width * height; i++) {
580  *(output++) = data[i * 3];
581  *(output++) = data[i * 3 + 1];
582  *(output++) = data[i * 3 + 2];
583  *(output++) = vpRGBa::alpha_default;
584  }
585  break;
586 
587  case 4:
588  output = (unsigned char *)I.bitmap;
589  for (unsigned int i = 0; i < width * height; i++) {
590  *(output++) = data[i * 4];
591  *(output++) = data[i * 4 + 1];
592  *(output++) = data[i * 4 + 2];
593  *(output++) = data[i * 4 + 3];
594  }
595  break;
596  }
597 
598  delete[](png_bytep) rowPtrs;
599  delete[] data;
600  png_read_end(png_ptr, NULL);
601  png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
602  fclose(file);
603 }
604 #endif
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:800
Type * bitmap
points toward the bitmap
Definition: vpImage.h:143
#define vpERROR_TRACE
Definition: vpDebug.h:393
Error that can be emited by the vpImage class and its derivates.
unsigned int getHeight() const
Definition: vpImage.h:188
unsigned int getWidth() const
Definition: vpImage.h:246