YARP
Yet Another Robot Platform
ImageFile.cpp
Go to the documentation of this file.
1 /*
2  * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3  * SPDX-FileCopyrightText: 2006-2010 RobotCub Consortium
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <yarp/sig/ImageFile.h>
8 #include <yarp/os/LogComponent.h>
9 #include <yarp/os/LogStream.h>
10 
11 #include <cstdio>
12 #include <cstring>
13 #include <cstdlib>
14 
15 #if defined (YARP_HAS_JPEG)
16 #include "jpeglib.h"
17 #endif
18 
19 #if defined (YARP_HAS_PNG)
20 #include <png.h>
21 #endif
22 
23 #if defined (YARP_HAS_ZLIB)
24 #include <zlib.h>
25 #endif
26 
27 using namespace yarp::os;
28 using namespace yarp::sig;
29 
30 namespace
31 {
32  YARP_LOG_COMPONENT(IMAGEFILE, "yarp.sig.ImageFile")
33 }
34 
35 namespace
36 {
37  bool ImageReadRGB_JPG(ImageOf<PixelRgb>& img, const char* filename);
38  bool ImageReadBGR_JPG(ImageOf<PixelBgr>& img, const char* filename);
39  bool ImageReadMono_JPG(ImageOf<PixelMono>& img, const char* filename);
40 
41  bool ImageReadRGB_PNG(ImageOf<PixelRgb>& img, const char* filename);
42  bool ImageReadBGR_PNG(ImageOf<PixelBgr>& img, const char* filename);
43  bool ImageReadMono_PNG(ImageOf<PixelMono>& img, const char* filename);
44 
45  bool ReadHeader_PxM(FILE* fp, int* height, int* width, int* color);
46  bool ImageReadMono_PxM(ImageOf<PixelMono>& img, const char* filename);
47  bool ImageReadRGB_PxM(ImageOf<PixelRgb>& img, const char* filename);
48  bool ImageReadBGR_PxM(ImageOf<PixelBgr>& img, const char* filename);
49 
50  bool ImageReadFloat_PlainHeaderless(ImageOf<PixelFloat>& dest, const std::string& filename);
51 #if defined (YARP_HAS_ZLIB)
52  bool ImageReadFloat_CompressedHeaderless(ImageOf<PixelFloat>& dest, const std::string& filename);
53 #endif
54 
55  bool SaveJPG(char* src, const char* filename, size_t h, size_t w, size_t rowSize);
56  bool SavePGM(char* src, const char* filename, size_t h, size_t w, size_t rowSize);
57  bool SavePPM(char* src, const char* filename, size_t h, size_t w, size_t rowSize);
58 #if defined (YARP_HAS_PNG)
59  bool SavePNG(char* src, const char* filename, size_t h, size_t w, size_t rowSize, png_byte color_type, png_byte bit_depth);
60 #endif
61  bool SaveFloatRaw(char* src, const char* filename, size_t h, size_t w, size_t rowSize);
62 #if defined (YARP_HAS_ZLIB)
63  bool SaveFloatCompressed(char* src, const char* filename, size_t h, size_t w, size_t rowSize);
64 #endif
65 
66  bool ImageWriteJPG(ImageOf<PixelRgb>& img, const char* filename);
67  bool ImageWritePNG(ImageOf<PixelRgb>& img, const char* filename);
68  bool ImageWritePNG(ImageOf<PixelMono>& img, const char* filename);
69  bool ImageWriteRGB(ImageOf<PixelRgb>& img, const char* filename);
70  bool ImageWriteMono(ImageOf<PixelMono>& img, const char* filename);
71 
72  bool ImageWriteFloat_PlainHeaderless(ImageOf<PixelFloat>& img, const char* filename);
73  bool ImageWriteFloat_CompressedHeaderless(ImageOf<PixelFloat>& img, const char* filename);
74 };
75 
77 // private read methods for JPG Files
79 namespace {
80 bool ImageReadRGB_JPG(ImageOf<PixelRgb>& img, const char* filename)
81 {
82 #if defined (YARP_HAS_JPEG)
83 
84  struct jpeg_decompress_struct cinfo;
85  struct jpeg_error_mgr jerr;
86  jpeg_create_decompress(&cinfo);
87  cinfo.err = jpeg_std_error(&jerr);
88 
89  FILE* fp = fopen(filename, "rb");
90  if (fp == NULL)
91  {
92  yCError(IMAGEFILE) << "Error: failed to open" << filename;
93  return false;
94  }
95 
96  jpeg_stdio_src(&cinfo, fp);
97  jpeg_read_header(&cinfo, TRUE);
98  jpeg_start_decompress(&cinfo);
99 
100  uint32_t j_width = cinfo.image_width;
101  uint32_t j_height = cinfo.image_height;
102  uint32_t j_ch = cinfo.num_components;
103 
104  uint8_t* j_data = NULL;
105  j_data = (uint8_t*)malloc(sizeof(uint8_t) * j_width * j_height * j_ch);
106 
107  //read line by line
108  uint8_t* j_row = j_data;
109  const uint32_t j_stride = j_width * j_ch;
110  for (size_t y = 0; y < j_height; y++)
111  {
112  jpeg_read_scanlines(&cinfo, &j_row, 1);
113  j_row += j_stride;
114  }
115 
116  jpeg_finish_decompress(&cinfo);
117  jpeg_destroy_decompress(&cinfo);
118  fclose(fp);
119 
120  img.resize(j_width, j_height);
121  for (size_t y = 0; y < j_height; y++)
122  {
123  for (size_t x = 0; x < j_width; x++)
124  {
125  unsigned char* address = img.getPixelAddress(x, y);
126  address[0] = j_data[y * j_width * j_ch + x * j_ch + 0];
127  address[1] = j_data[y * j_width * j_ch + x * j_ch + 1];
128  address[2] = j_data[y * j_width * j_ch + x * j_ch + 2];
129  }
130  }
131 
132  free(j_data);
133  j_data = nullptr;
134 
135  return true;
136 #else
137  yCError(IMAGEFILE) << "JPG library not available/not found";
138  return false;
139 #endif
140 }
141 
142 bool ImageReadBGR_JPG(ImageOf<PixelBgr>& img, const char* filename)
143 {
144 #if defined (YARP_HAS_JPEG)
145  yCError(IMAGEFILE) << "Not yet implemented";
146  return false;
147 #else
148  yCError(IMAGEFILE) << "JPG library not available/not found";
149  return false;
150 #endif
151 }
152 
153 bool ImageReadMono_JPG(ImageOf<PixelMono>& img, const char* filename)
154 {
155 #if defined (YARP_HAS_JPEG)
156  yCError(IMAGEFILE) << "Not yet implemented";
157  return false;
158 #else
159  yCError(IMAGEFILE) << "JPG library not available/not found";
160  return false;
161 #endif
162 }
163 }
164 
166 // private read methods for PNG Files
168 namespace {
169 bool ImageReadRGB_PNG(ImageOf<PixelRgb>& img, const char* filename)
170 {
171 #if defined (YARP_HAS_PNG)
172  FILE* fp = fopen(filename, "rb");
173 
174  png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
175  if (!png)
176  {
177  yCError(IMAGEFILE) << "PNG internal error";
178  return false;
179  }
180 
181  png_infop info = png_create_info_struct(png);
182  if (!info)
183  {
184  yCError(IMAGEFILE) << "PNG internal error";
185  return false;
186  }
187 
188  if (setjmp(png_jmpbuf(png)))
189  {
190  yCError(IMAGEFILE) << "PNG internal error";
191  return false;
192  }
193 
194  png_init_io(png, fp);
195 
196  png_read_info(png, info);
197 
198  int width = png_get_image_width(png, info);
199  int height = png_get_image_height(png, info);
200  png_byte color_type = png_get_color_type(png, info);
201  png_byte bit_depth = png_get_bit_depth(png, info);
202 
203  // Read any color_type into 8bit depth, RGBA format.
204  // See http://www.libpng.org/pub/png/libpng-manual.txt
205 
206  if (bit_depth == 16) {
207  png_set_strip_16(png);
208  }
209 
210  if (color_type == PNG_COLOR_TYPE_PALETTE) {
211  png_set_palette_to_rgb(png);
212  }
213 
214  // PNG_COLOR_TYPE_GRAY_ALPHA is always 8 or 16bit depth.
215  if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
216  png_set_expand_gray_1_2_4_to_8(png);
217  }
218 
219  if (png_get_valid(png, info, PNG_INFO_tRNS)) {
220  png_set_tRNS_to_alpha(png);
221  }
222 
223  // These color_type don't have an alpha channel then fill it with 0xff.
224  if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_PALETTE) {
225  png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
226  }
227 
228  if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
229  png_set_gray_to_rgb(png);
230  }
231 
232  png_read_update_info(png, info);
233 
234  png_bytep* row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height);
235  for (int y = 0; y < height; y++)
236  {
237  row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png, info));
238  }
239 
240  png_read_image(png, row_pointers);
241  fclose(fp);
242 
243  img.resize(width,height);
244  for (int y = 0; y < height; y++)
245  {
246  png_bytep row = row_pointers[y];
247  for (int x = 0; x < width; x++)
248  {
249  png_bytep px = &(row[x * 4]);
250  unsigned char* address = img.getPixelAddress(x,y);
251  address[0] = px[0];
252  address[1] = px[1];
253  address[2] = px[2];
254  }
255  }
256 
257  png_destroy_read_struct(&png, &info, NULL);
258  for (int y = 0; y < height; y++)
259  {
260  free(row_pointers[y]);
261  }
262  free(row_pointers);
263  return true;
264 #else
265  yCError(IMAGEFILE) << "PNG library not available/not found";
266  return false;
267 #endif
268 }
269 
270 bool ImageReadBGR_PNG(ImageOf<PixelBgr>& img, const char* filename)
271 {
272 #if defined (YARP_HAS_PNG)
273  yCError(IMAGEFILE) << "Not yet implemented";
274  return false;
275 #else
276  yCError(IMAGEFILE) << "PNG library not available/not found";
277  return false;
278 #endif
279 }
280 
281 bool ImageReadMono_PNG(ImageOf<PixelMono>& img, const char* filename)
282 {
283 #if defined (YARP_HAS_PNG)
284  yCError(IMAGEFILE) << "Not yet implemented";
285  return false;
286 #else
287  yCError(IMAGEFILE) << "PNG library not available/not found";
288  return false;
289 #endif
290 }
291 
293 // private read methods for PGM/PPM Files
295 
296 bool ReadHeader_PxM(FILE *fp, int *height, int *width, int *color)
297 {
298  char ch;
299  int maxval;
300 
301  *color = 0;
302 
304  if (fscanf(fp, "P%c\n", &ch) != 1 || (ch!='6'&&ch!='5'))
305  {
306  yCWarning(IMAGEFILE, "file is not in pgm/ppm raw format; cannot read");
307  return false;
308  }
309 
310  if (ch == '6') {
311  *color = 1;
312  }
313 
314  // skip comments
315  ch = fgetc(fp);
316  while (ch == '#')
317  {
318  do
319  {
320  ch = fgetc(fp);
321  }
322  while (ch != '\n');
323  ch = fgetc(fp);
324  }
325  ungetc(ch, fp);
326 
328  int n=fscanf(fp, "%d%d%d", width, height, &maxval);
329  if (n != 3) {
330  return false;
331  }
332 
333  fgetc(fp);
334  if (maxval != 255)
335  {
336  //die("image is not true-color (24 bit); read failed");
337  yCWarning(IMAGEFILE, "image is not true-color (24 bit); read failed");
338  return false;
339  }
340 
341  return true;
342 }
343 
344 
345 bool ImageReadRGB_PxM(ImageOf<PixelRgb> &img, const char *filename)
346 {
347  int width, height, color, num;
348  FILE *fp=nullptr;
349  fp = fopen(filename, "rb");
350 
351  if(fp==nullptr)
352  {
353  yCError(IMAGEFILE, "Error opening %s, check if file exists.\n", filename);
354  return false;
355  }
356 
357  if (!ReadHeader_PxM(fp, &height, &width, &color))
358  {
359  fclose (fp);
360  yCError(IMAGEFILE, "Error reading header, is file a valid ppm/pgm?\n");
361  return false;
362  }
363 
364  if (!color)
365  {
366  ImageOf<PixelMono> tmp;
367  tmp.resize(width,height);
368 
369  const int w = tmp.width() * tmp.getPixelSize();
370  const int h = tmp.height();
371  const int pad = tmp.getRowSize();
372  unsigned char *dst = tmp.getRawImage ();
373 
374  num = 0;
375  for (int i = 0; i < h; i++)
376  {
377  num += (int)fread((void *) dst, 1, (size_t) w, fp);
378  dst += pad;
379  }
380  fclose(fp);
381  img.copy(tmp);
382  return true;
383  }
384 
385  img.resize(width,height);
386 
387  const int w = img.width() * img.getPixelSize();
388  const int h = img.height();
389  const int pad = img.getRowSize();
390  unsigned char *dst = img.getRawImage ();
391 
392  num = 0;
393  for (int i = 0; i < h; i++)
394  {
395  num += (int)fread((void *) dst, 1, (size_t) w, fp);
396  dst += pad;
397  }
398 
399  fclose(fp);
400 
401  return true;
402 }
403 
404 #if defined (YARP_HAS_ZLIB)
405 bool ImageReadFloat_CompressedHeaderless(ImageOf<PixelFloat>& dest, const std::string& filename)
406 {
407  FILE* fp = fopen(filename.c_str(), "rb");
408  if (fp == nullptr) {
409  return false;
410  }
411 
412  size_t br = 0;
413 
414  //get the file size
415  fseek(fp, 0, SEEK_END);
416  size_t sizeDataCompressed = ftell(fp);
417  rewind(fp);
418 
419  //read the compressed data
420  char* dataReadInCompressed = new char[sizeDataCompressed];
421  br = fread(dataReadInCompressed, 1, sizeDataCompressed, fp);
422  fclose(fp);
423 
424  if (br != sizeDataCompressed) { yError() << "problems reading file!"; delete [] dataReadInCompressed; return false; }
425 
426  size_t h = ((size_t*)(dataReadInCompressed))[0]; //byte 0
427  size_t w = ((size_t*)(dataReadInCompressed))[1]; //byte 8, because size_t is 8 bytes long
428  size_t hds = 2* sizeof(size_t); //16 bytes
429 
430  dest.resize(w, h);
431  unsigned char* destbuff = dest.getRawImage();
432  //this is the size of the image
433  size_t sizeDataUncompressed = dest.getRawImageSize();
434  //this is the size of the buffer. Extra space is required for temporary operations (I choose arbitrarily *2)
435  size_t sizeDataUncompressedExtra = sizeDataUncompressed*2;
436 
437  char* dataUncompressed = new char[sizeDataUncompressedExtra];
438 
439  int z_result = uncompress((Bytef*) dataUncompressed, (uLongf*)&sizeDataUncompressedExtra, (const Bytef*)dataReadInCompressed+ hds, sizeDataCompressed- hds);
440  switch (z_result)
441  {
442  case Z_OK:
443  break;
444 
445  case Z_MEM_ERROR:
446  yCError(IMAGEFILE, "zlib compression: out of memory");
447  delete[] dataUncompressed;
448  return false;
449  break;
450 
451  case Z_BUF_ERROR:
452  yCError(IMAGEFILE, "zlib compression: output buffer wasn't large enough");
453  delete[] dataUncompressed;
454  return false;
455  break;
456 
457  case Z_DATA_ERROR:
458  yCError(IMAGEFILE, "zlib compression: file contains corrupted data");
459  delete[] dataUncompressed;
460  return false;
461  break;
462  }
463 
464  //here I am copy only the size of the image, obviously the extra space is not needed anymore.
465  for (size_t i=0; i< sizeDataUncompressed; i++)
466  {
467  destbuff[i] = dataUncompressed[i];
468  }
469 
470  delete [] dataUncompressed;
471  return true;
472 }
473 #endif
474 
475 bool ImageReadFloat_PlainHeaderless(ImageOf<PixelFloat>& dest, const std::string& filename)
476 {
477  FILE *fp = fopen(filename.c_str(), "rb");
478  if (fp == nullptr) {
479  return false;
480  }
481 
482  size_t dims[2];
483  if (fread(dims, sizeof(dims), 1, fp) == 0)
484  {
485  fclose(fp);
486  return false;
487  }
488 
489  size_t h = dims[0];
490  size_t w = dims[1];
491  dest.resize(w, h);
492  size_t pad = dest.getRowSize();
493  size_t bytes_to_read_per_row = w* dest.getPixelSize();
494  unsigned char* dst = dest.getRawImage();
495  size_t num = 0;
496  for (size_t i = 0; i < h; i++)
497  {
498  num += (int)fread((void*)dst, 1, bytes_to_read_per_row, fp);
499  dst += pad;
500  }
501 
502  fclose(fp);
503  return (num > 0);
504 }
505 
506 bool ImageReadBGR_PxM(ImageOf<PixelBgr> &img, const char *filename)
507 {
508  int width, height, color, num;
509  FILE *fp=nullptr;
510  fp = fopen(filename, "rb");
511 
512  if(fp==nullptr)
513  {
514  yCError(IMAGEFILE, "Error opening %s, check if file exists.\n", filename);
515  return false;
516  }
517 
518  if (!ReadHeader_PxM(fp, &height, &width, &color))
519  {
520  fclose (fp);
521  yCError(IMAGEFILE, "Error reading header, is file a valid ppm/pgm?\n");
522  return false;
523  }
524 
525  if (!color)
526  {
527  fclose(fp);
528  yCError(IMAGEFILE, "File is grayscale, conversion not yet supported\n");
529  return false;
530  }
531 
532  ImageOf<PixelRgb> tmpImg;
533  tmpImg.resize(width, height);
534 
535  const int w = tmpImg.width() * img.getPixelSize();
536  const int h = tmpImg.height();
537  const int pad = tmpImg.getRowSize();
538  unsigned char *dst = tmpImg.getRawImage ();
539 
540  num = 0;
541  for (int i = 0; i < h; i++)
542  {
543  num += (int)fread((void *) dst, 1, (size_t) w, fp);
544  dst += pad;
545  }
546 
547  fclose(fp);
548 
549  return img.copy(tmpImg);
550 }
551 
552 
553 bool ImageReadMono_PxM(ImageOf<PixelMono> &img, const char *filename)
554 {
555  int width, height, color, num;
556  FILE *fp=nullptr;
557  fp = fopen(filename, "rb");
558 
559  if(fp==nullptr)
560  {
561  yCError(IMAGEFILE, "Error opening %s, check if file exists.\n", filename);
562  return false;
563  }
564 
565  if (!ReadHeader_PxM(fp, &height, &width, &color))
566  {
567  fclose (fp);
568  yCError(IMAGEFILE, "Error reading header, is file a valid ppm/pgm?\n");
569  return false;
570  }
571 
572  if (color)
573  {
574  fclose(fp);
575  yCError(IMAGEFILE, "File is color, conversion not yet supported\n");
576  return false;
577  }
578 
579  img.resize(width,height);
580 
581  const int w = img.width() * img.getPixelSize();
582  const int h = img.height();
583  const int pad = img.getRowSize();
584  unsigned char *dst = img.getRawImage ();
585 
586  num = 0;
587  for (int i = 0; i < h; i++)
588  {
589  num += (int)fread((void *) dst, 1, (size_t) w, fp);
590  dst += pad;
591  }
592 
593  fclose(fp);
594 
595  return true;
596 }
597 
599 // private write methods
601 
602 #if defined (YARP_HAS_PNG)
603 bool SavePNG(char *src, const char *filename, size_t h, size_t w, size_t rowSize, png_byte color_type, png_byte bit_depth)
604 {
605  // create file
606  if (src == nullptr)
607  {
608  yCError(IMAGEFILE, "[write_png_file] Cannot write to file a nullptr image");
609  return false;
610  }
611 
612  if (filename == nullptr)
613  {
614  yCError(IMAGEFILE, "[write_png_file] Filename is nullptr");
615  return false;
616  }
617 
618  FILE *fp = fopen(filename, "wb");
619  if (!fp)
620  {
621  yCError(IMAGEFILE, "[write_png_file] File %s could not be opened for writing", filename);
622  return false;
623  }
624 
625  // initialize stuff
626  png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
627  if (!png_ptr)
628  {
629  yCError(IMAGEFILE, "[write_png_file] png_create_write_struct failed");
630  fclose(fp);
631  return false;
632  }
633 
634  png_infop info_ptr = png_create_info_struct(png_ptr);
635  if (!info_ptr)
636  {
637  yCError(IMAGEFILE, "[write_png_file] png_create_info_struct failed");
638  fclose(fp);
639  return false;
640  }
641 
642  //init io
643  if (setjmp(png_jmpbuf(png_ptr)))
644  {
645  yCError(IMAGEFILE, "[write_png_file] Error during init_io");
646  fclose(fp);
647  return false;
648  }
649  png_init_io(png_ptr, fp);
650 
651  // write header
652  if (setjmp(png_jmpbuf(png_ptr)))
653  {
654  yCError(IMAGEFILE, "[write_png_file] Error during writing header");
655  fclose(fp);
656  return false;
657  }
658  png_set_IHDR(png_ptr, info_ptr, w, h,
659  bit_depth, color_type, PNG_INTERLACE_NONE,
660  PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
661 
662  //write info
663  png_write_info(png_ptr, info_ptr);
664 
665  //allocate data space
666  png_bytep* row_pointers = new png_bytep[h];
667 
668  for (size_t y = 0; y < h; y++)
669  {
670  //this is an array of pointers. Each element points to a row of the image
671  row_pointers[y] = (png_bytep)(src) + (y * rowSize);
672  }
673 
674  // write bytes
675  if (setjmp(png_jmpbuf(png_ptr)))
676  {
677  yCError(IMAGEFILE, "[write_png_file] Error during writing bytes");
678  delete [] row_pointers;
679  png_destroy_write_struct(&png_ptr, &info_ptr);
680  fclose(fp);
681  return false;
682  }
683  png_write_image(png_ptr, row_pointers);
684 
685  // end write
686  if (setjmp(png_jmpbuf(png_ptr)))
687  {
688  yCError(IMAGEFILE, "[write_png_file] Error during end of write");
689  delete [] row_pointers;
690  png_destroy_write_struct(&png_ptr, &info_ptr);
691  fclose(fp);
692  return false;
693  }
694  png_write_end(png_ptr, info_ptr);
695 
696  // finished. cleanup allocation
697  delete[] row_pointers;
698  png_destroy_write_struct(&png_ptr, &info_ptr);
699  fclose(fp);
700  return true;
701 }
702 #endif
703 
704 bool SaveJPG(char *src, const char *filename, size_t h, size_t w, size_t rowSize)
705 {
706 #if defined (YARP_HAS_JPEG)
707  int quality = 100;
708  struct jpeg_compress_struct cinfo;
709  struct jpeg_error_mgr jerr;
710  FILE * outfile = nullptr;
711  JSAMPROW row_pointer[1];
712  int row_stride;
713 
714  cinfo.err = jpeg_std_error(&jerr);
715  jpeg_create_compress(&cinfo);
716 
717  if ((outfile = fopen(filename, "wb")) == nullptr)
718  {
719  yCError(IMAGEFILE, "can't write file: %s\n", filename);
720  return false;
721  }
722  jpeg_stdio_dest(&cinfo, outfile);
723 
724  cinfo.image_width = w;
725  cinfo.image_height = h;
726  cinfo.input_components = 3;
727  cinfo.in_color_space = JCS_RGB;
728  jpeg_set_defaults(&cinfo);
729  jpeg_set_quality(&cinfo, quality, TRUE);
730 
731  jpeg_start_compress(&cinfo, TRUE);
732 
733  row_stride = w * 3;
734 
735  while (cinfo.next_scanline < cinfo.image_height)
736  {
737  row_pointer[0] = (JSAMPROW)&src[cinfo.next_scanline * row_stride];
738  (void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
739  }
740 
741  jpeg_finish_compress(&cinfo);
742  fclose(outfile);
743  jpeg_destroy_compress(&cinfo);
744  return true;
745 #else
746  yCError(IMAGEFILE) << "libjpeg not installed";
747  return false;
748 #endif
749 }
750 
751 bool SavePGM(char *src, const char *filename, size_t h, size_t w, size_t rowSize)
752 {
753  FILE *fp = fopen(filename, "wb");
754  if (!fp)
755  {
756  yCError(IMAGEFILE, "cannot open file %s for writing\n", filename);
757  return false;
758  }
759  else
760  {
761  const int inc = rowSize;
762 
763  fprintf(fp, "P5\n%zu %zu\n%d\n", w, h, 255);
764  for (size_t i = 0; i < h; i++)
765  {
766  fwrite((void *)src, 1, (size_t)w, fp);
767  src += inc;
768  }
769 
770  fclose(fp);
771  }
772 
773  return true;
774 }
775 
776 
777 bool SavePPM(char *src, const char *filename, size_t h, size_t w, size_t rowSize)
778 {
779  FILE *fp = fopen(filename, "wb");
780  if (!fp)
781  {
782  yCError(IMAGEFILE, "cannot open file %s for writing\n", filename);
783  return false;
784  }
785  else
786  {
787  const int inc = rowSize;//YARPSimpleOperation::ComputePadding (w*3, YarpImageAlign) + w * 3;
788 
789  fprintf(fp, "P6\n%zu %zu\n%d\n", w, h, 255);
790  for (size_t i = 0; i < h; i++)
791  {
792  fwrite((void *)src, 1, (size_t)(w * 3), fp);
793  src += inc;
794  }
795 
797  fclose(fp);
798  }
799 
800  return true;
801 }
802 
803 #if defined (YARP_HAS_ZLIB)
804 bool SaveFloatCompressed(char* src, const char* filename, size_t h, size_t w, size_t rowSize)
805 {
806  size_t sizeDataOriginal=w*h*sizeof(float);
807  size_t sizeDataCompressed = (sizeDataOriginal * 1.1) + 12;
808  char* dataCompressed = (char*)malloc(sizeDataCompressed);
809 
810  int z_result = compress((Bytef*) dataCompressed,(uLongf*) &sizeDataCompressed, (Bytef*)src, sizeDataOriginal);
811  switch (z_result)
812  {
813  case Z_OK:
814  break;
815 
816  case Z_MEM_ERROR:
817  yCError(IMAGEFILE, "zlib compression: out of memory");
818  return false;
819  break;
820 
821  case Z_BUF_ERROR:
822  yCError(IMAGEFILE, "zlib compression: output buffer wasn't large enough");
823  return false;
824  break;
825  }
826 
827  FILE* fp = fopen(filename, "wb");
828  if (fp == nullptr)
829  {
830  return false;
831  }
832 
833  size_t bw = 0;
834  size_t dims[2] = { h,w };
835 
836  if (fwrite(dims, sizeof(dims), 1, fp) > 0) {
837  bw = fwrite((void*)dataCompressed, sizeDataCompressed, 1, fp);
838  }
839 
840  fclose(fp);
841  return (bw > 0);
842 }
843 #endif
844 
845 bool SaveFloatRaw(char* src, const char* filename, size_t h, size_t w, size_t rowSize)
846 {
847  FILE* fp = fopen(filename, "wb");
848  if (fp == nullptr)
849  {
850  return false;
851  }
852 
853  size_t dims[2] = { h,w };
854 
855  size_t bw = 0;
856  size_t size_ = sizeof(float);
857  auto count_ = (size_t)(dims[0] * dims[1]);
858 
859  if (fwrite(dims, sizeof(dims), 1, fp) > 0) {
860  bw = fwrite((void*)src, size_, count_, fp);
861  }
862 
863  fclose(fp);
864  return (bw > 0);
865 }
866 
867 bool ImageWriteJPG(ImageOf<PixelRgb>& img, const char *filename)
868 {
869  return SaveJPG((char*)img.getRawImage(), filename, img.height(), img.width(), img.getRowSize());
870 }
871 
872 bool ImageWritePNG(ImageOf<PixelRgb>& img, const char *filename)
873 {
874 #if defined (YARP_HAS_PNG)
875  return SavePNG((char*)img.getRawImage(), filename, img.height(), img.width(), img.getRowSize(), PNG_COLOR_TYPE_RGB, 8);
876 #else
877  yCError(IMAGEFILE) << "YARP was not built with png support";
878  return false;
879 #endif
880 }
881 
882 bool ImageWritePNG(ImageOf<PixelMono>& img, const char *filename)
883 {
884 #if defined (YARP_HAS_PNG)
885  return SavePNG((char*)img.getRawImage(), filename, img.height(), img.width(), img.getRowSize(), PNG_COLOR_TYPE_GRAY, 8);
886 #else
887  yCError(IMAGEFILE) << "YARP was not built with png support";
888  return false;
889 #endif
890 }
891 
892 bool ImageWriteRGB(ImageOf<PixelRgb>& img, const char *filename)
893 {
894  return SavePPM((char*)img.getRawImage(),filename,img.height(),img.width(),img.getRowSize());
895 }
896 
897 bool ImageWriteMono(ImageOf<PixelMono>& img, const char *filename)
898 {
899  return SavePGM((char*)img.getRawImage(), filename, img.height(), img.width(), img.getRowSize());
900 }
901 
902 bool ImageWriteFloat_PlainHeaderless(ImageOf<PixelFloat>& img, const char *filename)
903 {
904  return SaveFloatRaw((char*)img.getRawImage(), filename, img.height(), img.width(), img.getRowSize());
905 }
906 
907 bool ImageWriteFloat_CompressedHeaderless(ImageOf<PixelFloat>& img, const char* filename)
908 {
909 #if defined (YARP_HAS_ZLIB)
910  return SaveFloatCompressed((char*)img.getRawImage(), filename, img.height(), img.width(), img.getRowSize());
911 #else
912  yCError(IMAGEFILE) << "YARP was not built with zlib support";
913  return false;
914 #endif
915 }
916 }
917 
919 // public read methods
921 
922 bool file::read(ImageOf<PixelRgb> & dest, const std::string& src, image_fileformat format)
923 {
924  const char* file_ext = strrchr(src.c_str(), '.');
925  if (file_ext==nullptr)
926  {
927  yCError(IMAGEFILE) << "cannot find file extension in file name";
928  return false;
929  }
930 
931  if (strcmp(file_ext, ".pgm")==0 ||
932  strcmp(file_ext, ".ppm")==0 ||
933  format == FORMAT_PGM ||
934  format == FORMAT_PPM)
935  {
936  return ImageReadRGB_PxM(dest,src.c_str());
937  }
938  else if(strcmp(file_ext, ".png")==0 ||
939  format == FORMAT_PNG)
940  {
941  return ImageReadRGB_PNG(dest, src.c_str());
942  }
943  else if(strcmp(file_ext, ".jpg") == 0 ||
944  strcmp(file_ext, ".jpeg") == 0 ||
945  format == FORMAT_JPG)
946  {
947  return ImageReadRGB_JPG(dest, src.c_str());
948  }
949  yCError(IMAGEFILE) << "unsupported file format";
950  return false;
951 }
952 
953 
954 bool file::read(ImageOf<PixelBgr> & dest, const std::string& src, image_fileformat format)
955 {
956  const char* file_ext = strrchr(src.c_str(), '.');
957  if (file_ext == nullptr)
958  {
959  yCError(IMAGEFILE) << "cannot find file extension in file name";
960  return false;
961  }
962 
963  if (strcmp(file_ext, ".pgm") == 0 ||
964  strcmp(file_ext, ".ppm") == 0 ||
965  format == FORMAT_PGM ||
966  format == FORMAT_PPM)
967  {
968  return ImageReadBGR_PxM(dest, src.c_str());
969  }
970  else if (strcmp(file_ext, ".png") == 0 ||
971  format == FORMAT_PNG)
972  {
973  return ImageReadBGR_PNG(dest, src.c_str());
974  }
975  else if (strcmp(file_ext, ".jpg") == 0 ||
976  strcmp(file_ext, ".jpeg") == 0 ||
977  format == FORMAT_JPG)
978  {
979  return ImageReadBGR_JPG(dest, src.c_str());
980  }
981  yCError(IMAGEFILE) << "unsupported file format";
982  return false;
983 }
984 
985 
986 bool file::read(ImageOf<PixelRgba> & dest, const std::string& src, image_fileformat format)
987 {
988  const char* file_ext = strrchr(src.c_str(), '.');
989  if (file_ext == nullptr)
990  {
991  yCError(IMAGEFILE) << "cannot find file extension in file name";
992  return false;
993  }
994 
995  if (strcmp(file_ext, ".pgm") == 0 ||
996  strcmp(file_ext, ".ppm") == 0 ||
997  format == FORMAT_PGM ||
998  format == FORMAT_PPM)
999  {
1000  ImageOf<PixelRgb> img2;
1001  bool ok = ImageReadRGB_PxM(img2, src.c_str());
1002  if (ok)
1003  {
1004  dest.copy(img2);
1005  }
1006  return ok;
1007  }
1008  else if (strcmp(file_ext, ".png") == 0 ||
1009  format == FORMAT_PNG)
1010  {
1011  ImageOf<PixelRgb> img2;
1012  bool ok = ImageReadRGB_PNG(img2, src.c_str());
1013  if (ok)
1014  {
1015  dest.copy(img2);
1016  }
1017  return ok;
1018  }
1019  else if (strcmp(file_ext, ".jpg") == 0 ||
1020  strcmp(file_ext, ".jpeg") == 0 ||
1021  format == FORMAT_JPG)
1022  {
1023  ImageOf<PixelRgb> img2;
1024  bool ok = ImageReadRGB_JPG(img2, src.c_str());
1025  if (ok)
1026  {
1027  dest.copy(img2);
1028  }
1029  return ok;
1030  }
1031  yCError(IMAGEFILE) << "unsupported file format";
1032  return false;
1033 }
1034 
1035 bool file::read(ImageOf<PixelMono> & dest, const std::string& src, image_fileformat format)
1036 {
1037  const char* file_ext = strrchr(src.c_str(), '.');
1038  if (file_ext == nullptr)
1039  {
1040  yCError(IMAGEFILE) << "cannot find file extension in file name";
1041  return false;
1042  }
1043 
1044  if (strcmp(file_ext, ".pgm") == 0 ||
1045  strcmp(file_ext, ".ppm") == 0 ||
1046  format == FORMAT_PGM ||
1047  format == FORMAT_PPM)
1048  {
1049  return ImageReadMono_PxM(dest, src.c_str());
1050  }
1051  else if (strcmp(file_ext, ".png") == 0 ||
1052  format == FORMAT_PNG)
1053  {
1054  return ImageReadMono_PNG(dest, src.c_str());
1055  }
1056  else if (strcmp(file_ext, ".jpg") == 0 ||
1057  strcmp(file_ext, ".jpeg") == 0 ||
1058  format == FORMAT_JPG)
1059  {
1060  return ImageReadMono_JPG(dest, src.c_str());
1061  }
1062  yCError(IMAGEFILE) << "unsupported file format";
1063  return false;
1064 }
1065 
1066 bool file::read(ImageOf<PixelFloat>& dest, const std::string& src, image_fileformat format)
1067 {
1068  const char* file_ext = strrchr(src.c_str(), '.');
1069  if (file_ext == nullptr)
1070  {
1071  yCError(IMAGEFILE) << "cannot find file extension in file name";
1072  return false;
1073  }
1074 
1075  if (strcmp(file_ext, ".float") == 0 ||
1076  format == FORMAT_NUMERIC)
1077  {
1078  return ImageReadFloat_PlainHeaderless(dest, src);
1079  }
1080  else if (strcmp(file_ext, ".floatzip") == 0 ||
1081  format == FORMAT_NUMERIC_COMPRESSED)
1082  {
1083 #if defined (YARP_HAS_ZLIB)
1084  return ImageReadFloat_CompressedHeaderless(dest, src);
1085 #else
1086  yCError(IMAGEFILE) << "YARP was not built with zlib support";
1087  return false;
1088 #endif
1089  }
1090  yCError(IMAGEFILE) << "unsupported file format";
1091  return false;
1092 }
1093 
1097 
1098 bool file::write(const ImageOf<PixelRgb> & src, const std::string& dest, image_fileformat format)
1099 {
1100  if (format == FORMAT_PPM)
1101  {
1102  return ImageWriteRGB(const_cast<ImageOf<PixelRgb> &>(src), dest.c_str());
1103  }
1104  else if (format == FORMAT_JPG)
1105  {
1106  return ImageWriteJPG(const_cast<ImageOf<PixelRgb> &>(src), dest.c_str());
1107  }
1108  else if (format == FORMAT_PNG)
1109  {
1110  return ImageWritePNG(const_cast<ImageOf<PixelRgb> &>(src), dest.c_str());
1111  }
1112  else
1113  {
1114  yCError(IMAGEFILE) << "Invalid format, operation not supported";
1115  return false;
1116  }
1117 }
1118 
1119 bool file::write(const ImageOf<PixelBgr> & src, const std::string& dest, image_fileformat format)
1120 {
1121  ImageOf<PixelRgb> imgRGB;
1122  imgRGB.copy(src);
1123  if (format == FORMAT_PPM)
1124  {
1125  return ImageWriteRGB(const_cast<ImageOf<PixelRgb> &>(imgRGB), dest.c_str());
1126  }
1127  else if (format == FORMAT_JPG)
1128  {
1129  return ImageWriteJPG(const_cast<ImageOf<PixelRgb> &>(imgRGB), dest.c_str());
1130  }
1131  else if (format == FORMAT_PNG)
1132  {
1133  return ImageWritePNG(const_cast<ImageOf<PixelRgb> &>(imgRGB), dest.c_str());
1134  }
1135  else
1136  {
1137  yCError(IMAGEFILE) << "Invalid format, operation not supported";
1138  return false;
1139  }
1140 }
1141 
1142 
1143 bool file::write(const ImageOf<PixelRgba> & src, const std::string& dest, image_fileformat format)
1144 {
1145  ImageOf<PixelRgb> imgRGB;
1146  imgRGB.copy(src);
1147  if (format == FORMAT_PPM)
1148  {
1149  return ImageWriteRGB(const_cast<ImageOf<PixelRgb> &>(imgRGB), dest.c_str());
1150  }
1151  else if (format == FORMAT_JPG)
1152  {
1153  return ImageWriteJPG(const_cast<ImageOf<PixelRgb> &>(imgRGB), dest.c_str());
1154  }
1155  else if (format == FORMAT_PNG)
1156  {
1157  return ImageWritePNG(const_cast<ImageOf<PixelRgb> &>(imgRGB), dest.c_str());
1158  }
1159  else
1160  {
1161  yCError(IMAGEFILE) << "Invalid format, operation not supported";
1162  return false;
1163  }
1164 }
1165 
1166 
1167 bool file::write(const ImageOf<PixelMono> & src, const std::string& dest, image_fileformat format)
1168 {
1169  if (format == FORMAT_PGM)
1170  {
1171  return ImageWriteMono(const_cast<ImageOf<PixelMono> &>(src), dest.c_str());
1172  }
1173  else if (format == FORMAT_PNG)
1174  {
1175  return ImageWritePNG(const_cast<ImageOf<PixelMono> &>(src), dest.c_str());
1176  }
1177  else
1178  {
1179  yCError(IMAGEFILE) << "Invalid format, operation not supported";
1180  return false;
1181  }
1182 }
1183 
1184 bool file::write(const ImageOf<PixelFloat>& src, const std::string& dest, image_fileformat format)
1185 {
1186  if (format == FORMAT_NUMERIC)
1187  {
1188  return ImageWriteFloat_PlainHeaderless(const_cast<ImageOf<PixelFloat> &>(src), dest.c_str());
1189  }
1190  else if (format == FORMAT_NUMERIC_COMPRESSED)
1191  {
1192  return ImageWriteFloat_CompressedHeaderless(const_cast<ImageOf<PixelFloat>&>(src), dest.c_str());
1193  }
1194  else
1195  {
1196  yCError(IMAGEFILE) << "Invalid format, operation not supported";
1197  return false;
1198  }
1199 }
1200 
1201 bool file::write(const Image& src, const std::string& dest, image_fileformat format)
1202 {
1203  int code=src.getPixelCode();
1204  if (code == VOCAB_PIXEL_MONO)
1205  {
1206  return write(static_cast<const ImageOf<PixelMono>&>(src), dest, format);
1207  }
1208  else if (code == VOCAB_PIXEL_MONO_FLOAT)
1209  {
1210  return write(static_cast<const ImageOf<PixelFloat>&>(src), dest, format);
1211  }
1212  else if (code == VOCAB_PIXEL_BGR)
1213  {
1214  return write(static_cast<const ImageOf<PixelBgr>&>(src), dest, format);
1215  }
1216  else if (code == VOCAB_PIXEL_RGB)
1217  {
1218  return write(static_cast<const ImageOf<PixelRgb>&>(src), dest, format);
1219  }
1220  else if (code == VOCAB_PIXEL_RGBA)
1221  {
1222  return write(static_cast<const ImageOf<PixelRgba>&>(src), dest, format);
1223  }
1224  else
1225  {
1226  ImageOf<PixelRgb> img;
1227  img.copy(src);
1228  return write(img,dest);
1229  }
1230 }
1231 
1232 
#define yError(...)
Definition: Log.h:279
size_t getPixelSize() const override
Gets pixel size in memory in bytes.
Definition: Image.h:668
Base class for storing images.
Definition: Image.h:82
unsigned char * getPixelAddress(size_t x, size_t y) const
Get address of a pixel in memory.
Definition: Image.h:240
size_t width() const
Gets width of image in pixels.
Definition: Image.h:166
size_t getRowSize() const
Size of the underlying image buffer rows.
Definition: Image.h:192
unsigned char * getRawImage() const
Access to the internal image buffer.
Definition: Image.cpp:541
bool copy(const Image &alt)
Copy operator.
Definition: Image.cpp:836
size_t getRawImageSize() const
Access to the internal buffer size information (this is how much memory has been allocated for the im...
Definition: Image.cpp:550
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:452
size_t height() const
Gets height of image in pixels.
Definition: Image.h:172
virtual int getPixelCode() const
Gets pixel type identifier.
Definition: Image.cpp:440
#define yCError(component,...)
Definition: LogComponent.h:154
#define yCWarning(component,...)
Definition: LogComponent.h:143
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:77
@ VOCAB_PIXEL_RGBA
Definition: Image.h:48
@ VOCAB_PIXEL_BGR
Definition: Image.h:52
@ VOCAB_PIXEL_MONO_FLOAT
Definition: Image.h:56
@ VOCAB_PIXEL_MONO
Definition: Image.h:45
@ VOCAB_PIXEL_RGB
Definition: Image.h:47
An interface to the operating system, including Port based communication.
bool read(ImageOf< PixelRgb > &dest, const std::string &src, image_fileformat format=FORMAT_ANY)
Definition: ImageFile.cpp:922
@ FORMAT_NUMERIC_COMPRESSED
Definition: ImageFile.h:30
bool write(const ImageOf< PixelRgb > &src, const std::string &dest, image_fileformat format=FORMAT_PPM)
Definition: ImageFile.cpp:1098
Signal processing.
Definition: Image.h:22