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

Revision 10496, 31.0 kB (checked in by robert, 5 years ago)

From J.P. Delport, "attached a modified jpeg plugin that allows writing of grayscale images."

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