Visual Servoing Platform  version 3.5.0 under development (2022-02-15)
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 
46 void 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
50 
59 void 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 
128 void 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 
174 void 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 
216 void 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 
238 void 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 
264  vpImageConvert::convert(I, Itmp);
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 
291 void 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 
344 void 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 
400 void vp_readPGM(vpImage<vpRGBa> &I, const std::string &filename)
401 {
403 
404  vp_readPGM(Itmp, filename);
405 
406  vpImageConvert::convert(Itmp, I);
407 }
408 
409 //--------------------------------------------------------------------------
410 // PPM
411 //--------------------------------------------------------------------------
412 
428 void vp_readPPM(vpImage<unsigned char> &I, const std::string &filename)
429 {
430  vpImage<vpRGBa> Itmp;
431 
432  vp_readPPM(Itmp, filename);
433 
434  vpImageConvert::convert(Itmp, I);
435 }
436 
448 void 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 
505 void vp_writePPM(const vpImage<unsigned char> &I, const std::string &filename)
506 {
507  vpImage<vpRGBa> Itmp;
508 
509  vpImageConvert::convert(I, Itmp);
510 
511  vp_writePPM(Itmp, filename);
512 }
513 
521 void 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 }
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)
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:800
unsigned char B
Blue component.
Definition: vpRGBa.h:150
Type * bitmap
points toward the bitmap
Definition: vpImage.h:143
error that can be emited by ViSP classes.
Definition: vpException.h:71
Error that can be emited by the vpImage class and its derivates.
unsigned char G
Green component.
Definition: vpRGBa.h:149
Definition: vpRGBa.h:66
static std::vector< std::string > splitChain(const std::string &chain, const std::string &sep)
Definition: vpIoTools.cpp:1900
unsigned int getHeight() const
Definition: vpImage.h:188
unsigned int getSize() const
Definition: vpImage.h:227
unsigned char R
Red component.
Definition: vpRGBa.h:148
unsigned int getWidth() const
Definition: vpImage.h:246