YARP
Yet Another Robot Platform
ImageFile.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2019 Istituto Italiano di Tecnologia (IIT)
3  * Copyright (C) 2006-2010 RobotCub Consortium
4  * All rights reserved.
5  *
6  * This software may be modified and distributed under the terms of the
7  * BSD-3-Clause license. See the accompanying LICENSE file for details.
8  */
9 
10 #include <yarp/sig/ImageFile.h>
11 #include <yarp/os/Log.h>
12 #include <yarp/os/LogStream.h>
13 
14 #include <cstdio>
15 #include <cstdlib>
16 
17 #if YARP_HAS_JPEG_C
18 #include "jpeglib.h"
19 #endif
20 
21 #if defined (YARP_HAS_PNG)
22 #include <png.h>
23 #endif
24 
25 using namespace std;
26 using namespace yarp::os;
27 using namespace yarp::sig;
28 
30 // private read methods
32 
33 static bool ReadHeader(FILE *fp, int *height, int *width, int *color)
34 {
35  char ch;
36  int maxval;
37 
38  *color = 0;
39 
41  if (fscanf(fp, "P%c\n", &ch) != 1 || (ch!='6'&&ch!='5'))
42  {
43  yWarning("file is not in pgm/ppm raw format; cannot read");
44  return false;
45  }
46 
47  if (ch=='6') *color = 1;
48 
49  // skip comments
50  ch = fgetc(fp);
51  while (ch == '#')
52  {
53  do
54  {
55  ch = fgetc(fp);
56  }
57  while (ch != '\n');
58  ch = fgetc(fp);
59  }
60  ungetc(ch, fp);
61 
63  int n=fscanf(fp, "%d%d%d", width, height, &maxval);
64  if (n!=3)
65  return false;
66 
67  fgetc(fp);
68  if (maxval != 255)
69  {
70  //die("image is not true-color (24 bit); read failed");
71  yWarning("image is not true-color (24 bit); read failed");
72  return false;
73  }
74 
75  return true;
76 }
77 
78 
79 static bool ImageReadRGB(ImageOf<PixelRgb> &img, const char *filename)
80 {
81  int width, height, color, num;
82  FILE *fp=nullptr;
83  fp = fopen(filename, "rb");
84 
85  if(fp==nullptr)
86  {
87  yError("Error opening %s, check if file exists.\n", filename);
88  return false;
89  }
90 
91  if (!ReadHeader(fp, &height, &width, &color))
92  {
93  fclose (fp);
94  yError("Error reading header, is file a valid ppm/pgm?\n");
95  return false;
96  }
97 
98  if (!color)
99  {
100  ImageOf<PixelMono> tmp;
101  tmp.resize(width,height);
102 
103  const int w = tmp.width() * tmp.getPixelSize();
104  const int h = tmp.height();
105  const int pad = tmp.getRowSize();
106  unsigned char *dst = tmp.getRawImage ();
107 
108  num = 0;
109  for (int i = 0; i < h; i++)
110  {
111  num += (int)fread((void *) dst, 1, (size_t) w, fp);
112  dst += pad;
113  }
114  fclose(fp);
115  img.copy(tmp);
116  return true;
117  }
118 
119  img.resize(width,height);
120 
121  const int w = img.width() * img.getPixelSize();
122  const int h = img.height();
123  const int pad = img.getRowSize();
124  unsigned char *dst = img.getRawImage ();
125 
126  num = 0;
127  for (int i = 0; i < h; i++)
128  {
129  num += (int)fread((void *) dst, 1, (size_t) w, fp);
130  dst += pad;
131  }
132 
133  fclose(fp);
134 
135  return true;
136 }
137 
138 static bool ImageReadFloat(ImageOf<PixelFloat>& dest, const std::string& filename)
139 {
140  FILE *fp = fopen(filename.c_str(), "rb");
141  if (fp == nullptr) {
142  return false;
143  }
144 
145  size_t br = 0;
146  size_t size_ = sizeof(float);
147  size_t count_ = 0;
148 
149  size_t dims[2];
150  if (fread(dims, sizeof(dims), 1, fp) > 0)
151  {
152  count_ = (size_t)(dims[0] * dims[1]);
153  dest.resize(dims[0], dims[1]);
154  br = fread(&dest(0, 0), size_, count_, fp);
155  }
156 
157  fclose(fp);
158  return (br > 0);
159 }
160 
161 static bool ImageReadBGR(ImageOf<PixelBgr> &img, const char *filename)
162 {
163  int width, height, color, num;
164  FILE *fp=nullptr;
165  fp = fopen(filename, "rb");
166 
167  if(fp==nullptr)
168  {
169  yError("Error opening %s, check if file exists.\n", filename);
170  return false;
171  }
172 
173  if (!ReadHeader(fp, &height, &width, &color))
174  {
175  fclose (fp);
176  yError("Error reading header, is file a valid ppm/pgm?\n");
177  return false;
178  }
179 
180  if (!color)
181  {
182  fclose(fp);
183  yError("File is grayscale, conversion not yet supported\n");
184  return false;
185  }
186 
187  ImageOf<PixelRgb> tmpImg;
188  tmpImg.resize(width, height);
189 
190  const int w = tmpImg.width() * img.getPixelSize();
191  const int h = tmpImg.height();
192  const int pad = tmpImg.getRowSize();
193  unsigned char *dst = tmpImg.getRawImage ();
194 
195  num = 0;
196  for (int i = 0; i < h; i++)
197  {
198  num += (int)fread((void *) dst, 1, (size_t) w, fp);
199  dst += pad;
200  }
201 
202  fclose(fp);
203 
204  return img.copy(tmpImg);
205 }
206 
207 
208 static bool ImageReadMono(ImageOf<PixelMono> &img, const char *filename)
209 {
210  int width, height, color, num;
211  FILE *fp=nullptr;
212  fp = fopen(filename, "rb");
213 
214  if(fp==nullptr)
215  {
216  yError("Error opening %s, check if file exists.\n", filename);
217  return false;
218  }
219 
220  if (!ReadHeader(fp, &height, &width, &color))
221  {
222  fclose (fp);
223  yError("Error reading header, is file a valid ppm/pgm?\n");
224  return false;
225  }
226 
227  if (color)
228  {
229  fclose(fp);
230  yError("File is color, conversion not yet supported\n");
231  return false;
232  }
233 
234  img.resize(width,height);
235 
236  const int w = img.width() * img.getPixelSize();
237  const int h = img.height();
238  const int pad = img.getRowSize();
239  unsigned char *dst = img.getRawImage ();
240 
241  num = 0;
242  for (int i = 0; i < h; i++)
243  {
244  num += (int)fread((void *) dst, 1, (size_t) w, fp);
245  dst += pad;
246  }
247 
248  fclose(fp);
249 
250  return true;
251 }
252 
254 // private write methods
256 
257 #if defined (YARP_HAS_PNG)
258 static bool SavePNG(char *src, const char *filename, size_t h, size_t w, size_t rowSize, png_byte color_type, png_byte bit_depth)
259 {
260  // create file
261  if (src == nullptr)
262  {
263  yError("[write_png_file] Cannot write to file a nullptr image");
264  return false;
265  }
266 
267  if (filename == nullptr)
268  {
269  yError("[write_png_file] Filename is nullptr");
270  return false;
271  }
272 
273  FILE *fp = fopen(filename, "wb");
274  if (!fp)
275  {
276  yError("[write_png_file] File %s could not be opened for writing", filename);
277  return false;
278  }
279 
280  // initialize stuff
281  png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
282  if (!png_ptr)
283  {
284  yError("[write_png_file] png_create_write_struct failed");
285  fclose(fp);
286  return false;
287  }
288 
289  png_infop info_ptr = png_create_info_struct(png_ptr);
290  if (!info_ptr)
291  {
292  yError("[write_png_file] png_create_info_struct failed");
293  fclose(fp);
294  return false;
295  }
296 
297  png_bytep * row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * h);
298  for (size_t y = 0; y < h; y++)
299  {
300  row_pointers[y] = (png_bytep)(src)+y*w;
301  }
302 
303  if (setjmp(png_jmpbuf(png_ptr)))
304  {
305  yError("[write_png_file] Error during init_io");
306  free(row_pointers);
307  fclose(fp);
308  return false;
309  }
310  png_init_io(png_ptr, fp);
311 
312 
313  // write header
314  if (setjmp(png_jmpbuf(png_ptr)))
315  {
316  yError("[write_png_file] Error during writing header");
317  free(row_pointers);
318  return false;
319  }
320  png_set_IHDR(png_ptr, info_ptr, w, h,
321  bit_depth, color_type, PNG_INTERLACE_NONE,
322  PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
323 
324  png_write_info(png_ptr, info_ptr);
325 
326 
327  // write bytes
328  if (setjmp(png_jmpbuf(png_ptr)))
329  {
330  yError("[write_png_file] Error during writing bytes");
331  free(row_pointers);
332  fclose(fp);
333  return false;
334  }
335  png_write_image(png_ptr, row_pointers);
336 
337 
338  // end write
339  if (setjmp(png_jmpbuf(png_ptr)))
340  {
341  yError("[write_png_file] Error during end of write");
342  free(row_pointers);
343  fclose(fp);
344  return false;
345  }
346  png_write_end(png_ptr, NULL);
347 
348  // cleanup heap allocation
349  free(row_pointers);
350 
351  fclose(fp);
352  return true;
353 }
354 #endif
355 
356 static bool SaveJPG(char *src, const char *filename, int h, int w, int rowSize)
357 {
358 #if YARP_HAS_JPEG_C
359  int quality = 100;
360  struct jpeg_compress_struct cinfo;
361  struct jpeg_error_mgr jerr;
362  FILE * outfile;
363  JSAMPROW row_pointer[1];
364  int row_stride;
365 
366  cinfo.err = jpeg_std_error(&jerr);
367  jpeg_create_compress(&cinfo);
368 
369  if ((outfile = fopen(filename, "wb")) == nullptr)
370  {
371  yError("can't write file: %s\n", filename);
372  return false;
373  }
374  jpeg_stdio_dest(&cinfo, outfile);
375 
376  cinfo.image_width = w;
377  cinfo.image_height = h;
378  cinfo.input_components = 3;
379  cinfo.in_color_space = JCS_RGB;
380  jpeg_set_defaults(&cinfo);
381  jpeg_set_quality(&cinfo, quality, TRUE);
382 
383  jpeg_start_compress(&cinfo, TRUE);
384 
385  row_stride = w * 3;
386 
387  while (cinfo.next_scanline < cinfo.image_height)
388  {
389  row_pointer[0] = (JSAMPROW)&src[cinfo.next_scanline * row_stride];
390  (void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
391  }
392 
393  jpeg_finish_compress(&cinfo);
394  fclose(outfile);
395  jpeg_destroy_compress(&cinfo);
396  return true;
397 #else
398  yError() << "libjpeg not installed";
399  return false;
400 #endif
401 }
402 
403 static bool SavePGM(char *src, const char *filename, int h, int w, int rowSize)
404 {
405  FILE *fp = fopen(filename, "wb");
406  if (!fp)
407  {
408  yError("cannot open file %s for writing\n", filename);
409  return false;
410  }
411  else
412  {
413  const int inc = rowSize;
414 
415  fprintf(fp, "P5\n%d %d\n%d\n", w, h, 255);
416  for (int i = 0; i < h; i++)
417  {
418  fwrite((void *)src, 1, (size_t)w, fp);
419  src += inc;
420  }
421 
422  fclose(fp);
423  }
424 
425  return true;
426 }
427 
428 
429 static bool SavePPM(char *src, const char *filename, int h, int w, int rowSize)
430 {
431  FILE *fp = fopen(filename, "wb");
432  if (!fp)
433  {
434  yError("cannot open file %s for writing\n", filename);
435  return false;
436  }
437  else
438  {
439  const int inc = rowSize;//YARPSimpleOperation::ComputePadding (w*3, YarpImageAlign) + w * 3;
440 
441  fprintf(fp, "P6\n%d %d\n%d\n", w, h, 255);
442  for (int i = 0; i < h; i++)
443  {
444  fwrite((void *)src, 1, (size_t)(w * 3), fp);
445  src += inc;
446  }
447 
449  fclose(fp);
450  }
451 
452  return true;
453 }
454 
455 static bool ImageWriteJPG(ImageOf<PixelRgb>& img, const char *filename)
456 {
457  return SaveJPG((char*)img.getRawImage(), filename, img.height(), img.width(), img.getRowSize());
458 }
459 
460 static bool ImageWritePNG(ImageOf<PixelRgb>& img, const char *filename)
461 {
462 #if defined (YARP_HAS_PNG)
463  return SavePNG((char*)img.getRawImage(), filename, img.height(), img.width(), img.getRowSize(), PNG_COLOR_TYPE_RGB, 24);
464 #else
465  yError() << "YARP was not built with png support";
466  return false;
467 #endif
468 }
469 
470 static bool ImageWritePNG(ImageOf<PixelMono>& img, const char *filename)
471 {
472 #if defined (YARP_HAS_PNG)
473  return SavePNG((char*)img.getRawImage(), filename, img.height(), img.width(), img.getRowSize(), PNG_COLOR_TYPE_GRAY, 8);
474 #else
475  yError() << "YARP was not built with png support";
476  return false;
477 #endif
478 }
479 
480 static bool ImageWriteRGB(ImageOf<PixelRgb>& img, const char *filename)
481 {
482  return SavePPM((char*)img.getRawImage(),filename,img.height(),img.width(),img.getRowSize());
483 }
484 
485 static bool ImageWriteMono(ImageOf<PixelMono>& img, const char *filename)
486 {
487  return SavePGM((char*)img.getRawImage(), filename, img.height(), img.width(), img.getRowSize());
488 }
489 
490 static bool ImageWriteFloat(ImageOf<PixelFloat>& img, const char *filename)
491 {
492  FILE *fp = fopen(filename, "wb");
493  if (fp == nullptr)
494  {
495  return false;
496  }
497 
498  size_t dims[2] = { img.width(), img.height() };
499 
500  size_t bw = 0;
501  size_t size_ = sizeof(float);
502  auto count_ = (size_t)(dims[0] * dims[1]);
503 
504  if (fwrite(dims, sizeof(dims), 1, fp) > 0) {
505  bw = fwrite(&img(0, 0), size_, count_, fp);
506  }
507 
508  fclose(fp);
509  return (bw > 0);
510 }
511 
513 // public read methods
515 
516 bool file::read(ImageOf<PixelRgb> & dest, const std::string& src, image_fileformat format)
517 {
518  return ImageReadRGB(dest,src.c_str());
519 }
520 
521 
522 bool file::read(ImageOf<PixelBgr> & dest, const std::string& src, image_fileformat format)
523 {
524  return ImageReadBGR(dest,src.c_str());
525 }
526 
527 
528 bool file::read(ImageOf<PixelRgba> & dest, const std::string& src, image_fileformat format)
529 {
530  ImageOf<PixelRgb> img2;
531  bool ok = ImageReadRGB(img2,src.c_str());
532  if (ok)
533  {
534  dest.copy(img2);
535  }
536  return ok;
537 }
538 
539 bool file::read(ImageOf<PixelMono> & dest, const std::string& src, image_fileformat format)
540 {
541  return ImageReadMono(dest, src.c_str());
542 }
543 
544 bool file::read(ImageOf<PixelFloat>& dest, const std::string& src, image_fileformat format)
545 {
546  return ImageReadFloat(dest, src);
547 }
548 
552 
553 bool file::write(const ImageOf<PixelRgb> & src, const std::string& dest, image_fileformat format)
554 {
555  if (format == FORMAT_PPM)
556  {
557  return ImageWriteRGB(const_cast<ImageOf<PixelRgb> &>(src), dest.c_str());
558  }
559  else if (format == FORMAT_JPG)
560  {
561  return ImageWriteJPG(const_cast<ImageOf<PixelRgb> &>(src), dest.c_str());
562  }
563  else if (format == FORMAT_PNG)
564  {
565  return ImageWritePNG(const_cast<ImageOf<PixelRgb> &>(src), dest.c_str());
566  }
567  else
568  {
569  yError() << "Invalid format, operation not supported";
570  return false;
571  }
572 }
573 
574 bool file::write(const ImageOf<PixelBgr> & src, const std::string& dest, image_fileformat format)
575 {
576  ImageOf<PixelRgb> imgRGB;
577  imgRGB.copy(src);
578  if (format == FORMAT_PPM)
579  {
580  return ImageWriteRGB(const_cast<ImageOf<PixelRgb> &>(imgRGB), dest.c_str());
581  }
582  else if (format == FORMAT_JPG)
583  {
584  return ImageWriteJPG(const_cast<ImageOf<PixelRgb> &>(imgRGB), dest.c_str());
585  }
586  else if (format == FORMAT_PNG)
587  {
588  return ImageWritePNG(const_cast<ImageOf<PixelRgb> &>(imgRGB), dest.c_str());
589  }
590  else
591  {
592  yError() << "Invalid format, operation not supported";
593  return false;
594  }
595 }
596 
597 
598 bool file::write(const ImageOf<PixelRgba> & src, const std::string& dest, image_fileformat format)
599 {
600  ImageOf<PixelRgb> imgRGB;
601  imgRGB.copy(src);
602  if (format == FORMAT_PPM)
603  {
604  return ImageWriteRGB(const_cast<ImageOf<PixelRgb> &>(imgRGB), dest.c_str());
605  }
606  else if (format == FORMAT_JPG)
607  {
608  return ImageWriteJPG(const_cast<ImageOf<PixelRgb> &>(imgRGB), dest.c_str());
609  }
610  else if (format == FORMAT_PNG)
611  {
612  return ImageWritePNG(const_cast<ImageOf<PixelRgb> &>(imgRGB), dest.c_str());
613  }
614  else
615  {
616  yError() << "Invalid format, operation not supported";
617  return false;
618  }
619 }
620 
621 
622 bool file::write(const ImageOf<PixelMono> & src, const std::string& dest, image_fileformat format)
623 {
624  if (format == FORMAT_PGM)
625  {
626  return ImageWriteMono(const_cast<ImageOf<PixelMono> &>(src), dest.c_str());
627  }
628  else if (format == FORMAT_PNG)
629  {
630  return ImageWritePNG(const_cast<ImageOf<PixelMono> &>(src), dest.c_str());
631  }
632  else
633  {
634  yError() << "Invalid format, operation not supported";
635  return false;
636  }
637 }
638 
639 bool file::write(const ImageOf<PixelFloat>& src, const std::string& dest, image_fileformat format)
640 {
641  if (format == FORMAT_NUMERIC)
642  {
643  return ImageWriteFloat(const_cast<ImageOf<PixelFloat> &>(src), dest.c_str());
644  }
645  else
646  {
647  yError() << "Invalid format, operation not supported";
648  return false;
649  }
650 }
651 
652 bool file::write(const Image& src, const std::string& dest, image_fileformat format)
653 {
654  int code=src.getPixelCode();
655  if (code == VOCAB_PIXEL_MONO)
656  {
657  return write(static_cast<const ImageOf<PixelMono>&>(src), dest, format);
658  }
659  else if (code == VOCAB_PIXEL_MONO_FLOAT)
660  {
661  return write(static_cast<const ImageOf<PixelFloat>&>(src), dest, format);
662  }
663  else if (code == VOCAB_PIXEL_BGR)
664  {
665  return write(static_cast<const ImageOf<PixelBgr>&>(src), dest, format);
666  }
667  else if (code == VOCAB_PIXEL_RGB)
668  {
669  return write(static_cast<const ImageOf<PixelRgb>&>(src), dest, format);
670  }
671  else if (code == VOCAB_PIXEL_RGBA)
672  {
673  return write(static_cast<const ImageOf<PixelRgba>&>(src), dest, format);
674  }
675  else
676  {
677  ImageOf<PixelRgb> img;
678  img.copy(src);
679  return write(img,dest);
680  }
681 }
682 
683 
bool write(const ImageOf< PixelRgb > &src, const std::string &dest, image_fileformat format=FORMAT_PPM)
Definition: ImageFile.cpp:553
unsigned char * getRawImage() const
Access to the internal image buffer.
Definition: Image.cpp:527
static bool ImageWriteFloat(ImageOf< PixelFloat > &img, const char *filename)
Definition: ImageFile.cpp:490
static bool ImageWritePNG(ImageOf< PixelRgb > &img, const char *filename)
Definition: ImageFile.cpp:460
bool read(ImageOf< PixelRgb > &dest, const std::string &src, image_fileformat format=FORMAT_ANY)
Definition: ImageFile.cpp:516
bool copy(const Image &alt)
Copy operator.
Definition: Image.cpp:829
static bool ImageReadRGB(ImageOf< PixelRgb > &img, const char *filename)
Definition: ImageFile.cpp:79
static bool ImageReadFloat(ImageOf< PixelFloat > &dest, const std::string &filename)
Definition: ImageFile.cpp:138
size_t getRowSize() const
Size of the underlying image buffer rows.
Definition: Image.h:179
STL namespace.
static bool SavePGM(char *src, const char *filename, int h, int w, int rowSize)
Definition: ImageFile.cpp:403
static bool ReadHeader(FILE *fp, int *height, int *width, int *color)
Definition: ImageFile.cpp:33
size_t width() const
Gets width of image in pixels.
Definition: Image.h:153
size_t getPixelSize() const override
Gets pixel size in memory in bytes.
Definition: Image.h:595
Base class for storing images.
Definition: Image.h:85
void resize(size_t imgWidth, size_t imgHeight)
Reallocate an image to be of a desired size, throwing away its current contents.
Definition: Image.cpp:463
static bool ImageReadBGR(ImageOf< PixelBgr > &img, const char *filename)
Definition: ImageFile.cpp:161
static bool SavePPM(char *src, const char *filename, int h, int w, int rowSize)
Definition: ImageFile.cpp:429
static bool SaveJPG(char *src, const char *filename, int h, int w, int rowSize)
Definition: ImageFile.cpp:356
#define yWarning
Definition: Log.h:108
#define yError
Definition: Log.h:109
size_t height() const
Gets height of image in pixels.
Definition: Image.h:159
static bool ImageWriteRGB(ImageOf< PixelRgb > &img, const char *filename)
Definition: ImageFile.cpp:480
static bool ImageWriteMono(ImageOf< PixelMono > &img, const char *filename)
Definition: ImageFile.cpp:485
An interface to the operating system, including Port based communication.
static bool ImageReadMono(ImageOf< PixelMono > &img, const char *filename)
Definition: ImageFile.cpp:208
Signal processing.
Definition: Image.h:25
static bool ImageWriteJPG(ImageOf< PixelRgb > &img, const char *filename)
Definition: ImageFile.cpp:455
virtual int getPixelCode() const
Gets pixel type identifier.
Definition: Image.cpp:451