Visual Servoing Platform version 3.5.0
vpImageIoPortable.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 * Backend for portable image format I/O operations.
33 *
34 *****************************************************************************/
35
41#include "vpImageIoBackend.h"
42#include <visp3/core/vpIoTools.h>
43#include <visp3/core/vpImageConvert.h>
44
45
46void vp_decodeHeaderPNM(const std::string &filename, std::ifstream &fd, const std::string &magic, unsigned int &w,
47 unsigned int &h, unsigned int &maxval);
48
49#ifndef DOXYGEN_SHOULD_SKIP_THIS
59void vp_decodeHeaderPNM(const std::string &filename, std::ifstream &fd, const std::string &magic, unsigned int &w,
60 unsigned int &h, unsigned int &maxval)
61{
62 std::string line;
63 unsigned int nb_elt = 4, cpt_elt = 0;
64 while (cpt_elt != nb_elt) {
65 // Skip empty lines or lines starting with # (comment)
66 while (std::getline(fd, line) && (line.compare(0, 1, "#") == 0 || line.size() == 0)) {
67 }
68
69 if (fd.eof()) {
70 fd.close();
71 throw(vpImageException(vpImageException::ioError, "Cannot read header of file \"%s\"", filename.c_str()));
72 }
73
74 std::vector<std::string> header = vpIoTools::splitChain(line, std::string(" "));
75
76 if (header.size() == 0) {
77 fd.close();
78 throw(vpImageException(vpImageException::ioError, "Cannot read header of file \"%s\"", filename.c_str()));
79 }
80
81 if (cpt_elt == 0) { // decode magic
82 if (header[0].compare(0, magic.size(), magic) != 0) {
83 fd.close();
84 throw(vpImageException(vpImageException::ioError, "\"%s\" is not a PNM file with magic number %s",
85 filename.c_str(), magic.c_str()));
86 }
87 cpt_elt++;
88 header.erase(header.begin(),
89 header.begin() + 1); // erase first element that is processed
90 }
91 while (header.size()) {
92 if (cpt_elt == 1) { // decode width
93 std::istringstream ss(header[0]);
94 ss >> w;
95 cpt_elt++;
96 header.erase(header.begin(),
97 header.begin() + 1); // erase first element that is processed
98 } else if (cpt_elt == 2) { // decode height
99 std::istringstream ss(header[0]);
100 ss >> h;
101 cpt_elt++;
102 header.erase(header.begin(),
103 header.begin() + 1); // erase first element that is processed
104 } else if (cpt_elt == 3) { // decode maxval
105 std::istringstream ss(header[0]);
106 ss >> maxval;
107 cpt_elt++;
108 header.erase(header.begin(),
109 header.begin() + 1); // erase first element that is processed
110 }
111 }
112 }
113}
114#endif
115
116//--------------------------------------------------------------------------
117// PFM
118//--------------------------------------------------------------------------
119
128void vp_writePFM(const vpImage<float> &I, const std::string &filename)
129{
130 FILE *fd;
131
132 // Test the filename
133 if (filename.empty()) {
134 throw(vpImageException(vpImageException::ioError, "Cannot write PFM image: filename empty"));
135 }
136
137 fd = fopen(filename.c_str(), "wb");
138
139 if (fd == NULL) {
140 throw(vpImageException(vpImageException::ioError, "Cannot create PFM file \"%s\"", filename.c_str()));
141 }
142
143 // Write the head
144 fprintf(fd, "P8\n"); // Magic number
145 fprintf(fd, "%u %u\n", I.getWidth(), I.getHeight()); // Image size
146 fprintf(fd, "255\n"); // Max level
147
148 // Write the bitmap
149 size_t ierr;
150 size_t nbyte = I.getWidth() * I.getHeight();
151
152 ierr = fwrite(I.bitmap, sizeof(float), nbyte, fd);
153 if (ierr != nbyte) {
154 fclose(fd);
155 throw(vpImageException(vpImageException::ioError, "Cannot save PFM file \"%s\": only %d bytes over %d saved ",
156 filename.c_str(), ierr, nbyte));
157 }
158
159 fflush(fd);
160 fclose(fd);
161}
162
163//--------------------------------------------------------------------------
164// PGM
165//--------------------------------------------------------------------------
166
174void vp_writePGM(const vpImage<unsigned char> &I, const std::string &filename)
175{
176 FILE *fd;
177
178 // Test the filename
179 if (filename.empty()) {
180 throw(vpImageException(vpImageException::ioError, "Cannot create PGM file: filename empty"));
181 }
182
183 fd = fopen(filename.c_str(), "wb");
184
185 if (fd == NULL) {
186 throw(vpImageException(vpImageException::ioError, "Cannot create PGM file \"%s\"", filename.c_str()));
187 }
188
189 // Write the head
190 fprintf(fd, "P5\n"); // Magic number
191 fprintf(fd, "%u %u\n", I.getWidth(), I.getHeight()); // Image size
192 fprintf(fd, "255\n"); // Max level
193
194 // Write the bitmap
195 size_t ierr;
196 size_t nbyte = I.getWidth() * I.getHeight();
197
198 ierr = fwrite(I.bitmap, sizeof(unsigned char), nbyte, fd);
199 if (ierr != nbyte) {
200 fclose(fd);
201 throw(vpImageException(vpImageException::ioError, "Cannot save PGM file \"%s\": only %d over %d bytes saved",
202 filename.c_str(), ierr, nbyte));
203 }
204
205 fflush(fd);
206 fclose(fd);
207}
208
216void vp_writePGM(const vpImage<short> &I, const std::string &filename)
217{
219 unsigned int nrows = I.getHeight();
220 unsigned int ncols = I.getWidth();
221
222 Iuc.resize(nrows, ncols);
223
224 for (unsigned int i = 0; i < nrows * ncols; i++)
225 Iuc.bitmap[i] = (unsigned char)I.bitmap[i];
226
227 vp_writePGM(Iuc, filename);
228}
229
238void vp_writePGM(const vpImage<vpRGBa> &I, const std::string &filename)
239{
240
241 FILE *fd;
242
243 // Test the filename
244 if (filename.empty()) {
245 throw(vpImageException(vpImageException::ioError, "Cannot create PGM file: filename empty"));
246 }
247
248 fd = fopen(filename.c_str(), "wb");
249
250 if (fd == NULL) {
251 throw(vpImageException(vpImageException::ioError, "Cannot create PGM file \"%s\"", filename.c_str()));
252 }
253
254 // Write the head
255 fprintf(fd, "P5\n"); // Magic number
256 fprintf(fd, "%u %u\n", I.getWidth(), I.getHeight()); // Image size
257 fprintf(fd, "255\n"); // Max level
258
259 // Write the bitmap
260 size_t ierr;
261 size_t nbyte = I.getWidth() * I.getHeight();
262
265
266 ierr = fwrite(Itmp.bitmap, sizeof(unsigned char), nbyte, fd);
267 if (ierr != nbyte) {
268 fclose(fd);
269 throw(vpImageException(vpImageException::ioError, "Cannot save PGM file \"%s\": only %d over %d bytes saved",
270 filename.c_str(), ierr, nbyte));
271 }
272
273 fflush(fd);
274 fclose(fd);
275}
276
291void vp_readPFM(vpImage<float> &I, const std::string &filename)
292{
293 unsigned int w = 0, h = 0, maxval = 0;
294 unsigned int w_max = 100000, h_max = 100000, maxval_max = 255;
295 std::string magic("P8");
296
297 std::ifstream fd(filename.c_str(), std::ios::binary);
298
299 // Open the filename
300 if (!fd.is_open()) {
301 throw(vpImageException(vpImageException::ioError, "Cannot open file \"%s\"", filename.c_str()));
302 }
303
304 vp_decodeHeaderPNM(filename, fd, magic, w, h, maxval);
305
306 if (w > w_max || h > h_max) {
307 fd.close();
308 throw(vpException(vpException::badValue, "Bad image size in \"%s\"", filename.c_str()));
309 }
310 if (maxval > maxval_max) {
311 fd.close();
312 throw(vpImageException(vpImageException::ioError, "Bad maxval in \"%s\"", filename.c_str()));
313 }
314
315 if ((h != I.getHeight()) || (w != I.getWidth())) {
316 I.resize(h, w);
317 }
318
319 unsigned int nbyte = I.getHeight() * I.getWidth();
320 fd.read((char *)I.bitmap, sizeof(float) * nbyte);
321 if (!fd) {
322 fd.close();
323 throw(vpImageException(vpImageException::ioError, "Read only %d of %d bytes in file \"%s\"", fd.gcount(), nbyte,
324 filename.c_str()));
325 }
326
327 fd.close();
328}
329
344void vp_readPGM(vpImage<unsigned char> &I, const std::string &filename)
345{
346 unsigned int w = 0, h = 0, maxval = 0;
347 unsigned int w_max = 100000, h_max = 100000, maxval_max = 255;
348 std::string magic("P5");
349
350 std::ifstream fd(filename.c_str(), std::ios::binary);
351
352 // Open the filename
353 if (!fd.is_open()) {
354 throw(vpImageException(vpImageException::ioError, "Cannot open file \"%s\"", filename.c_str()));
355 }
356
357 vp_decodeHeaderPNM(filename, fd, magic, w, h, maxval);
358
359 if (w > w_max || h > h_max) {
360 fd.close();
361 throw(vpException(vpException::badValue, "Bad image size in \"%s\"", filename.c_str()));
362 }
363 if (maxval > maxval_max) {
364 fd.close();
365 throw(vpImageException(vpImageException::ioError, "Bad maxval in \"%s\"", filename.c_str()));
366 }
367
368 if ((h != I.getHeight()) || (w != I.getWidth())) {
369 I.resize(h, w);
370 }
371
372 unsigned int nbyte = I.getHeight() * I.getWidth();
373 fd.read((char *)I.bitmap, nbyte);
374 if (!fd) {
375 fd.close();
376 throw(vpImageException(vpImageException::ioError, "Read only %d of %d bytes in file \"%s\"", fd.gcount(), nbyte,
377 filename.c_str()));
378 }
379
380 fd.close();
381}
382
400void vp_readPGM(vpImage<vpRGBa> &I, const std::string &filename)
401{
403
404 vp_readPGM(Itmp, filename);
405
407}
408
409//--------------------------------------------------------------------------
410// PPM
411//--------------------------------------------------------------------------
412
428void vp_readPPM(vpImage<unsigned char> &I, const std::string &filename)
429{
430 vpImage<vpRGBa> Itmp;
431
432 vp_readPPM(Itmp, filename);
433
435}
436
448void vp_readPPM(vpImage<vpRGBa> &I, const std::string &filename)
449{
450 unsigned int w = 0, h = 0, maxval = 0;
451 unsigned int w_max = 100000, h_max = 100000, maxval_max = 255;
452 std::string magic("P6");
453
454 std::ifstream fd(filename.c_str(), std::ios::binary);
455
456 // Open the filename
457 if (!fd.is_open()) {
458 throw(vpImageException(vpImageException::ioError, "Cannot open file \"%s\"", filename.c_str()));
459 }
460
461 vp_decodeHeaderPNM(filename, fd, magic, w, h, maxval);
462
463 if (w > w_max || h > h_max) {
464 fd.close();
465 throw(vpException(vpException::badValue, "Bad image size in \"%s\"", filename.c_str()));
466 }
467 if (maxval > maxval_max) {
468 fd.close();
469 throw(vpImageException(vpImageException::ioError, "Bad maxval in \"%s\"", filename.c_str()));
470 }
471
472 if ((h != I.getHeight()) || (w != I.getWidth())) {
473 I.resize(h, w);
474 }
475
476 for (unsigned int i = 0; i < I.getHeight(); i++) {
477 for (unsigned int j = 0; j < I.getWidth(); j++) {
478 unsigned char rgb[3];
479 fd.read((char *)&rgb, 3);
480
481 if (!fd) {
482 fd.close();
483 throw(vpImageException(vpImageException::ioError, "Read only %d of %d bytes in file \"%s\"",
484 (i * I.getWidth() + j) * 3 + fd.gcount(), I.getSize() * 3, filename.c_str()));
485 }
486
487 I[i][j].R = rgb[0];
488 I[i][j].G = rgb[1];
489 I[i][j].B = rgb[2];
490 I[i][j].A = vpRGBa::alpha_default;
491 }
492 }
493
494 fd.close();
495}
496
505void vp_writePPM(const vpImage<unsigned char> &I, const std::string &filename)
506{
507 vpImage<vpRGBa> Itmp;
508
510
511 vp_writePPM(Itmp, filename);
512}
513
521void vp_writePPM(const vpImage<vpRGBa> &I, const std::string &filename)
522{
523 FILE *f;
524
525 // Test the filename
526 if (filename.empty()) {
527 throw(vpImageException(vpImageException::ioError, "Cannot create PPM file: filename empty"));
528 }
529
530 f = fopen(filename.c_str(), "wb");
531
532 if (f == NULL) {
533 throw(vpImageException(vpImageException::ioError, "Cannot create PPM file \"%s\"", filename.c_str()));
534 }
535
536 fprintf(f, "P6\n"); // Magic number
537 fprintf(f, "%u %u\n", I.getWidth(), I.getHeight()); // Image size
538 fprintf(f, "%d\n", 255); // Max level
539
540 for (unsigned int i = 0; i < I.getHeight(); i++) {
541 for (unsigned int j = 0; j < I.getWidth(); j++) {
542 vpRGBa v = I[i][j];
543 unsigned char rgb[3];
544 rgb[0] = v.R;
545 rgb[1] = v.G;
546 rgb[2] = v.B;
547
548 size_t res = fwrite(&rgb, 1, 3, f);
549 if (res != 3) {
550 fclose(f);
551 throw(vpImageException(vpImageException::ioError, "cannot write file \"%s\"", filename.c_str()));
552 }
553 }
554 }
555
556 fflush(f);
557 fclose(f);
558}
error that can be emited by ViSP classes.
Definition: vpException.h:72
@ badValue
Used to indicate that a value is not in the allowed range.
Definition: vpException.h:97
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
unsigned int getSize() const
Definition: vpImage.h:227
Type * bitmap
points toward the bitmap
Definition: vpImage.h:143
unsigned int getHeight() const
Definition: vpImage.h:188
static std::vector< std::string > splitChain(const std::string &chain, const std::string &sep)
Definition: vpIoTools.cpp:1900
Definition: vpRGBa.h:67
unsigned char B
Blue component.
Definition: vpRGBa.h:150
unsigned char R
Red component.
Definition: vpRGBa.h:148
unsigned char G
Green component.
Definition: vpRGBa.h:149
@ alpha_default
Definition: vpRGBa.h:69