root/OpenSceneGraph/trunk/src/osgPlugins/jpeg/ReaderWriterJPEG.cpp @ 12545

Revision 12545, 31.9 kB (checked in by robert, 3 years ago)

Added disabling of VisualStudio? warning C4324 : structure was padded due to declspec(align())

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#include <osg/Image>
2#include <osg/Notify>
3#include <osg/Geode>
4#include <osg/GL>
5
6#include <osgDB/Registry>
7#include <osgDB/FileNameUtils>
8#include <osgDB/FileUtils>
9
10#include <sstream>
11
12#if defined(_MSC_VER) && defined(OSG_DISABLE_MSVC_WARNINGS)
13    // disable "structure was padded due to __declspec(align())
14    #pragma warning( disable : 4324 )
15#endif
16
17/****************************************************************************
18 *
19 * Follows is code extracted from the simage library.  Original Authors:
20 *
21 *      Systems in Motion,
22 *      <URL:http://www.sim.no>
23 *
24 *      Peder Blekken <pederb@sim.no>
25 *      Morten Eriksen <mortene@sim.no>
26 *      Marius Bugge Monsen <mariusbu@sim.no>
27 *
28 * The original COPYING notice
29 *
30 *      All files in this library are public domain, except simage_rgb.cpp which is
31 *      Copyright (c) Mark J Kilgard <mjk@nvidia.com>. I will contact Mark
32 *      very soon to hear if this source also can become public domain.
33 *
34 *      Please send patches for bugs and new features to: <pederb@sim.no>.
35 *
36 *      Peder Blekken
37 *
38 *
39 * Ported into the OSG as a plugin, Robert Osfield Decemeber 2000.
40 * Note, reference above to license of simage_rgb is not relevent to the OSG
41 * as the OSG does not use it.  Also for patches, bugs and new features
42 * please send them direct to the OSG dev team rather than address above.
43 *
44 **********************************************************************/
45
46/*
47 * Based on example code found in the libjpeg archive
48 *
49 */
50
51#include <stdio.h>
52
53extern "C"
54{
55    #include <jpeglib.h>
56    #include "jerror.h"
57}
58
59#include <setjmp.h>
60#include <string.h>
61#include <assert.h>
62#include <stdlib.h>
63
64#if defined(_MSC_VER) && defined(OSG_DISABLE_MSVC_WARNINGS)
65    #pragma warning( disable : 4611 )
66#endif
67
68namespace osgDBJPEG
69{
70
71#define ERR_NO_ERROR 0
72#define ERR_OPEN     1
73#define ERR_MEM      2
74#define ERR_JPEGLIB  3
75
76static int jpegerror = ERR_NO_ERROR;
77
78/* Some versions of jmorecfg.h define boolean, some don't...
79   Those that do also define HAVE_BOOLEAN, so we can guard using that. */
80#ifndef HAVE_BOOLEAN
81  typedef int boolean;
82  #define FALSE 0
83  #define TRUE 1
84#endif
85
86/* CODE FOR READING/WRITING JPEG FROM STREAMS
87 *  This code was taken directly from jdatasrc.c and jdatadst.c (libjpeg source)
88 *  and modified to use a std::istream/ostream* instead of a FILE*
89 */
90
91/* Expanded data source object for stdio input */
92
93typedef struct {
94    struct jpeg_source_mgr pub;    /* public fields */
95    std::istream * infile;        /* source stream */
96    JOCTET * buffer;              /* start of buffer */
97    boolean start_of_file;        /* have we gotten any data yet? */
98} stream_source_mgr;
99
100typedef stream_source_mgr * stream_src_ptr;
101
102#define INPUT_BUF_SIZE  4096    /* choose an efficiently fread'able size */
103
104/*
105 * Initialize source --- called by jpeg_read_header
106 * before any data is actually read.
107 */
108
109void init_source (j_decompress_ptr cinfo)
110{
111  stream_src_ptr src = (stream_src_ptr) cinfo->src;
112
113  /* We reset the empty-input-file flag for each image,
114   * but we don't clear the input buffer.
115   * This is correct behavior for reading a series of images from one source.
116   */
117  src->start_of_file = TRUE;
118}
119
120
121/*
122 * Fill the input buffer --- called whenever buffer is emptied.
123 *
124 * In typical applications, this should read fresh data into the buffer
125 * (ignoring the current state of next_input_byte & bytes_in_buffer),
126 * reset the pointer & count to the start of the buffer, and return TRUE
127 * indicating that the buffer has been reloaded.  It is not necessary to
128 * fill the buffer entirely, only to obtain at least one more byte.
129 *
130 * There is no such thing as an EOF return.  If the end of the file has been
131 * reached, the routine has a choice of ERREXIT() or inserting fake data into
132 * the buffer.  In most cases, generating a warning message and inserting a
133 * fake EOI marker is the best course of action --- this will allow the
134 * decompressor to output however much of the image is there.  However,
135 * the resulting error message is misleading if the real problem is an empty
136 * input file, so we handle that case specially.
137 *
138 * In applications that need to be able to suspend compression due to input
139 * not being available yet, a FALSE return indicates that no more data can be
140 * obtained right now, but more may be forthcoming later.  In this situation,
141 * the decompressor will return to its caller (with an indication of the
142 * number of scanlines it has read, if any).  The application should resume
143 * decompression after it has loaded more data into the input buffer.  Note
144 * that there are substantial restrictions on the use of suspension --- see
145 * the documentation.
146 *
147 * When suspending, the decompressor will back up to a convenient restart point
148 * (typically the start of the current MCU). next_input_byte & bytes_in_buffer
149 * indicate where the restart point will be if the current call returns FALSE.
150 * Data beyond this point must be rescanned after resumption, so move it to
151 * the front of the buffer rather than discarding it.
152 */
153
154boolean fill_input_buffer (j_decompress_ptr cinfo)
155{
156  stream_src_ptr src = (stream_src_ptr) cinfo->src;
157  size_t nbytes;
158
159  src->infile->read((char*)src->buffer,INPUT_BUF_SIZE);
160  nbytes = src->infile->gcount();
161
162  if (nbytes <= 0) {
163    if (src->start_of_file)    /* Treat empty input file as fatal error */
164      ERREXIT(cinfo, JERR_INPUT_EMPTY);
165    WARNMS(cinfo, JWRN_JPEG_EOF);
166    /* Insert a fake EOI marker */
167    src->buffer[0] = (JOCTET) 0xFF;
168    src->buffer[1] = (JOCTET) JPEG_EOI;
169    nbytes = 2;
170  }
171
172  src->pub.next_input_byte = src->buffer;
173  src->pub.bytes_in_buffer = nbytes;
174  src->start_of_file = FALSE;
175
176  return TRUE;
177}
178
179
180/*
181 * Skip data --- used to skip over a potentially large amount of
182 * uninteresting data (such as an APPn marker).
183 *
184 * Writers of suspendable-input applications must note that skip_input_data
185 * is not granted the right to give a suspension return.  If the skip extends
186 * beyond the data currently in the buffer, the buffer can be marked empty so
187 * that the next read will cause a fill_input_buffer call that can suspend.
188 * Arranging for additional bytes to be discarded before reloading the input
189 * buffer is the application writer's problem.
190 */
191
192void skip_input_data (j_decompress_ptr cinfo, long num_bytes)
193{
194  stream_src_ptr src = (stream_src_ptr) cinfo->src;
195
196  /* Just a dumb implementation for now.  Could use fseek() except
197   * it doesn't work on pipes.  Not clear that being smart is worth
198   * any trouble anyway --- large skips are infrequent.
199   */
200  if (num_bytes > 0) {
201    while (num_bytes > (long) src->pub.bytes_in_buffer) {
202      num_bytes -= (long) src->pub.bytes_in_buffer;
203      (void) fill_input_buffer(cinfo);
204      /* note we assume that fill_input_buffer will never return FALSE,
205       * so suspension need not be handled.
206       */
207    }
208    src->pub.next_input_byte += (size_t) num_bytes;
209    src->pub.bytes_in_buffer -= (size_t) num_bytes;
210  }
211}
212
213
214/*
215 * An additional method that can be provided by data source modules is the
216 * resync_to_restart method for error recovery in the presence of RST markers.
217 * For the moment, this source module just uses the default resync method
218 * provided by the JPEG library.  That method assumes that no backtracking
219 * is possible.
220 */
221
222
223/*
224 * Terminate source --- called by jpeg_finish_decompress
225 * after all data has been read.  Often a no-op.
226 *
227 * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
228 * application must deal with any cleanup that should happen even
229 * for error exit.
230 */
231void term_source (j_decompress_ptr /*cinfo*/)
232{
233  /* no work necessary here */
234}
235
236void jpeg_istream_src(j_decompress_ptr cinfo, std::istream *infile)
237{
238    stream_src_ptr src;
239
240    /* The source object and input buffer are made permanent so that a series
241     * of JPEG images can be read from the same file by calling jpeg_stdio_src
242     * only before the first one.  (If we discarded the buffer at the end of
243     * one image, we'd likely lose the start of the next one.)
244     * This makes it unsafe to use this manager and a different source
245     * manager serially with the same JPEG object.  Caveat programmer.
246     */
247    if (cinfo->src == NULL) {    /* first time for this JPEG object? */
248        cinfo->src = (struct jpeg_source_mgr *)
249            (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,sizeof(stream_source_mgr));
250        src = (stream_src_ptr) cinfo->src;
251        src->buffer = (JOCTET *)
252            (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,INPUT_BUF_SIZE * sizeof(JOCTET));
253    }
254
255    src = (stream_src_ptr) cinfo->src;
256    src->pub.init_source = init_source;
257    src->pub.fill_input_buffer = fill_input_buffer;
258    src->pub.skip_input_data = skip_input_data;
259    src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
260    src->pub.term_source = term_source;
261    src->infile = infile;
262    src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
263    src->pub.next_input_byte = NULL; /* until buffer loaded */
264}
265
266/* Expanded data destination object for stdio output */
267
268typedef struct {
269  struct jpeg_destination_mgr pub; /* public fields */
270
271  std::ostream * outfile;    /* target stream */
272  JOCTET * buffer;          /* start of buffer */
273} stream_destination_mgr;
274
275typedef stream_destination_mgr * stream_dest_ptr;
276
277#define OUTPUT_BUF_SIZE  4096    /* choose an efficiently fwrite'able size */
278
279
280/*
281 * Initialize destination --- called by jpeg_start_compress
282 * before any data is actually written.
283 */
284
285void init_destination (j_compress_ptr cinfo)
286{
287  stream_dest_ptr dest = (stream_dest_ptr) cinfo->dest;
288
289  /* Allocate the output buffer --- it will be released when done with image */
290  dest->buffer = (JOCTET *)
291      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, OUTPUT_BUF_SIZE * sizeof(JOCTET));
292
293  dest->pub.next_output_byte = dest->buffer;
294  dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
295}
296
297
298/*
299 * Empty the output buffer --- called whenever buffer fills up.
300 *
301 * In typical applications, this should write the entire output buffer
302 * (ignoring the current state of next_output_byte & free_in_buffer),
303 * reset the pointer & count to the start of the buffer, and return TRUE
304 * indicating that the buffer has been dumped.
305 *
306 * In applications that need to be able to suspend compression due to output
307 * overrun, a FALSE return indicates that the buffer cannot be emptied now.
308 * In this situation, the compressor will return to its caller (possibly with
309 * an indication that it has not accepted all the supplied scanlines).  The
310 * application should resume compression after it has made more room in the
311 * output buffer.  Note that there are substantial restrictions on the use of
312 * suspension --- see the documentation.
313 *
314 * When suspending, the compressor will back up to a convenient restart point
315 * (typically the start of the current MCU). next_output_byte & free_in_buffer
316 * indicate where the restart point will be if the current call returns FALSE.
317 * Data beyond this point will be regenerated after resumption, so do not
318 * write it out when emptying the buffer externally.
319 */
320
321boolean empty_output_buffer (j_compress_ptr cinfo)
322{
323  stream_dest_ptr dest = (stream_dest_ptr) cinfo->dest;
324
325  dest->outfile->write((const char*)dest->buffer,OUTPUT_BUF_SIZE);
326  if (dest->outfile->bad())
327    ERREXIT(cinfo, JERR_FILE_WRITE);
328
329  dest->pub.next_output_byte = dest->buffer;
330  dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
331
332  return TRUE;
333}
334
335
336/*
337 * Terminate destination --- called by jpeg_finish_compress
338 * after all data has been written.  Usually needs to flush buffer.
339 *
340 * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
341 * application must deal with any cleanup that should happen even
342 * for error exit.
343 */
344
345void term_destination (j_compress_ptr cinfo)
346{
347  stream_dest_ptr dest = (stream_dest_ptr) cinfo->dest;
348  size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
349
350  /* Write any data remaining in the buffer */
351  if (datacount > 0) {
352    dest->outfile->write((const char*)dest->buffer,datacount);
353    if (dest->outfile->bad())
354      ERREXIT(cinfo, JERR_FILE_WRITE);
355  }
356  dest->outfile->flush();
357  /* Make sure we wrote the output file OK */
358  if (dest->outfile->bad())
359    ERREXIT(cinfo, JERR_FILE_WRITE);
360}
361
362
363/*
364 * Prepare for output to a stdio stream.
365 * The caller must have already opened the stream, and is responsible
366 * for closing it after finishing compression.
367 */
368
369void jpeg_stream_dest (j_compress_ptr cinfo, std::ostream * outfile)
370{
371    stream_dest_ptr dest;
372
373    /* The destination object is made permanent so that multiple JPEG images
374     * can be written to the same file without re-executing jpeg_stdio_dest.
375     * This makes it dangerous to use this manager and a different destination
376     * manager serially with the same JPEG object, because their private object
377     * sizes may be different.  Caveat programmer.
378     */
379    if (cinfo->dest == NULL) {    /* first time for this JPEG object? */
380        cinfo->dest = (struct jpeg_destination_mgr *)
381            (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(stream_destination_mgr));
382    }
383
384    dest = (stream_dest_ptr) cinfo->dest;
385    dest->pub.init_destination = init_destination;
386    dest->pub.empty_output_buffer = empty_output_buffer;
387    dest->pub.term_destination = term_destination;
388    dest->outfile = outfile;
389}
390
391/* END OF READ/WRITE STREAM CODE */
392
393int
394simage_jpeg_error(char * buffer, int buflen)
395{
396    switch (jpegerror)
397    {
398        case ERR_OPEN:
399            strncpy(buffer, "JPEG loader: Error opening file", buflen);
400            break;
401        case ERR_MEM:
402            strncpy(buffer, "JPEG loader: Out of memory error", buflen);
403            break;
404        case ERR_JPEGLIB:
405            strncpy(buffer, "JPEG loader: Illegal jpeg file", buflen);
406            break;
407    }
408    return jpegerror;
409}
410
411
412struct my_error_mgr
413{
414    struct jpeg_error_mgr pub;   /* "public" fields */
415
416    jmp_buf setjmp_buffer;       /* for return to caller */
417};
418
419typedef struct my_error_mgr * my_error_ptr;
420
421static void
422my_error_exit (j_common_ptr cinfo)
423{
424    /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
425    my_error_ptr myerr = (my_error_ptr) cinfo->err;
426
427    /* Always display the message. */
428    /* We could postpone this until after returning, if we chose. */
429    /*(*cinfo->err->output_message) (cinfo);*/
430
431    /* FIXME: get error messahe from jpeglib */
432
433    /* Return control to the setjmp point */
434    longjmp(myerr->setjmp_buffer, 1);
435}
436
437static void
438my_output_message (j_common_ptr cinfo)
439{
440  char buffer[JMSG_LENGTH_MAX];
441
442  /* Create the message */
443  (*cinfo->err->format_message) (cinfo, buffer);
444
445  OSG_WARN<<buffer<<std::endl;
446}
447
448
449int
450simage_jpeg_identify(const char *,
451const unsigned char *header,
452int headerlen)
453{
454    static unsigned char jpgcmp[] = {'J', 'F', 'I', 'F' };
455    if (headerlen < 4) return 0;
456    if (memcmp((const void*)&header[6],
457        (const void*)jpgcmp, 4) == 0) return 1;
458    return 0;
459}
460
461
462static unsigned char*
463copyScanline(unsigned char *currPtr, unsigned char *from, int cnt)
464{
465    memcpy((void*)currPtr, (void*)from, cnt);
466    currPtr -= cnt;
467    return currPtr;
468}
469
470unsigned char *
471simage_jpeg_load(std::istream& fin,
472int *width_ret,
473int *height_ret,
474int *numComponents_ret)
475{
476    int width;
477    int height;
478    unsigned char *currPtr;
479    int format;
480    /* This struct contains the JPEG decompression parameters and pointers to
481     * working space (which is allocated as needed by the JPEG library).
482     */
483    struct jpeg_decompress_struct cinfo;
484    /* We use our private extension JPEG error handler.
485     * Note that this struct must live as long as the main JPEG parameter
486     * struct, to avoid dangling-pointer problems.
487     */
488    struct my_error_mgr jerr;
489    /* More stuff */
490    //FILE * infile;               /* source file */
491    JSAMPARRAY rowbuffer;        /* Output row buffer */
492    int row_stride;              /* physical row width in output buffer */
493
494    jpegerror = ERR_NO_ERROR;
495
496    /* In this example we want to open the input file before doing anything else,
497     * so that the setjmp() error recovery below can assume the file is open.
498     * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
499     * requires it in order to read binary files.
500     */
501
502    /*if ((infile = fopen(filename, "rb")) == NULL)
503    {
504        jpegerror = ERR_OPEN;
505        return NULL;
506    }*/
507
508    /* Step 1: allocate and initialize JPEG decompression object */
509
510    /* We set up the normal JPEG error routines, then override error_exit. */
511    cinfo.err = jpeg_std_error(&jerr.pub);
512    jerr.pub.error_exit = my_error_exit;
513    jerr.pub.output_message = my_output_message;
514    /* Establish the setjmp return context for my_error_exit to use. */
515    if (setjmp(jerr.setjmp_buffer))
516    {
517        /* If we get here, the JPEG code has signaled an error.
518         * We need to clean up the JPEG object, close the input file, and return.
519         */
520        jpegerror = ERR_JPEGLIB;
521        jpeg_destroy_decompress(&cinfo);
522        //fclose(infile);
523        //if (buffer) delete [] buffer;
524        return NULL;
525    }
526
527    // used to be before setjump above, but have moved to after to avoid compile warnings.
528    unsigned char *buffer = NULL;
529
530    /* Now we can initialize the JPEG decompression object. */
531    jpeg_create_decompress(&cinfo);
532
533    /* Step 2: specify data source (eg, a file) */
534
535    //jpeg_stdio_src(&cinfo, infile);
536    jpeg_istream_src(&cinfo,&fin);
537
538    /* Step 3: read file parameters with jpeg_read_header() */
539
540    (void) jpeg_read_header(&cinfo, TRUE);
541    /* We can ignore the return value from jpeg_read_header since
542     *   (a) suspension is not possible with the stdio data source, and
543     *   (b) we passed TRUE to reject a tables-only JPEG file as an error.
544     * See libjpeg.doc for more info.
545     */
546
547    /* Step 4: set parameters for decompression */
548    /* In this example, we don't need to change any of the defaults set by
549     * jpeg_read_header(), so we do nothing here.
550     */
551
552    /* Step 5: Start decompressor */
553    if (cinfo.jpeg_color_space == JCS_GRAYSCALE)
554    {
555        format = 1;
556        cinfo.out_color_space = JCS_GRAYSCALE;
557    }
558    else                         /* use rgb */
559    {
560        format = 3;
561        cinfo.out_color_space = JCS_RGB;
562    }
563
564    (void) jpeg_start_decompress(&cinfo);
565    /* We can ignore the return value since suspension is not possible
566     * with the stdio data source.
567     */
568
569    /* We may need to do some setup of our own at this point before reading
570     * the data.  After jpeg_start_decompress() we have the correct scaled
571     * output image dimensions available, as well as the output colormap
572     * if we asked for color quantization.
573     * In this example, we need to make an output work buffer of the right size.
574     */
575    /* JSAMPLEs per row in output buffer */
576    row_stride = cinfo.output_width * cinfo.output_components;
577    /* Make a one-row-high sample array that will go away when done with image */
578    rowbuffer = (*cinfo.mem->alloc_sarray)
579        ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
580    width = cinfo.output_width;
581    height = cinfo.output_height;
582    buffer = currPtr = new unsigned char [width*height*cinfo.output_components];
583
584    /* Step 6: while (scan lines remain to be read) */
585    /*           jpeg_read_scanlines(...); */
586
587    /* Here we use the library's state variable cinfo.output_scanline as the
588     * loop counter, so that we don't have to keep track ourselves.
589     */
590
591    /* flip image upside down */
592    if (buffer)
593    {
594        currPtr = buffer + row_stride * (cinfo.output_height-1);
595
596        while (cinfo.output_scanline < cinfo.output_height)
597        {
598            /* jpeg_read_scanlines expects an array of pointers to scanlines.
599             * Here the array is only one element long, but you could ask for
600             * more than one scanline at a time if that's more convenient.
601             */
602            (void) jpeg_read_scanlines(&cinfo, rowbuffer, 1);
603            /* Assume put_scanline_someplace wants a pointer and sample count. */
604            currPtr = copyScanline(currPtr, rowbuffer[0], row_stride);
605        }
606    }
607    /* Step 7: Finish decompression */
608
609    (void) jpeg_finish_decompress(&cinfo);
610    /* We can ignore the return value since suspension is not possible
611     * with the stdio data source.
612     */
613
614    /* Step 8: Release JPEG decompression object */
615
616    /* This is an important step since it will release a good deal of memory. */
617    jpeg_destroy_decompress(&cinfo);
618
619    /* After finish_decompress, we can close the input file.
620     * Here we postpone it until after no more JPEG errors are possible,
621     * so as to simplify the setjmp error logic above.  (Actually, I don't
622     * think that jpeg_destroy can do an error exit, but why assume anything...)
623     */
624    //fclose(infile);
625
626    /* At this point you may want to check to see whether any corrupt-data
627     * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
628     */
629
630    /* And we're done! */
631    if (buffer)
632    {
633        *width_ret = width;
634        *height_ret = height;
635        *numComponents_ret = format;
636    }
637    else
638    {
639        jpegerror = ERR_MEM;
640    }
641    return buffer;
642}
643} // namespace osgDBJPEG
644
645class ReaderWriterJPEG : public osgDB::ReaderWriter
646{
647
648        WriteResult::WriteStatus write_JPEG_file (std::ostream &fout, const osg::Image &img, int quality = 100) const
649        {
650            int image_width = img.s();
651            int image_height = img.t();
652            if ( (image_width == 0) || (image_height == 0) )
653            {
654                OSG_DEBUG << "ReaderWriterJPEG::write_JPEG_file - Error no size" << std::endl;
655                return WriteResult::ERROR_IN_WRITING_FILE;
656            }
657
658            J_COLOR_SPACE image_color_space = JCS_RGB;
659            int image_components = 3;
660            // Only cater for gray, alpha and RGB for now
661            switch(img.getPixelFormat()) {
662              case(GL_LUMINANCE):
663              case(GL_ALPHA): {
664                  image_color_space = JCS_GRAYSCALE;
665                  image_components = 1;
666                  break;
667              }
668              case(GL_RGB): {
669                  image_color_space = JCS_RGB;
670                  image_components = 3;
671                  break;
672              }
673              default:
674              {
675                  OSG_DEBUG << "ReaderWriterJPEG::write_JPEG_file - Error pixel format non supported" << std::endl;
676                return WriteResult::ERROR_IN_WRITING_FILE; break;             
677              }
678            }
679
680            JSAMPLE* image_buffer = (JSAMPLE*)(img.data());
681
682            /* This struct contains the JPEG compression parameters and pointers to
683            * working space (which is allocated as needed by the JPEG library).
684            * It is possible to have several such structures, representing multiple
685            * compression/decompression processes, in existence at once.  We refer
686            * to any one struct (and its associated working data) as a "JPEG object".
687            */
688            struct jpeg_compress_struct cinfo;
689            /* This struct represents a JPEG error handler.  It is declared separately
690            * because applications often want to supply a specialized error handler
691            * (see the second half of this file for an example).  But here we just
692            * take the easy way out and use the standard error handler, which will
693            * print a message on stderr and call exit() if compression fails.
694            * Note that this struct must live as long as the main JPEG parameter
695            * struct, to avoid dangling-pointer problems.
696            */
697            struct jpeg_error_mgr jerr;
698            /* More stuff */
699            //FILE * outfile;        /* target file */
700            JSAMPROW row_pointer[1];    /* pointer to JSAMPLE row[s] */
701            int row_stride;        /* physical row width in image buffer */
702
703            /* Step 1: allocate and initialize JPEG compression object */
704
705            /* We have to set up the error handler first, in case the initialization
706            * step fails.  (Unlikely, but it could happen if you are out of memory.)
707            * This routine fills in the contents of struct jerr, and returns jerr's
708            * address which we place into the link field in cinfo.
709            */
710            cinfo.err = jpeg_std_error(&jerr);
711            /* Now we can initialize the JPEG compression object. */
712            jpeg_create_compress(&cinfo);
713
714            /* Step 2: specify data destination (eg, a file) */
715            /* Note: steps 2 and 3 can be done in either order. */
716
717            /* Here we use the library-supplied code to send compressed data to a
718            * stdio stream.  You can also write your own code to do something else.
719            * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
720            * requires it in order to write binary files.
721            */
722            /*if (!(outfile = fopen(filename, "wb")))
723            {
724                return WriteResult::ERROR_IN_WRITING_FILE;
725            }*/
726   
727            //jpeg_stdio_dest(&cinfo, outfile);
728            osgDBJPEG::jpeg_stream_dest(&cinfo, &fout);
729
730            /* Step 3: set parameters for compression */
731
732            /* First we supply a description of the input image.
733            * Four fields of the cinfo struct must be filled in:
734            */
735            cinfo.image_width = image_width;     /* image width and height, in pixels */
736            cinfo.image_height = image_height;
737            cinfo.input_components = image_components;        /* # of color components per pixel */
738            cinfo.in_color_space = image_color_space;     /* colorspace of input image */
739            /* Now use the library's routine to set default compression parameters.
740            * (You must set at least cinfo.in_color_space before calling this,
741            * since the defaults depend on the source color space.)
742            */
743            jpeg_set_defaults(&cinfo);
744            /* Now you can set any non-default parameters you wish to.
745            * Here we just illustrate the use of quality (quantization table) scaling:
746            */
747            jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
748
749            /* Step 4: Start compressor */
750
751            /* TRUE ensures that we will write a complete interchange-JPEG file.
752            * Pass TRUE unless you are very sure of what you're doing.
753            */
754            jpeg_start_compress(&cinfo, TRUE);
755
756            /* Step 5: while (scan lines remain to be written) */
757            /*           jpeg_write_scanlines(...); */
758
759            /* Here we use the library's state variable cinfo.next_scanline as the
760            * loop counter, so that we don't have to keep track ourselves.
761            * To keep things simple, we pass one scanline per call; you can pass
762            * more if you wish, though.
763            */
764            row_stride = image_width * image_components;    /* JSAMPLEs per row in image_buffer */
765
766            while (cinfo.next_scanline < cinfo.image_height)
767            {
768                /* jpeg_write_scanlines expects an array of pointers to scanlines.
769                * Here the array is only one element long, but you could pass
770                * more than one scanline at a time if that's more convenient.
771                */
772                row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];
773                (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
774            }
775
776            /* Step 6: Finish compression */
777
778            jpeg_finish_compress(&cinfo);
779            /* After finish_compress, we can close the output file. */
780            //fclose(outfile);
781
782            /* Step 7: release JPEG compression object */
783
784            /* This is an important step since it will release a good deal of memory. */
785            jpeg_destroy_compress(&cinfo);
786
787            /* And we're done! */
788            return WriteResult::FILE_SAVED;
789        }
790        int getQuality(const osgDB::ReaderWriter::Options *options) const {
791            if(options) {
792                std::istringstream iss(options->getOptionString());
793                std::string opt;
794                while (iss >> opt) {
795                    if(opt=="JPEG_QUALITY") {
796                        int quality;
797                        iss >> quality;
798                        return quality;
799                    }
800                }
801            }
802
803            return 100;
804        }
805    public:
806
807        ReaderWriterJPEG()
808        {
809            supportsExtension("jpeg","JPEG image format");
810            supportsExtension("jpg","JPEG image format");
811        }
812
813        virtual const char* className() const { return "JPEG Image Reader/Writer"; }
814
815        ReadResult readJPGStream(std::istream& fin) const
816        {
817            unsigned char *imageData = NULL;
818            int width_ret;
819            int height_ret;
820            int numComponents_ret;
821
822            imageData = osgDBJPEG::simage_jpeg_load(fin,&width_ret,&height_ret,&numComponents_ret);
823
824            if (imageData==NULL) return ReadResult::ERROR_IN_READING_FILE;
825
826            int s = width_ret;
827            int t = height_ret;
828            int r = 1;
829
830            //int internalFormat = numComponents_ret;
831            int internalFormat =
832                numComponents_ret == 1 ? GL_LUMINANCE :
833                numComponents_ret == 2 ? GL_LUMINANCE_ALPHA :
834                numComponents_ret == 3 ? GL_RGB :
835                numComponents_ret == 4 ? GL_RGBA : (GLenum)-1;
836
837            unsigned int pixelFormat =
838                numComponents_ret == 1 ? GL_LUMINANCE :
839                numComponents_ret == 2 ? GL_LUMINANCE_ALPHA :
840                numComponents_ret == 3 ? GL_RGB :
841                numComponents_ret == 4 ? GL_RGBA : (GLenum)-1;
842
843            unsigned int dataType = GL_UNSIGNED_BYTE;
844
845            osg::Image* pOsgImage = new osg::Image;
846            pOsgImage->setImage(s,t,r,
847                internalFormat,
848                pixelFormat,
849                dataType,
850                imageData,
851                osg::Image::USE_NEW_DELETE);
852
853            return pOsgImage;
854        }
855
856        virtual ReadResult readObject(std::istream& fin,const osgDB::ReaderWriter::Options* options =NULL) const
857        {
858            return readImage(fin, options);
859        }
860
861        virtual ReadResult readObject(const std::string& file, const osgDB::ReaderWriter::Options* options =NULL) const
862        {
863            return readImage(file, options);
864        }
865
866        virtual ReadResult readImage(std::istream& fin,const osgDB::ReaderWriter::Options* =NULL) const
867        {
868            return readJPGStream(fin);
869        }
870
871        virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const
872        {
873            std::string ext = osgDB::getLowerCaseFileExtension(file);
874            if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
875
876            std::string fileName = osgDB::findDataFile( file, options );
877            if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
878
879            osgDB::ifstream istream(fileName.c_str(), std::ios::in | std::ios::binary);
880            if(!istream) return ReadResult::ERROR_IN_READING_FILE;
881            ReadResult rr = readJPGStream(istream);
882            if(rr.validImage()) rr.getImage()->setFileName(file);
883            return rr;
884        }
885
886        virtual WriteResult writeImage(const osg::Image& img,std::ostream& fout,const osgDB::ReaderWriter::Options *options) const
887        {
888            osg::ref_ptr<osg::Image> tmp_img = new osg::Image(img);
889            tmp_img->flipVertical();
890            WriteResult::WriteStatus ws = write_JPEG_file(fout, *(tmp_img.get()), getQuality(options));
891            return ws;
892        }
893
894        virtual WriteResult writeImage(const osg::Image &img,const std::string& fileName, const osgDB::ReaderWriter::Options *options) const
895        {
896            std::string ext = osgDB::getFileExtension(fileName);
897            if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;
898
899            osgDB::ofstream fout(fileName.c_str(), std::ios::out | std::ios::binary);
900            if(!fout) return WriteResult::ERROR_IN_WRITING_FILE;
901
902            return writeImage(img,fout,options);
903        }
904};
905
906// now register with Registry to instantiate the above
907// reader/writer.
908REGISTER_OSGPLUGIN(jpeg, ReaderWriterJPEG)
Note: See TracBrowser for help on using the browser.