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

Revision 10963, 31.2 kB (checked in by robert, 5 years ago)

From Jean-Sebastien Guay, build fixes for Mingw

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