Visualization Library 2.0.0

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

[Download] [Tutorials] [All Classes] [Grouped Classes]
ioJPG.cpp
Go to the documentation of this file.
1 /**************************************************************************************/
2 /* */
3 /* Visualization Library */
4 /* http://visualizationlibrary.org */
5 /* */
6 /* Copyright (c) 2005-2020, Michele Bosi */
7 /* All rights reserved. */
8 /* */
9 /* Redistribution and use in source and binary forms, with or without modification, */
10 /* are permitted provided that the following conditions are met: */
11 /* */
12 /* - Redistributions of source code must retain the above copyright notice, this */
13 /* list of conditions and the following disclaimer. */
14 /* */
15 /* - Redistributions in binary form must reproduce the above copyright notice, this */
16 /* list of conditions and the following disclaimer in the documentation and/or */
17 /* other materials provided with the distribution. */
18 /* */
19 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */
20 /* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
21 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
22 /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */
23 /* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
24 /* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
25 /* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
26 /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
27 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
28 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
29 /* */
30 /**************************************************************************************/
31 
32 #include "ioJPG.hpp"
34 #include <vlCore/FileSystem.hpp>
35 #include <vlCore/VirtualFile.hpp>
36 #include <vlCore/Image.hpp>
38 
39 extern "C"
40 {
41  #include "jpeglib.h"
42  #include "jconfig.h"
43  #include "jerror.h"
44  #include "jmorecfg.h"
45 }
46 #include <setjmp.h>
47 #include <cstdio>
48 
49 using namespace vl;
50 
51 namespace
52 {
53  /*
54  * Some of the code below has been adapted to VL from the IJG jpeg library.
55  */
56 
57  /* Expanded data source object for stdio input */
58 
59  typedef struct
60  {
61  struct jpeg_source_mgr pub;
62  VirtualFile * infile; /* source stream */
63  JOCTET * buffer; /* start of buffer */
64  boolean start_of_file; /* have we gotten any data yet? */
65  } my_source_mgr;
66 
67  typedef my_source_mgr * my_src_ptr;
68 
69  #define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */
70 
71  /*
72  * Initialize source --- called by jpeg_read_header
73  * before any data is actually read.
74  */
75 
76  METHODDEF(void)
77  init_source (j_decompress_ptr cinfo)
78  {
79  my_src_ptr src = (my_src_ptr) cinfo->src;
80 
81  /* We reset the empty-input-file flag for each image,
82  * but we don't clear the input buffer.
83  * This is correct behavior for reading a series of images from one source.
84  */
85  src->start_of_file = TRUE;
86  }
87 
88  /*
89  * Fill the input buffer --- called whenever buffer is emptied.
90  *
91  * In typical applications, this should read fresh data into the buffer
92  * (ignoring the current state of next_input_byte & bytes_in_buffer),
93  * reset the pointer & count to the start of the buffer, and return TRUE
94  * indicating that the buffer has been reloaded. It is not necessary to
95  * fill the buffer entirely, only to obtain at least one more byte.
96  *
97  * There is no such thing as an EOF return. If the end of the file has been
98  * reached, the routine has a choice of ERREXIT() or inserting fake data into
99  * the buffer. In most cases, generating a warning message and inserting a
100  * fake EOI marker is the best course of action --- this will allow the
101  * decompressor to output however much of the image is there. However,
102  * the resulting error message is misleading if the real problem is an empty
103  * input file, so we handle that case specially.
104  *
105  * In applications that need to be able to suspend compression due to input
106  * not being available yet, a FALSE return indicates that no more data can be
107  * obtained right now, but more may be forthcoming later. In this situation,
108  * the decompressor will return to its caller (with an indication of the
109  * number of scanlines it has read, if any). The application should resume
110  * decompression after it has loaded more data into the input buffer. Note
111  * that there are substantial restrictions on the use of suspension --- see
112  * the documentation.
113  *
114  * When suspending, the decompressor will back up to a convenient restart point
115  * (typically the start of the current MCU). next_input_byte & bytes_in_buffer
116  * indicate where the restart point will be if the current call returns FALSE.
117  * Data beyond this point must be rescanned after resumption, so move it to
118  * the front of the buffer rather than discarding it.
119  */
120 
121  METHODDEF(boolean)
122  fill_input_buffer (j_decompress_ptr cinfo)
123  {
124  my_src_ptr src = (my_src_ptr) cinfo->src;
125  size_t nbytes;
126 
127  nbytes = (size_t)src->infile->read(src->buffer, INPUT_BUF_SIZE);
128 
129  if (nbytes <= 0) {
130  if (src->start_of_file) /* Treat empty input file as fatal error */
131  ERREXIT(cinfo, JERR_INPUT_EMPTY);
132  WARNMS(cinfo, JWRN_JPEG_EOF);
133  /* Insert a fake EOI marker */
134  src->buffer[0] = (JOCTET) 0xFF;
135  src->buffer[1] = (JOCTET) JPEG_EOI;
136  nbytes = 2;
137  }
138 
139  src->pub.next_input_byte = src->buffer;
140  src->pub.bytes_in_buffer = nbytes;
141  src->start_of_file = FALSE;
142 
143  return TRUE;
144  }
145 
146  /*
147  * Skip data --- used to skip over a potentially large amount of
148  * uninteresting data (such as an APPn marker).
149  *
150  * Writers of suspendable-input applications must note that skip_input_data
151  * is not granted the right to give a suspension return. If the skip extends
152  * beyond the data currently in the buffer, the buffer can be marked empty so
153  * that the next read will cause a fill_input_buffer call that can suspend.
154  * Arranging for additional bytes to be discarded before reloading the input
155  * buffer is the application writer's problem.
156  */
157 
158  METHODDEF(void)
159  skip_input_data (j_decompress_ptr cinfo, long num_bytes)
160  {
161  my_src_ptr src = (my_src_ptr) cinfo->src;
162 
163  /* Just a dumb implementation for now. Could use fseek() except
164  * it doesn't work on pipes. Not clear that being smart is worth
165  * any trouble anyway --- large skips are infrequent.
166  */
167  if (num_bytes > 0) {
168  while (num_bytes > (long) src->pub.bytes_in_buffer) {
169  num_bytes -= (long) src->pub.bytes_in_buffer;
170  fill_input_buffer(cinfo);
171  /* note we assume that fill_input_buffer will never return FALSE,
172  * so suspension need not be handled.
173  */
174  }
175  src->pub.next_input_byte += (size_t) num_bytes;
176  src->pub.bytes_in_buffer -= (size_t) num_bytes;
177  }
178  }
179 
180  /*
181  * An additional method that can be provided by data source modules is the
182  * resync_to_restart method for error recovery in the presence of RST markers.
183  * For the moment, this source module just uses the default resync method
184  * provided by the JPEG library. That method assumes that no backtracking
185  * is possible.
186  */
187 
188  /*
189  * Terminate source --- called by jpeg_finish_decompress
190  * after all data has been read. Often a no-op.
191  *
192  * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
193  * application must deal with any cleanup that should happen even
194  * for error exit.
195  */
196 
197  METHODDEF(void)
198  term_source (j_decompress_ptr /*cinfo*/)
199  {
200  /* no work necessary here */
201  }
202 
203  /*
204  * Prepare for input from a stdio stream.
205  * The caller must have already opened the stream, and is responsible
206  * for closing it after finishing decompression.
207  */
208 
209  GLOBAL(void)
210  jpeg_vl_src (j_decompress_ptr cinfo, VirtualFile* infile)
211  {
212  my_src_ptr src;
213 
214  /* The source object and input buffer are made permanent so that a series
215  * of JPEG images can be read from the same file by calling jpeg_stdio_src
216  * only before the first one. (If we discarded the buffer at the end of
217  * one image, we'd likely lose the start of the next one.)
218  * This makes it unsafe to use this manager and a different source
219  * manager serially with the same JPEG object. Caveat programmer.
220  */
221  if (cinfo->src == NULL) { /* first time for this JPEG object? */
222  cinfo->src = (struct jpeg_source_mgr *)
223  (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(my_source_mgr));
224  src = (my_src_ptr) cinfo->src;
225  src->buffer = (JOCTET *)
226  (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
227  INPUT_BUF_SIZE * sizeof(JOCTET));
228  }
229 
230  src = (my_src_ptr) cinfo->src;
231  src->pub.init_source = init_source;
232  src->pub.fill_input_buffer = fill_input_buffer;
233  src->pub.skip_input_data = skip_input_data;
234  src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
235  src->pub.term_source = term_source;
236  src->infile = infile;
237  src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
238  src->pub.next_input_byte = NULL; /* until buffer loaded */
239  }
240  //-----------------------------------------------------------------------------
241  struct my_error_mgr {
242  struct jpeg_error_mgr pub; /* "public" fields */
243  jmp_buf setjmp_buffer; /* for return to caller */
244  };
245 
246  typedef struct my_error_mgr * my_error_ptr;
247 
248  /*
249  * Here's the routine that will replace the standard error_exit method:
250  */
251 
252  METHODDEF(void)
253  my_error_exit (j_common_ptr cinfo)
254  {
255  /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
256  my_error_ptr myerr = (my_error_ptr) cinfo->err;
257 
258  /* Always display the message. */
259  /* We could postpone this until after returning, if we chose. */
260  (*cinfo->err->output_message) (cinfo);
261 
262  /* Return control to the setjmp point */
263  longjmp(myerr->setjmp_buffer, 1);
264  }
265 
266 //-----------------------------------------------------------------------------
267 
268  /* Expanded data destination object for stdio output */
269 
270  typedef struct {
271  struct jpeg_destination_mgr pub; /* public fields */
272 
273  VirtualFile * outfile; /* target stream */
274  JOCTET * buffer; /* start of buffer */
275  } my_destination_mgr;
276 
277  typedef my_destination_mgr * my_dest_ptr;
278 
279  #define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */
280 
281  /*
282  * Initialize destination --- called by jpeg_start_compress
283  * before any data is actually written.
284  */
285 
286  METHODDEF(void)
287  init_destination (j_compress_ptr cinfo)
288  {
289  my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
290 
291  /* Allocate the output buffer --- it will be released when done with image */
292  dest->buffer = (JOCTET *)
293  (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
294  OUTPUT_BUF_SIZE * sizeof(JOCTET));
295 
296  dest->pub.next_output_byte = dest->buffer;
297  dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
298  }
299 
300  /*
301  * Empty the output buffer --- called whenever buffer fills up.
302  *
303  * In typical applications, this should write the entire output buffer
304  * (ignoring the current state of next_output_byte & free_in_buffer),
305  * reset the pointer & count to the start of the buffer, and return TRUE
306  * indicating that the buffer has been dumped.
307  *
308  * In applications that need to be able to suspend compression due to output
309  * overrun, a FALSE return indicates that the buffer cannot be emptied now.
310  * In this situation, the compressor will return to its caller (possibly with
311  * an indication that it has not accepted all the supplied scanlines). The
312  * application should resume compression after it has made more room in the
313  * output buffer. Note that there are substantial restrictions on the use of
314  * suspension --- see the documentation.
315  *
316  * When suspending, the compressor will back up to a convenient restart point
317  * (typically the start of the current MCU). next_output_byte & free_in_buffer
318  * indicate where the restart point will be if the current call returns FALSE.
319  * Data beyond this point will be regenerated after resumption, so do not
320  * write it out when emptying the buffer externally.
321  */
322 
323  METHODDEF(boolean)
324  empty_output_buffer (j_compress_ptr cinfo)
325  {
326  my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
327 
328  // if (JFWRITE(dest->outfile, dest->buffer, OUTPUT_BUF_SIZE) != (size_t) OUTPUT_BUF_SIZE)
329  if (dest->outfile->write(dest->buffer, OUTPUT_BUF_SIZE) != (size_t) OUTPUT_BUF_SIZE)
330  ERREXIT(cinfo, JERR_FILE_WRITE);
331 
332  dest->pub.next_output_byte = dest->buffer;
333  dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
334 
335  return TRUE;
336  }
337 
338  /*
339  * Terminate destination --- called by jpeg_finish_compress
340  * after all data has been written. Usually needs to flush buffer.
341  *
342  * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
343  * application must deal with any cleanup that should happen even
344  * for error exit.
345  */
346 
347  METHODDEF(void)
348  term_destination (j_compress_ptr cinfo)
349  {
350  my_dest_ptr dest = (my_dest_ptr)cinfo->dest;
351  size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
352 
353  /* Write any data remaining in the buffer */
354  if (datacount > 0) {
355  if (dest->outfile->write(dest->buffer, datacount) != (long long)datacount)
356  ERREXIT(cinfo, JERR_FILE_WRITE);
357  }
358  // fixme?
359  //fflush(dest->outfile);
361  //if (ferror(dest->outfile))
362  // ERREXIT(cinfo, JERR_FILE_WRITE);
363  }
364 
365  /*
366  * Prepare for output to a stdio stream.
367  * The caller must have already opened the stream, and is responsible
368  * for closing it after finishing compression.
369  */
370 
371  GLOBAL(void)
372  jpeg_vl_dest (j_compress_ptr cinfo, VirtualFile * outfile)
373  {
374  my_dest_ptr dest;
375 
376  /* The destination object is made permanent so that multiple JPEG images
377  * can be written to the same file without re-executing jpeg_stdio_dest.
378  * This makes it dangerous to use this manager and a different destination
379  * manager serially with the same JPEG object, because their private object
380  * sizes may be different. Caveat programmer.
381  */
382  if (cinfo->dest == NULL) { /* first time for this JPEG object? */
383  cinfo->dest = (struct jpeg_destination_mgr *)
384  (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
385  sizeof(my_destination_mgr));
386  }
387 
388  dest = (my_dest_ptr) cinfo->dest;
389  dest->pub.init_destination = init_destination;
390  dest->pub.empty_output_buffer = empty_output_buffer;
391  dest->pub.term_destination = term_destination;
392  dest->outfile = outfile;
393  }
394 }
395 //-----------------------------------------------------------------------------
397 {
398  if ( !file->open(OM_ReadOnly) )
399  {
400  Log::error( Say("loadJPG: cannot open file '%s'\n") << file->path() );
401  return NULL;
402  }
403 
404  ref<Image> img = new Image;
405  img->setObjectName(file->path().toStdString().c_str());
406 
407  struct jpeg_decompress_struct cinfo;
408 
409  struct my_error_mgr jerr;
410 
411  JSAMPARRAY buffer; /* Output row buffer */
412  int row_stride; /* physical row width in output buffer */
413 
414  /* Step 1: allocate and initialize JPEG decompression object */
415 
416  /* We set up the normal JPEG error routines, then override error_exit. */
417  cinfo.err = jpeg_std_error(&jerr.pub);
418  jerr.pub.error_exit = my_error_exit;
419 
420  // fixme? "warning C4611: interaction between '_setjmp' and C++ object destruction is non-portable"
421 
422 #if 0
423  /* Establish the setjmp return context for my_error_exit to use. */
424  if (setjmp(jerr.setjmp_buffer)) {
425  /* If we get here, the JPEG code has signaled an error.
426  * We need to clean up the JPEG object, close the input file, and return. */
427  jpeg_destroy_decompress(&cinfo);
428  file->close();
429  return 0;
430  }
431 #endif
432 
433  /* Now we can initialize the JPEG decompression object. */
434  jpeg_create_decompress(&cinfo);
435 
436  /* Step 2: specify data source (eg, a file) */
437 
438  jpeg_vl_src(&cinfo, file);
439 
440  /* Step 3: read file parameters with jpeg_read_header() */
441 
442  jpeg_read_header(&cinfo, TRUE);
443 
444  if (cinfo.jpeg_color_space == JCS_GRAYSCALE)
445  {
446  VL_CHECK(cinfo.out_color_space == JCS_GRAYSCALE)
447  img->allocate2D(cinfo.image_width, cinfo.image_height, 1, IF_LUMINANCE, IT_UNSIGNED_BYTE);
448  }
449  else // JCS_RGB
450  {
451  VL_CHECK(cinfo.out_color_space == JCS_RGB)
452  img->allocate2D(cinfo.image_width, cinfo.image_height, 1, IF_RGB, IT_UNSIGNED_BYTE);
453  }
454 
455  /* Step 4: set parameters for decompression */
456 
457  // Use defaults set by jpeg_read_header()
458 
459  /* Step 5: Start decompressor */
460 
461  jpeg_start_decompress(&cinfo);
462 
463  /* JSAMPLEs per row in output buffer */
464  row_stride = cinfo.output_width * cinfo.output_components;
465  /* Make a one-row-high sample array that will go away when done with image */
466  buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1);
467 
468  /* Step 6: read scanlines */
469 
470  /* Here we use the library's state variable cinfo.output_scanline as the
471  * loop counter, so that we don't have to keep track ourselves.
472  */
473  while (cinfo.output_scanline < cinfo.output_height)
474  {
475  /* jpeg_read_scanlines expects an array of pointers to scanlines.
476  * Here the array is only one element long, but you could ask for
477  * more than one scanline at a time if that's more convenient.
478  */
479  jpeg_read_scanlines(&cinfo, buffer, 1);
480 
481  memcpy(img->pixels() + img->pitch()*(img->height() - cinfo.output_scanline), buffer[0], row_stride);
482  }
483 
484  /* Step 7: Finish decompression */
485 
486  jpeg_finish_decompress(&cinfo);
487 
488  /* Step 8: Release JPEG decompression object */
489 
490  /* This is an important step since it will release a good deal of memory. */
491  jpeg_destroy_decompress(&cinfo);
492 
493  /* After finish_decompress, we can close the input file.
494  * Here we postpone it until after no more JPEG errors are possible,
495  * so as to simplify the setjmp error logic above. (Actually, I don't
496  * think that jpeg_destroy can do an error exit, but why assume anything...)
497  */
498  file->close();
499 
500  return img;
501 }
502 //-----------------------------------------------------------------------------
504 {
505  ref<VirtualFile> file = defFileSystem()->locateFile(path);
506  if ( !file )
507  {
508  Log::error( Say("File '%s' not found.\n") << path );
509  return NULL;
510  }
511  else
512  return loadJPG(file.get());
513 }
514 //-----------------------------------------------------------------------------
516 {
517  file->open(OM_ReadOnly);
518  unsigned char sig1[] = { 0xFF, 0xD8, 0xFF, 0xE0 };
519  unsigned char sig2[] = { 0xFF, 0xD8, 0xFF, 0xE1 };
520  unsigned char signature[4];
521  file->read(signature,4);
522  file->close();
523  bool sig_ok = memcmp(sig1,signature,4) == 0 || memcmp(sig2,signature,4) == 0;
524  return sig_ok || (file->path().toLowerCase().endsWith(".jpg") || file->path().toLowerCase().endsWith(".jpeg"));
525 }
526 //-----------------------------------------------------------------------------
527 bool vl::saveJPG(const Image* src, const String& path, int quality)
528 {
529  ref<DiskFile> file = new DiskFile(path);
530  return saveJPG(src, file.get(), quality);
531 }
532 //-----------------------------------------------------------------------------
533 bool vl::saveJPG(const Image* src, VirtualFile* fout, int quality)
534 {
535  //if (src->dimension() != ID_2D )
536  //{
537  // Log::error( Say("saveJPG('%s'): can save only 2D images.\n") << fout->path() );
538  // return false;
539  //}
540 
541  int w = src->width();
542  int h = src->height();
543  int d = src->depth();
544  if (h == 0) h=1;
545  if (d == 0) d=1;
546  if (src->isCubemap()) d=6;
547  h = h*d;
548 
549  // convert src to IT_UNSIGNED_BYTE / IF_RGB
550  ref<Image> cimg;
551  if (src->type() != IT_UNSIGNED_BYTE)
552  {
553  cimg = src->convertType(IT_UNSIGNED_BYTE);
554  src = cimg.get();
555  if (!cimg)
556  {
557  Log::error( Say("saveJPG('%s'): could not convert image to IT_UNSIGNED_BYTE.\n") << fout->path() );
558  return false;
559  }
560  }
561  if (src->format() != IF_RGB)
562  {
563  cimg = src->convertFormat(IF_RGB);
564  src = cimg.get();
565  if (!cimg)
566  {
567  Log::error( Say("saveJPG('%s'): could not convert image to IF_RGB.\n") << fout->path() );
568  return false;
569  }
570  }
571 
572  if(!fout->open(OM_WriteOnly))
573  {
574  Log::error( Say("JPG: could not write to '%s'.\n") << fout->path() );
575  return false;
576  }
577 
578  /* This struct contains the JPEG compression parameters and pointers to
579  * working space (which is allocated as needed by the JPEG library).
580  * It is possible to have several such structures, representing multiple
581  * compression/decompression processes, in existence at once. We refer
582  * to any one struct (and its associated working data) as a "JPEG object".
583  */
584  struct jpeg_compress_struct cinfo;
585 
586  /* This struct represents a JPEG error handler. It is declared separately
587  * because applications often want to supply a specialized error handler
588  * (see the second half of this file for an example). But here we just
589  * take the easy way out and use the standard error handler, which will
590  * print a message on stderr and call exit() if compression fails.
591  * Note that this struct must live as long as the main JPEG parameter
592  * struct, to avoid dangling-pointer problems.
593  */
594  struct jpeg_error_mgr jerr;
595 
596  JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
597  int row_stride; /* physical row width in image buffer */
598 
599  /* Step 1: allocate and initialize JPEG compression object */
600 
601  /* We have to set up the error handler first, in case the initialization
602  * step fails. (Unlikely, but it could happen if you are out of memory.)
603  * This routine fills in the contents of struct jerr, and returns jerr's
604  * address which we place into the link field in cinfo.
605  */
606  cinfo.err = jpeg_std_error(&jerr);
607 
608  /* Now we can initialize the JPEG compression object. */
609  jpeg_create_compress(&cinfo);
610 
611  /* Step 2: specify data destination (eg, a file) */
612  /* Note: steps 2 and 3 can be done in either order. */
613 
615  // * stdio stream. You can also write your own code to do something else.
616  // * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
617  // * requires it in order to write binary files.
618  // */
619  //if ((outfile = fopen(filename, "wb")) == NULL) {
620  // fprintf(stderr, "can't open %s\n", filename);
621  // exit(1);
622  //}
623  //jpeg_stdio_dest(&cinfo, outfile);
624  jpeg_vl_dest(&cinfo, fout);
625 
626  /* Step 3: set parameters for compression */
627 
628  /* First we supply a description of the input image.
629  * Four fields of the cinfo struct must be filled in:
630  */
631  cinfo.image_width = w; /* image width and height, in pixels */
632  cinfo.image_height = h;
633  cinfo.input_components = 3; /* # of color components per pixel */
634  cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
635 
636  /* Now use the library's routine to set default compression parameters.
637  * (You must set at least cinfo.in_color_space before calling this,
638  * since the defaults depend on the source color space.)
639  */
640  jpeg_set_defaults(&cinfo);
641 
642  /* Now you can set any non-default parameters you wish to.
643  * Here we just illustrate the use of quality (quantization table) scaling: */
644  jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
645 
646  /* Step 4: Start compressor */
647 
648  /* TRUE ensures that we will write a complete interchange-JPEG file.
649  * Pass TRUE unless you are very sure of what you're doing.
650  */
651  jpeg_start_compress(&cinfo, TRUE);
652 
653  /* Step 5: while (scan lines remain to be written) */
654  /* jpeg_write_scanlines(...); */
655 
656  /* Here we use the library's state variable cinfo.next_scanline as the
657  * loop counter, so that we don't have to keep track ourselves.
658  * To keep things simple, we pass one scanline per call; you can pass
659  * more if you wish, though.
660  */
661  row_stride = w * 3; /* JSAMPLEs per row in image_buffer */
662 
663  while (cinfo.next_scanline < cinfo.image_height)
664  {
665  /* jpeg_write_scanlines expects an array of pointers to scanlines.
666  * Here the array is only one element long, but you could pass
667  * more than one scanline at a time if that's more convenient.
668  */
669  row_pointer[0] = (JSAMPROW)(src->pixels() + (h - 1 - cinfo.next_scanline) * row_stride);
670  jpeg_write_scanlines(&cinfo, row_pointer, 1);
671  }
672 
673  /* Step 6: Finish compression */
674 
675  jpeg_finish_compress(&cinfo);
676 
677  /* Step 7: release JPEG compression object */
678 
679  /* This is an important step since it will release a good deal of memory. */
680  jpeg_destroy_compress(&cinfo);
681 
682  /* And we're done! */
683 
684  fout->close();
685  return true;
686 }
687 //-----------------------------------------------------------------------------
String toLowerCase() const
Returns the lower-case version of a String.
Definition: String.cpp:755
long long read(void *buffer, long long byte_count)
Reads byte_count bytes from a file. Returns the number of bytes actually read.
Definition: VirtualFile.cpp:82
VLCORE_EXPORT FileSystem * defFileSystem()
Returns the default FileSystem used by VisualizationLibrary.
Definition: pimpl.cpp:97
int depth() const
Definition: Image.hpp:211
const T * get() const
Definition: Object.hpp:128
An abstract class representing a file.
Definition: VirtualFile.hpp:60
A simple String formatting class.
Definition: Say.hpp:124
const unsigned char * pixels() const
Raw pointer to pixels.
Definition: Image.hpp:170
void setObjectName(const char *name)
The name of the object, by default set to the object&#39;s class name in debug builds.
Definition: Object.hpp:220
The String class implements an advanced UTF16 (Unicode BMP) string manipulation engine.
Definition: String.hpp:62
ref< Image > convertType(EImageType new_type) const
Converts the type() of an image.
Definition: Image.cpp:1303
static void error(const String &message)
Use this function to provide information about run-time errors: file not found, out of memory...
Definition: Log.cpp:165
VLCORE_EXPORT ref< Image > loadJPG(VirtualFile *file)
Definition: ioJPG.cpp:396
virtual ref< VirtualFile > locateFile(const String &full_path, const String &alternate_path=String()) const
Looks for a VirtualFile on the disk and in the currently active FileSystem.
Definition: FileSystem.cpp:61
virtual void close()=0
Closes the file.
const String & path() const
Returns the path of the file.
Definition: VirtualFile.hpp:98
Visualization Library main namespace.
int height() const
Definition: Image.hpp:209
VLCORE_EXPORT bool isJPG(VirtualFile *file)
Definition: ioJPG.cpp:515
VLCORE_EXPORT bool saveJPG(const Image *src, const String &path, int quality=95)
Definition: ioJPG.cpp:527
int width() const
Definition: Image.hpp:207
virtual bool open(EOpenMode mode)=0
Opens the file in the specified mode.
int pitch() const
Definition: Image.hpp:213
#define NULL
Definition: OpenGLDefs.hpp:81
ref< Image > convertFormat(EImageFormat new_format) const
Converts the format() of an image.
Definition: Image.cpp:1719
#define INPUT_BUF_SIZE
Definition: ioJPG.cpp:69
A VirtualFile that operates on regular disk files.
Definition: DiskFile.hpp:64
EImageType type() const
Definition: Image.hpp:217
Implements a generic 1d, 2d, 3d and cubemap image that can have mipmaps.
Definition: Image.hpp:54
The ref<> class is used to reference-count an Object.
Definition: Object.hpp:55
void allocate2D(int x, int y, int bytealign, EImageFormat format, EImageType type)
Definition: Image.cpp:608
std::string toStdString() const
Returns a UTF8 encoded std::string.
Definition: String.cpp:1156
bool endsWith(const String &str) const
Returns true if a String ends with the specified String str.
Definition: String.cpp:705
#define VL_CHECK(expr)
Definition: checks.hpp:73
EImageFormat format() const
Definition: Image.hpp:215
bool isCubemap() const
Definition: Image.hpp:78
#define OUTPUT_BUF_SIZE
Definition: ioJPG.cpp:279