Visual Servoing Platform version 3.5.0
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
62void 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
159void 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
269void 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
446void 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)
Error that can be emited by the vpImage class and its derivates.
unsigned int getWidth() const
Definition: vpImage.h:246
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
unsigned int getHeight() const
Definition: vpImage.h:188
@ alpha_default
Definition: vpRGBa.h:69
#define vpERROR_TRACE
Definition: vpDebug.h:393