1 /*---------------------------------------------------------------------------*\
5 * Copyright (C) 2000-2002 by the OpenSG Forum *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
37 \*---------------------------------------------------------------------------*/
42 #include "OSGConfig.h"
60 #include "OSGJPGImageFileType.h"
65 # define OSG_JPG_ARG(ARG) ARG
67 # define OSG_JPG_ARG(ARG)
70 # define OSG_JPG_ARG(ARG) ARG
73 // Static Class Varible implementations:
74 static const OSG::Char8
*suffixArray
[] = { "jpg",
81 /*! \class JPGImageFileType
83 Image File Type to read/write and store/restore Image objects as
86 To be able to load JPEG images you need the IJG JPEG library,
87 version 6 or later (check the Prerequisites page on www.opensg.org).
88 The lib comes with all Linux distributions.
90 You have to --enable-jpg in the configure line to enable
97 static const unsigned long BUFFERSIZE
= 4096;
101 struct jpeg_source_mgr pub
;
104 SourceManager(j_decompress_ptr cinfo
, std::istream
&iStream
);
107 static void istream_init_source(j_decompress_ptr cinfo
)
109 } // no action necessary
111 static boolean
istream_fill_input_buffer(j_decompress_ptr cinfo
)
113 SourceManager
*sourceManager
=
114 reinterpret_cast<SourceManager
*>(cinfo
->src
);
116 sourceManager
->is
->read(sourceManager
->buffer
, BUFFERSIZE
);
118 cinfo
->src
->next_input_byte
=
119 reinterpret_cast<const JOCTET
*>(sourceManager
->buffer
);
121 if (sourceManager
->is
->gcount() == 0)
123 /* Insert a fake EOI marker */
124 sourceManager
->buffer
[0] = JOCTET(0xFF);
125 sourceManager
->buffer
[1] = JOCTET(JPEG_EOI
);
126 cinfo
->src
->bytes_in_buffer
= 2;
130 cinfo
->src
->bytes_in_buffer
= sourceManager
->is
->gcount();
136 static void istream_skip_input_data(j_decompress_ptr cinfo
, long num_bytes
)
138 if (static_cast<unsigned long>(num_bytes
) <= cinfo
->src
->bytes_in_buffer
)
140 cinfo
->src
->bytes_in_buffer
-= num_bytes
;
141 cinfo
->src
->next_input_byte
+= num_bytes
;
145 num_bytes
-= long(cinfo
->src
->bytes_in_buffer
);
146 SourceManager
*sourceManager
=
147 reinterpret_cast<SourceManager
*>(cinfo
->src
);
148 sourceManager
->is
->ignore(num_bytes
);
149 cinfo
->src
->bytes_in_buffer
= 0;
150 cinfo
->src
->next_input_byte
= 0;
154 static void istream_term_source(j_decompress_ptr cinfo
) {} // no action necessary
156 SourceManager::SourceManager(j_decompress_ptr cinfo
, std::istream
&iStream
):
161 pub
.init_source
= istream_init_source
;
162 pub
.fill_input_buffer
= istream_fill_input_buffer
;
163 pub
.skip_input_data
= istream_skip_input_data
;
164 pub
.resync_to_restart
= jpeg_resync_to_restart
; /* use default method */
165 pub
.term_source
= istream_term_source
;
166 pub
.bytes_in_buffer
= 0; /* forces fill_input_buffer on first read */
167 pub
.next_input_byte
= 0; /* until buffer loaded */
169 buffer
= static_cast<char*>((*cinfo
->mem
->alloc_small
)(j_common_ptr(cinfo
),
174 struct DestinationManager
176 struct jpeg_destination_mgr pub
;
179 DestinationManager(j_compress_ptr cinfo
, std::ostream
&oStream
);
182 static void ostream_init_destination(j_compress_ptr cinfo
)
184 DestinationManager
* dest
=
185 reinterpret_cast<DestinationManager
*>(cinfo
->dest
);
187 // Allocate the output buffer --- it will be released when done with image
188 dest
->buffer
= static_cast<char *>(
189 (*cinfo
->mem
->alloc_small
)(j_common_ptr(cinfo
), JPOOL_IMAGE
,
190 BUFFERSIZE
* sizeof(char)));
192 dest
->pub
.next_output_byte
= reinterpret_cast<JOCTET
*>(dest
->buffer
);
193 dest
->pub
.free_in_buffer
= BUFFERSIZE
;
196 static boolean
ostream_empty_output_buffer(j_compress_ptr cinfo
)
198 DestinationManager
*destinationManager
=
199 reinterpret_cast<DestinationManager
*>(cinfo
->dest
);
201 destinationManager
->os
->write(
202 static_cast<char *>(destinationManager
->buffer
),
205 destinationManager
->pub
.next_output_byte
=
206 reinterpret_cast<JOCTET
*>(destinationManager
->buffer
);
207 destinationManager
->pub
.free_in_buffer
= BUFFERSIZE
;
209 return destinationManager
->os
->good() != false ? TRUE
: FALSE
;
212 static void ostream_term_destination(j_compress_ptr cinfo
)
214 DestinationManager
* dest
=
215 reinterpret_cast<DestinationManager
*>(cinfo
->dest
);
217 size_t datacount
= BUFFERSIZE
- dest
->pub
.free_in_buffer
;
218 // Write any data remaining in the buffer
221 dest
->os
->write(static_cast<char *>(dest
->buffer
), datacount
);
225 DestinationManager::DestinationManager(j_compress_ptr cinfo
,
226 std::ostream
&oStream
):
231 pub
.init_destination
= ostream_init_destination
;
232 pub
.empty_output_buffer
= ostream_empty_output_buffer
;
233 pub
.term_destination
= ostream_term_destination
;
235 buffer
= static_cast<char *>(
236 (*cinfo
->mem
->alloc_small
)(j_common_ptr(cinfo
),
239 pub
.free_in_buffer
= BUFFERSIZE
;
240 pub
.next_output_byte
= reinterpret_cast<JOCTET
*>(buffer
);
243 struct osg_jpeg_error_mgr
245 struct jpeg_error_mgr pub
;
246 jmp_buf setjmp_buffer
;
249 static void osg_jpeg_error_exit(j_common_ptr cinfo
)
251 /* Always display the message */
252 (*cinfo
->err
->output_message
) (cinfo
);
254 /* Let the memory manager delete any temp files before we die */
257 /* Return control to the setjmp point */
258 struct osg_jpeg_error_mgr
*osgerr
=
259 reinterpret_cast<struct osg_jpeg_error_mgr
*>(cinfo
->err
);
260 longjmp(osgerr
->setjmp_buffer
, 1);
263 static void osg_jpeg_output_message(j_common_ptr cinfo
)
265 char buffer
[JMSG_LENGTH_MAX
];
267 /* Create the message */
268 (*cinfo
->err
->format_message
) (cinfo
, buffer
);
270 /* Send it to the OSG logger, adding a newline */
271 FFATAL (("JPG: %s\n", buffer
));
276 struct jpeg_destination_mgr dest
;
277 struct jpeg_source_mgr src
;
284 static void jpeg_mem_init_source(j_decompress_ptr
OSG_CHECK_ARG(cinfo
))
286 jpeg_mem
.src
.next_input_byte
= static_cast<JOCTET
*>(jpeg_mem
.buffer
);
287 jpeg_mem
.src
.bytes_in_buffer
= size_t(jpeg_mem
.dataSize
);
292 static boolean
jpeg_mem_fill_input_buffer(
293 j_decompress_ptr
OSG_CHECK_ARG(cinfo
))
295 SFATAL
<< "Missing data. Given data block to small." << std::endl
;
300 static void jpeg_mem_skip_input_data(j_decompress_ptr
OSG_CHECK_ARG(cinfo
),
303 jpeg_mem
.src
.next_input_byte
+= num_bytes
;
304 jpeg_mem
.src
.bytes_in_buffer
-= num_bytes
;
308 static boolean
jpeg_mem_resync_to_restart(
309 j_decompress_ptr
OSG_CHECK_ARG(cinfo
),
310 int OSG_CHECK_ARG(desired
))
316 static void jpeg_mem_term_source(j_decompress_ptr
OSG_CHECK_ARG(cinfo
))
321 static void jpeg_mem_init_destination(j_compress_ptr
OSG_CHECK_ARG(cinfo
))
323 jpeg_mem
.dest
.next_output_byte
= static_cast<JOCTET
*>(jpeg_mem
.buffer
);
324 jpeg_mem
.dest
.free_in_buffer
= size_t(jpeg_mem
.memSize
);
328 static boolean
jpeg_mem_empty_output_buffer(
329 j_compress_ptr
OSG_CHECK_ARG(cinfo
))
331 SFATAL
<< "Not enough space left in buffer." << std::endl
;
336 static void jpeg_mem_term_destination(j_compress_ptr
OSG_CHECK_ARG(cinfo
))
339 (static_cast<UChar8
*>(jpeg_mem
.dest
.next_output_byte
)) -
340 (static_cast<UChar8
*>(jpeg_mem
.buffer
));
344 static void jpeg_memory_dest(struct jpeg_compress_struct
*cinfo
,
348 jpeg_mem
.buffer
=buffer
;
349 jpeg_mem
.memSize
=memSize
;
350 jpeg_mem
.dest
.init_destination
= jpeg_mem_init_destination
;
351 jpeg_mem
.dest
.empty_output_buffer
= jpeg_mem_empty_output_buffer
;
352 jpeg_mem
.dest
.term_destination
= jpeg_mem_term_destination
;
354 cinfo
->dest
=&jpeg_mem
.dest
;
358 static void jpeg_memory_src( struct jpeg_decompress_struct
*cinfo
,
359 const UChar8
*buffer
,
362 jpeg_mem
.buffer
= const_cast < UChar8
* > (buffer
);
363 jpeg_mem
.dataSize
= dataSize
;
365 jpeg_mem
.src
.init_source
= jpeg_mem_init_source
;
366 jpeg_mem
.src
.fill_input_buffer
= jpeg_mem_fill_input_buffer
;
367 jpeg_mem
.src
.skip_input_data
= jpeg_mem_skip_input_data
;
368 jpeg_mem
.src
.resync_to_restart
= jpeg_mem_resync_to_restart
;
369 jpeg_mem
.src
.term_source
= jpeg_mem_term_source
;
370 cinfo
->src
= &jpeg_mem
.src
;
374 JPGImageFileType
JPGImageFileType:: _the("image/jpeg",
375 suffixArray
, sizeof(suffixArray
),
376 (OSG_READ_SUPPORTED
|
377 OSG_WRITE_SUPPORTED
));
379 void JPGImageFileType::setQuality(UInt32 cl
)
387 UInt32
JPGImageFileType::getQuality(void)
392 #ifdef OSG_DEBUG_OLD_C_CASTS
393 #ifdef jpeg_create_compress
394 #undef jpeg_create_compress
396 #ifdef jpeg_create_decompress
397 #undef jpeg_create_decompress
400 #define jpeg_create_compress(cinfo) \
401 jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \
402 size_t(sizeof(struct jpeg_compress_struct)))
403 #define jpeg_create_decompress(cinfo) \
404 jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \
405 size_t(sizeof(struct jpeg_decompress_struct)))
408 //-------------------------------------------------------------------------
410 Tries to fill the image object with the data read from
411 the given stream. Returns true on success.
414 bool JPGImageFileType::read( Image
*OSG_JPG_ARG(pImage
),
415 std::istream
&OSG_JPG_ARG(is
),
416 const std::string
&OSG_JPG_ARG(mimetype
))
420 struct osg_jpeg_error_mgr jerr
;
421 struct jpeg_decompress_struct cinfo
;
423 cinfo
.err
= jpeg_std_error(&jerr
.pub
);
424 if (setjmp(jerr
.setjmp_buffer
))
426 cinfo
.err
->error_exit
= osg_jpeg_error_exit
;
427 cinfo
.err
->output_message
= osg_jpeg_output_message
;
429 jpeg_create_decompress(&cinfo
);
431 SourceManager
*sourceManager
=
432 new ((*cinfo
.mem
->alloc_small
)(j_common_ptr(&cinfo
),
434 sizeof(SourceManager
)))
435 SourceManager(&cinfo
, is
);
437 cinfo
.src
= reinterpret_cast<jpeg_source_mgr
*>(sourceManager
);
439 jpeg_read_header(&cinfo
, TRUE
);
440 jpeg_start_decompress(&cinfo
);
442 Image::PixelFormat pixelFormat
;
444 switch (cinfo
.output_components
)
447 pixelFormat
= Image::OSG_L_PF
;
450 pixelFormat
= Image::OSG_RGB_PF
;
453 pixelFormat
= Image::OSG_INVALID_PF
;
459 if(pImage
->set(pixelFormat
,
461 cinfo
.output_height
) == true)
463 Real32 res_x
= Real32(cinfo
.X_density
);
464 Real32 res_y
= Real32(cinfo
.Y_density
);
465 UInt16 res_unit
= UInt16(cinfo
.density_unit
);
466 if(res_unit
== 2) // centimeter
468 // convert dpcm to dpi.
471 res_unit
= Image::OSG_RESUNIT_INCH
;
473 pImage
->setResX(res_x
);
474 pImage
->setResY(res_y
);
475 pImage
->setResUnit(res_unit
);
477 unsigned char *destData
= pImage
->editData() + pImage
->getSize();
479 int row_stride
= cinfo
.output_width
* cinfo
.output_components
;
481 while (cinfo
.output_scanline
< cinfo
.output_height
)
483 destData
-= row_stride
;
484 jpeg_read_scanlines(&cinfo
, &destData
, 1);
493 jpeg_finish_decompress (&cinfo
);
494 jpeg_destroy_decompress(&cinfo
);
500 SWARNING
<< getMimeType()
501 << " read is not compiled into the current binary "
509 //-------------------------------------------------------------------------
510 /*! Tries to write the image object to the given stream.
511 Returns true on success.
514 bool JPGImageFileType::write(const Image
*OSG_JPG_ARG(pImage
),
515 std::ostream
&OSG_JPG_ARG(os
),
516 const std::string
&OSG_JPG_ARG(mimetype
))
520 if((pImage
->getBpp() != 1 &&
521 pImage
->getBpp() != 3) || pImage
->getDepth() != 1)
523 SWARNING
<< getMimeType()
524 << " JPEG write only works for 2D 1 or 3 bpp images "
530 struct osg_jpeg_error_mgr jerr
;
531 struct jpeg_compress_struct cinfo
;
533 cinfo
.err
= jpeg_std_error(&jerr
.pub
);
535 if (setjmp(jerr
.setjmp_buffer
))
537 cinfo
.err
->error_exit
= osg_jpeg_error_exit
;
538 cinfo
.err
->output_message
= osg_jpeg_output_message
;
540 jpeg_create_compress(&cinfo
);
542 DestinationManager
*destinationManager
=
543 new ((*cinfo
.mem
->alloc_small
)(j_common_ptr(&cinfo
),
545 sizeof(DestinationManager
)))
546 DestinationManager(&cinfo
, os
);
549 reinterpret_cast<jpeg_destination_mgr
*>(destinationManager
);
550 cinfo
.image_width
= pImage
->getWidth();
551 cinfo
.image_height
= pImage
->getHeight();
552 cinfo
.input_components
= pImage
->getBpp();
553 cinfo
.in_color_space
= (pImage
->getBpp() == 1) ? JCS_GRAYSCALE
: JCS_RGB
;
555 jpeg_set_defaults(&cinfo
);
557 cinfo
.density_unit
= 1; // dpi
558 cinfo
.X_density
= UInt16(pImage
->getResX() < 0.0f
?
559 pImage
->getResX() - 0.5f
:
560 pImage
->getResX() + 0.5f
);
561 cinfo
.Y_density
= UInt16(pImage
->getResY() < 0.0f
?
562 pImage
->getResY() - 0.5f
:
563 pImage
->getResY() + 0.5f
);
565 jpeg_set_quality (&cinfo
, _quality
, TRUE
);
566 jpeg_start_compress(&cinfo
, TRUE
);
568 unsigned char *srcData
=
569 const_cast<UInt8
*>(pImage
->getData()) + pImage
->getSize();
570 int row_stride
= cinfo
.image_width
* cinfo
.input_components
;
572 while (cinfo
.next_scanline
< cinfo
.image_height
)
574 srcData
-= row_stride
;
575 jpeg_write_scanlines(&cinfo
, &srcData
, 1);
578 jpeg_finish_compress (&cinfo
);
579 jpeg_destroy_compress(&cinfo
);
584 SWARNING
<< getMimeType()
585 << " write is not compiled into the current binary "
593 //-------------------------------------------------------------------------
595 Tries to determine the mime type of the data provided by an input stream
596 by searching for magic bytes. Returns the mime type or an empty string
597 when the function could not determine the mime type.
600 std::string
JPGImageFileType::determineMimetypeFromStream(std::istream
&is
)
604 is
.read(filecode
, 2);
605 is
.seekg(-2, std::ios::cur
);
607 return strncmp(filecode
, "\xff\xd8", 2) == 0 ?
608 std::string(getMimeType()) : std::string();
612 bool JPGImageFileType::validateHeader(const Char8
*fileName
,
620 FILE *file
= fopen(fileName
, "rb");
627 fread(static_cast<void *>(&magic
), sizeof(magic
), 1, file
);
631 #if BYTE_ORDER == LITTLE_ENDIAN
632 if(magic
== 0xd8ff) // the magic header is big endian need to swap it.
644 UInt64
JPGImageFileType::restoreData( Image
*OSG_JPG_ARG(pImage
),
645 const UChar8
*OSG_JPG_ARG(buffer
),
646 Int32
OSG_JPG_ARG(memSize
)) const
651 struct local_error_mgr
653 struct jpeg_error_mgr pub
;
654 jmp_buf setjmp_buffer
;
657 unsigned char *destData
;
658 Image::PixelFormat pixelFormat
= Image::OSG_INVALID_PF
;
660 unsigned long imageSize
;
661 struct local_error_mgr jerr
;
662 struct jpeg_decompress_struct cinfo
;
663 JSAMPARRAY imagebuffer
;
667 cinfo
.err
= jpeg_std_error(&jerr
.pub
);
669 if(setjmp(jerr
.setjmp_buffer
))
671 jpeg_destroy_decompress(&cinfo
);
676 jpeg_create_decompress(&cinfo
);
677 jpeg_memory_src(&cinfo
, buffer
, memSize
);
678 jpeg_read_header(&cinfo
, TRUE
);
679 jpeg_start_decompress(&cinfo
);
681 switch(cinfo
.output_components
)
684 pixelFormat
= Image::OSG_L_PF
;
687 pixelFormat
= Image::OSG_LA_PF
;
690 pixelFormat
= Image::OSG_RGB_PF
;
693 pixelFormat
= Image::OSG_RGBA_PF
;
697 if(pImage
->set(pixelFormat
, cinfo
.output_width
, cinfo
.output_height
))
699 imageSize
= pImage
->getSize();
700 destData
= pImage
->editData() + imageSize
;
701 row_stride
= cinfo
.output_width
* cinfo
.output_components
;
703 imagebuffer
= (*cinfo
.mem
->alloc_sarray
) (j_common_ptr(&cinfo
),
708 while(cinfo
.output_scanline
< cinfo
.output_height
)
710 destData
-= row_stride
;
711 jpeg_read_scanlines(&cinfo
, imagebuffer
, 1);
712 memcpy(destData
, *imagebuffer
, row_stride
);
722 jpeg_finish_decompress(&cinfo
);
723 jpeg_destroy_decompress(&cinfo
);
727 SWARNING
<< getMimeType()
728 << " read is not compiled into the current binary "
735 //-------------------------------------------------------------------------
737 Tries to restore the image data from the given memblock.
738 Returns the amount of data read.
740 UInt64
JPGImageFileType::storeData(const Image
*OSG_JPG_ARG(pImage
),
741 UChar8
*OSG_JPG_ARG(buffer
),
742 Int32
OSG_JPG_ARG(memSize
)) const
745 if((pImage
->getBpp () != 1 && pImage
->getBpp() != 3) ||
746 (pImage
->getDepth() != 1) )
748 SWARNING
<< getMimeType()
749 << " JPEG storeData only works for 2D 1 or 3 bpp images "
755 struct local_error_mgr
757 struct jpeg_error_mgr pub
;
758 jmp_buf setjmp_buffer
;
761 struct local_error_mgr jerr
;
762 struct jpeg_compress_struct cinfo
;
763 JSAMPARRAY imagebuffer
;
766 cinfo
.err
= jpeg_std_error(&jerr
.pub
);
768 if(setjmp(jerr
.setjmp_buffer
))
770 jpeg_destroy_compress(&cinfo
);
775 jpeg_create_compress(&cinfo
);
776 jpeg_memory_dest (&cinfo
, buffer
, memSize
);
778 cinfo
.image_width
= pImage
->getWidth();
779 cinfo
.image_height
= pImage
->getHeight();
780 cinfo
.input_components
= pImage
->getBpp();
781 cinfo
.in_color_space
= (pImage
->getBpp() == 1) ? JCS_GRAYSCALE
: JCS_RGB
;
783 jpeg_set_defaults(&cinfo
);
784 jpeg_set_quality(&cinfo
, _quality
, TRUE
);
785 jpeg_start_compress(&cinfo
, TRUE
);
789 while(cinfo
.next_scanline
< cinfo
.image_height
)
792 const_cast<UInt8
*>(pImage
->getData()) +
793 (pImage
->getHeight() - 1 - cinfo
.next_scanline
) *
797 jpeg_write_scanlines(&cinfo
, imagebuffer
, 1);
800 jpeg_finish_compress(&cinfo
);
801 jpeg_destroy_compress(&cinfo
);
803 return jpeg_mem
.dataSize
;
805 SWARNING
<< getMimeType()
806 << " write is not compiled into the current binary "
813 //-------------------------------------------------------------------------
814 /*! Constructor used for the singleton object
817 JPGImageFileType::JPGImageFileType(const Char8
*mimeType
,
818 const Char8
*suffixArray
[],
819 UInt16 suffixByteCount
,
830 //-------------------------------------------------------------------------
831 /*! Dummy Copy Constructor
834 //-------------------------------------------------------------------------
838 JPGImageFileType::~JPGImageFileType(void)