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