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