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