00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #include <stdlib.h>
00042 #include <stdio.h>
00043
00044 #include "OSGConfig.h"
00045
00046 #ifdef OSG_WITH_JPG
00047 extern "C" {
00048
00049 #ifdef WIN32
00050 #define __WIN32__
00051 #endif
00052
00053 #include <setjmp.h>
00054 #include <jpeglib.h>
00055
00056 }
00057 #endif
00058
00059 #ifdef OSG_SGI_LIB
00060 #include <limits>
00061 #endif
00062 #include "OSGJPGImageFileType.h"
00063 #include <OSGLog.h>
00064
00065 #include <iostream>
00066
00067 #ifndef OSG_DO_DOC
00068 # ifdef OSG_WITH_JPG
00069 # define OSG_JPG_ARG(ARG) ARG
00070 # else
00071 # define OSG_JPG_ARG(ARG)
00072 # endif
00073 #else
00074 # define OSG_JPG_ARG(ARG) ARG
00075 #endif
00076
00077 OSG_USING_NAMESPACE
00078
00094 #ifdef OSG_WITH_JPG
00095
00096 static const unsigned long BUFFERSIZE = 4096;
00097
00098 typedef struct SourceManager
00099 {
00100 struct jpeg_source_mgr pub;
00101 std::istream *is;
00102 char *buffer;
00103 SourceManager(j_decompress_ptr cinfo, std::istream &is);
00104 } SourceManager;
00105
00106 static void istream_init_source(j_decompress_ptr cinfo) {}
00107
00108 static boolean istream_fill_input_buffer(j_decompress_ptr cinfo)
00109 {
00110 SourceManager *sourceManager = reinterpret_cast<SourceManager*>(cinfo->src);
00111
00112 sourceManager->is->read(sourceManager->buffer, BUFFERSIZE);
00113
00114 cinfo->src->next_input_byte = (const JOCTET*)sourceManager->buffer;
00115
00116 if (sourceManager->is->gcount() == 0)
00117 {
00118
00119 sourceManager->buffer[0] = (JOCTET) 0xFF;
00120 sourceManager->buffer[1] = (JOCTET) JPEG_EOI;
00121 cinfo->src->bytes_in_buffer = 2;
00122 }
00123 else
00124 cinfo->src->bytes_in_buffer = sourceManager->is->gcount();
00125
00126 return TRUE;
00127 }
00128
00129 static void istream_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
00130 {
00131 if ((unsigned long)num_bytes <= cinfo->src->bytes_in_buffer)
00132 {
00133 cinfo->src->bytes_in_buffer -= num_bytes;
00134 cinfo->src->next_input_byte += num_bytes;
00135 }
00136 else
00137 {
00138 num_bytes -= cinfo->src->bytes_in_buffer;
00139 SourceManager *sourceManager = reinterpret_cast<SourceManager*>(cinfo->src);
00140 sourceManager->is->ignore(num_bytes);
00141 cinfo->src->bytes_in_buffer = 0;
00142 cinfo->src->next_input_byte = 0;
00143 }
00144 }
00145
00146 static void istream_term_source(j_decompress_ptr cinfo) {}
00147
00148 SourceManager::SourceManager(j_decompress_ptr cinfo, std::istream &is)
00149 {
00150 pub.init_source = istream_init_source;
00151 pub.fill_input_buffer = istream_fill_input_buffer;
00152 pub.skip_input_data = istream_skip_input_data;
00153 pub.resync_to_restart = jpeg_resync_to_restart;
00154 pub.term_source = istream_term_source;
00155 pub.bytes_in_buffer = 0;
00156 pub.next_input_byte = 0;
00157 this->is = &is;
00158 buffer = (char*)(*cinfo->mem->alloc_small)((j_common_ptr)cinfo, JPOOL_IMAGE, BUFFERSIZE);
00159 }
00160
00161 typedef struct DestinationManager
00162 {
00163 struct jpeg_destination_mgr pub;
00164 std::ostream *os;
00165 char *buffer;
00166 DestinationManager(j_compress_ptr cinfo, std::ostream &os);
00167 } DestinationManager;
00168
00169 static void ostream_init_destination(j_compress_ptr cinfo) {}
00170
00171 static boolean ostream_empty_output_buffer(j_compress_ptr cinfo)
00172 {
00173 DestinationManager *destinationManager = reinterpret_cast<DestinationManager*>(cinfo->dest);
00174
00175 destinationManager->os->write(destinationManager->buffer, BUFFERSIZE);
00176
00177 destinationManager->pub.next_output_byte = (JOCTET*)destinationManager->buffer;
00178 destinationManager->pub.free_in_buffer = BUFFERSIZE;
00179
00180 return destinationManager->os->good() != false ? TRUE : FALSE;
00181 }
00182
00183 static void ostream_term_destination(j_compress_ptr cinfo)
00184 {
00185 DestinationManager *destinationManager = reinterpret_cast<DestinationManager*>(cinfo->dest);
00186
00187 if(destinationManager->pub.free_in_buffer > 0)
00188 {
00189 destinationManager->os->write(destinationManager->buffer, BUFFERSIZE - destinationManager->pub.free_in_buffer);
00190 }
00191 }
00192
00193 DestinationManager::DestinationManager(j_compress_ptr cinfo, std::ostream &os)
00194 {
00195 pub.init_destination = ostream_init_destination;
00196 pub.empty_output_buffer = ostream_empty_output_buffer;
00197 pub.term_destination = ostream_term_destination;
00198 this->os = &os;
00199 buffer = (char*)(*cinfo->mem->alloc_small)((j_common_ptr)cinfo, JPOOL_IMAGE, BUFFERSIZE);
00200 pub.free_in_buffer = BUFFERSIZE;
00201 pub.next_output_byte = (JOCTET *) buffer;
00202 }
00203
00204 struct osg_jpeg_error_mgr
00205 {
00206 struct jpeg_error_mgr pub;
00207 jmp_buf setjmp_buffer;
00208 };
00209
00210 static void osg_jpeg_error_exit(j_common_ptr cinfo)
00211 {
00212
00213 (*cinfo->err->output_message) (cinfo);
00214
00215
00216 jpeg_destroy(cinfo);
00217
00218
00219 struct osg_jpeg_error_mgr *osgerr = (struct osg_jpeg_error_mgr *)cinfo->err;
00220 longjmp(osgerr->setjmp_buffer, 1);
00221 }
00222
00223 static void osg_jpeg_output_message(j_common_ptr cinfo)
00224 {
00225 char buffer[JMSG_LENGTH_MAX];
00226
00227
00228 (*cinfo->err->format_message) (cinfo, buffer);
00229
00230
00231 FFATAL (("JPG: %s\n", buffer));
00232 }
00233
00234 struct jpeg_mem
00235 {
00236 struct jpeg_destination_mgr dest;
00237 struct jpeg_source_mgr src;
00238 UChar8 *buffer;
00239 UInt32 memSize;
00240 UInt32 dataSize;
00241 } jpeg_mem;
00242
00243
00244 static void jpeg_mem_init_source(j_decompress_ptr OSG_CHECK_ARG(cinfo))
00245 {
00246 jpeg_mem.src.next_input_byte = (JOCTET *) jpeg_mem.buffer;
00247 jpeg_mem.src.bytes_in_buffer = (size_t) jpeg_mem.dataSize;
00248 }
00249
00250
00251 static boolean jpeg_mem_fill_input_buffer(j_decompress_ptr OSG_CHECK_ARG(cinfo))
00252 {
00253 SFATAL << "Missing data. Given data block too small." << std::endl;
00254 return false;
00255 }
00256
00257
00258 static void jpeg_mem_skip_input_data(j_decompress_ptr OSG_CHECK_ARG(cinfo ),
00259 long num_bytes)
00260 {
00261 jpeg_mem.src.next_input_byte += num_bytes;
00262 jpeg_mem.src.bytes_in_buffer -= num_bytes;
00263 }
00264
00265
00266 static boolean jpeg_mem_resync_to_restart(j_decompress_ptr OSG_CHECK_ARG(cinfo ),
00267 int OSG_CHECK_ARG(desired))
00268 {
00269 return false;
00270 }
00271
00272
00273 static void jpeg_mem_term_source(j_decompress_ptr OSG_CHECK_ARG(cinfo))
00274 {
00275 }
00276
00277
00278 static void jpeg_mem_init_destination(j_compress_ptr OSG_CHECK_ARG(cinfo))
00279 {
00280 jpeg_mem.dest.next_output_byte = (JOCTET *) jpeg_mem.buffer;
00281 jpeg_mem.dest.free_in_buffer = (size_t) jpeg_mem.memSize;
00282 }
00283
00284
00285 static boolean jpeg_mem_empty_output_buffer(j_compress_ptr OSG_CHECK_ARG(cinfo))
00286 {
00287 SFATAL << "Not enough space left in buffer." << std::endl;
00288 return false;
00289 }
00290
00291
00292 static void jpeg_mem_term_destination(j_compress_ptr OSG_CHECK_ARG(cinfo))
00293 {
00294 jpeg_mem.dataSize = ((UChar8 *) jpeg_mem.dest.next_output_byte) - ((UChar8 *) jpeg_mem.buffer);
00295 }
00296
00297
00298 static void jpeg_memory_dest(struct jpeg_compress_struct *cinfo,
00299 UChar8 *buffer,
00300 UInt32 memSize)
00301 {
00302 jpeg_mem.buffer=buffer;
00303 jpeg_mem.memSize=memSize;
00304 jpeg_mem.dest.init_destination = jpeg_mem_init_destination;
00305 jpeg_mem.dest.empty_output_buffer = jpeg_mem_empty_output_buffer;
00306 jpeg_mem.dest.term_destination = jpeg_mem_term_destination;
00307 cinfo->dest=&jpeg_mem.dest;
00308 }
00309
00310
00311 static void jpeg_memory_src(struct jpeg_decompress_struct *cinfo,
00312 const UChar8 *buffer,
00313 UInt32 dataSize)
00314 {
00315 jpeg_mem.buffer = const_cast < UChar8 * > (buffer);
00316 jpeg_mem.dataSize = dataSize;
00317 jpeg_mem.src.init_source = jpeg_mem_init_source;
00318 jpeg_mem.src.fill_input_buffer = jpeg_mem_fill_input_buffer;
00319 jpeg_mem.src.skip_input_data = jpeg_mem_skip_input_data;
00320 jpeg_mem.src.resync_to_restart = jpeg_mem_resync_to_restart;
00321 jpeg_mem.src.term_source = jpeg_mem_term_source;
00322 cinfo->src = &jpeg_mem.src;
00323 }
00324 #endif
00325
00326
00327
00328
00329
00330
00331
00332
00333 static const Char8 *suffixArray[] = { "jpg", "jpeg", "jpe", "jfif" };
00334
00335 JPGImageFileType JPGImageFileType:: _the("image/jpeg",
00336 suffixArray, sizeof(suffixArray),
00337 OSG_READ_SUPPORTED |
00338 OSG_WRITE_SUPPORTED );
00339
00340
00341
00342
00343
00344
00345
00349 JPGImageFileType& JPGImageFileType::the (void)
00350 {
00351 return _the;
00352 }
00353
00354
00355
00356
00357
00358 void JPGImageFileType::setQuality(UInt32 cl)
00359 {
00360 if(cl > 100)
00361 cl = 100;
00362
00363 _quality = cl;
00364 }
00365
00366 UInt32 JPGImageFileType::getQuality(void)
00367 {
00368 return _quality;
00369 }
00370
00371
00376 bool JPGImageFileType::read(ImagePtr &OSG_JPG_ARG(image), std::istream &OSG_JPG_ARG(is),
00377 const std::string &OSG_JPG_ARG(mimetype))
00378 {
00379 #ifdef OSG_WITH_JPG
00380
00381 struct osg_jpeg_error_mgr jerr;
00382 struct jpeg_decompress_struct cinfo;
00383
00384 cinfo.err = jpeg_std_error(&jerr.pub);
00385 if (setjmp(jerr.setjmp_buffer))
00386 return false;
00387 cinfo.err->error_exit = osg_jpeg_error_exit;
00388 cinfo.err->output_message = osg_jpeg_output_message;
00389
00390 jpeg_create_decompress(&cinfo);
00391
00392 SourceManager *sourceManager =
00393 new ((*cinfo.mem->alloc_small)((j_common_ptr)&cinfo, JPOOL_IMAGE, sizeof(SourceManager)))
00394 SourceManager(&cinfo, is);
00395 cinfo.src = (jpeg_source_mgr*)sourceManager;
00396
00397 jpeg_read_header(&cinfo, TRUE);
00398 jpeg_start_decompress(&cinfo);
00399
00400 Image::PixelFormat pixelFormat;
00401 switch (cinfo.output_components)
00402 {
00403 case 1:
00404 pixelFormat = Image::OSG_L_PF;
00405 break;
00406 case 3:
00407 pixelFormat = Image::OSG_RGB_PF;
00408 break;
00409 default:
00410 pixelFormat = Image::OSG_INVALID_PF;
00411 break;
00412 };
00413
00414 bool retCode;
00415 if (image->set(pixelFormat, cinfo.output_width, cinfo.output_height) == true)
00416 {
00417 Real32 res_x = Real32(cinfo.X_density);
00418 Real32 res_y = Real32(cinfo.Y_density);
00419 UInt16 res_unit = UInt16(cinfo.density_unit);
00420 if(res_unit == 2)
00421 {
00422
00423 res_x *= 2.54f;
00424 res_y *= 2.54f;
00425 res_unit = Image::OSG_RESUNIT_INCH;
00426 }
00427 image->setResX(res_x);
00428 image->setResY(res_y);
00429 image->setResUnit(res_unit);
00430
00431 unsigned char *destData = image->getData() + image->getSize();
00432 int row_stride = cinfo.output_width * cinfo.output_components;
00433 while (cinfo.output_scanline < cinfo.output_height)
00434 {
00435 destData -= row_stride;
00436 jpeg_read_scanlines(&cinfo, &destData, 1);
00437 }
00438 retCode = true;
00439 }
00440 else
00441 retCode = false;
00442
00443 jpeg_finish_decompress(&cinfo);
00444 jpeg_destroy_decompress(&cinfo);
00445
00446 return retCode;
00447
00448 #else
00449
00450 SWARNING <<
00451 getMimeType() <<
00452 " read is not compiled into the current binary " <<
00453 std::endl;
00454 return false;
00455
00456 #endif
00457 }
00458
00459
00464 bool JPGImageFileType::write(const ImagePtr &OSG_JPG_ARG(image), std::ostream &OSG_JPG_ARG(os),
00465 const std::string &OSG_JPG_ARG(mimetype))
00466 {
00467 #ifdef OSG_WITH_JPG
00468
00469 if ((image->getBpp() != 1 &&
00470 image->getBpp() != 3) || image->getDepth() != 1)
00471 {
00472 SWARNING <<
00473 getMimeType() <<
00474 " JPEG write only works for 2D 1 or 3 bpp images " <<
00475 std::endl;
00476 return false;
00477 }
00478
00479 struct osg_jpeg_error_mgr jerr;
00480 struct jpeg_compress_struct cinfo;
00481
00482 cinfo.err = jpeg_std_error(&jerr.pub);
00483 if (setjmp(jerr.setjmp_buffer))
00484 return false;
00485 cinfo.err->error_exit = osg_jpeg_error_exit;
00486 cinfo.err->output_message = osg_jpeg_output_message;
00487
00488 jpeg_create_compress(&cinfo);
00489
00490 DestinationManager *destinationManager =
00491 new ((*cinfo.mem->alloc_small)((j_common_ptr)&cinfo, JPOOL_IMAGE, sizeof(DestinationManager)))
00492 DestinationManager(&cinfo, os);
00493 cinfo.dest = (jpeg_destination_mgr*)destinationManager;
00494
00495 cinfo.image_width = image->getWidth();
00496 cinfo.image_height = image->getHeight();
00497 cinfo.input_components = image->getBpp();
00498 cinfo.in_color_space = (image->getBpp() == 1) ? JCS_GRAYSCALE : JCS_RGB;
00499
00500 jpeg_set_defaults(&cinfo);
00501 jpeg_set_quality(&cinfo, _quality, TRUE);
00502
00503 cinfo.density_unit = 1;
00504 cinfo.X_density = UInt16(image->getResX() < 0.0f ?
00505 image->getResX() - 0.5f :
00506 image->getResX() + 0.5f);
00507 cinfo.Y_density = UInt16(image->getResY() < 0.0f ?
00508 image->getResY() - 0.5f :
00509 image->getResY() + 0.5f);
00510
00511 jpeg_start_compress(&cinfo, TRUE);
00512
00513 unsigned char *srcData = image->getData() + image->getSize();
00514 int row_stride = cinfo.image_width * cinfo.input_components;
00515 while (cinfo.next_scanline < cinfo.image_height)
00516 {
00517 srcData -= row_stride;
00518 jpeg_write_scanlines(&cinfo, &srcData, 1);
00519 }
00520
00521 jpeg_finish_compress(&cinfo);
00522 jpeg_destroy_compress(&cinfo);
00523
00524 return true;
00525
00526 #else
00527
00528 SWARNING <<
00529 getMimeType() <<
00530 " write is not compiled into the current binary " <<
00531 std::endl;
00532 return false;
00533
00534 #endif
00535 }
00536
00537
00543 std::string JPGImageFileType::determineMimetypeFromStream(std::istream &is)
00544 {
00545 char filecode[2];
00546 is.read(filecode, 2);
00547 is.seekg(-2, std::ios::cur);
00548 return strncmp(filecode, "\xff\xd8", 2) == 0 ?
00549 std::string(getMimeType()) : std::string();
00550 }
00551
00552
00553
00554 bool JPGImageFileType::validateHeader( const Char8 *fileName, bool &implemented )
00555 {
00556 implemented = true;
00557
00558 if(fileName == NULL)
00559 return false;
00560
00561 FILE *file = fopen(fileName, "rb");
00562 if(file == NULL)
00563 return false;
00564
00565 UInt16 magic = 0;
00566 fread((void *) &magic, sizeof(magic), 1, file);
00567 fclose(file);
00568
00569 #if BYTE_ORDER == LITTLE_ENDIAN
00570 if(magic == 0xd8ff)
00571 #else
00572 if(magic == 0xffd8)
00573 #endif
00574 {
00575 return true;
00576 }
00577
00578 return false;
00579 }
00580
00581
00582
00583 UInt64 JPGImageFileType::restoreData( ImagePtr &OSG_JPG_ARG(image ),
00584 const UChar8 *OSG_JPG_ARG(buffer ),
00585 Int32 OSG_JPG_ARG(memSize))
00586 {
00587 #ifdef OSG_WITH_JPG
00588 UInt64 retCode = 0;
00589 struct local_error_mgr
00590 {
00591 struct jpeg_error_mgr pub;
00592 jmp_buf setjmp_buffer;
00593 };
00594
00595 unsigned char *destData;
00596 Image::PixelFormat pixelFormat = osg::Image::OSG_INVALID_PF;
00597
00598 unsigned long imageSize;
00599 typedef struct local_error_mgr *local_error_ptr;
00600 struct local_error_mgr jerr;
00601 struct jpeg_decompress_struct cinfo;
00602 JSAMPARRAY imagebuffer;
00603
00604 int row_stride;
00605
00606 cinfo.err = jpeg_std_error(&jerr.pub);
00607 if(setjmp(jerr.setjmp_buffer))
00608 {
00609 jpeg_destroy_decompress(&cinfo);
00610 return 0;
00611 }
00612
00613 jpeg_create_decompress(&cinfo);
00614 jpeg_memory_src(&cinfo, buffer, memSize);
00615 jpeg_read_header(&cinfo, TRUE);
00616 jpeg_start_decompress(&cinfo);
00617
00618 switch(cinfo.output_components)
00619 {
00620 case 1:
00621 pixelFormat = Image::OSG_L_PF;
00622 break;
00623 case 2:
00624 pixelFormat = Image::OSG_LA_PF;
00625 break;
00626 case 3:
00627 pixelFormat = Image::OSG_RGB_PF;
00628 break;
00629 case 4:
00630 pixelFormat = Image::OSG_RGBA_PF;
00631 break;
00632 };
00633
00634 if(image->set(pixelFormat, cinfo.output_width, cinfo.output_height))
00635 {
00636 imageSize = image->getSize();
00637 destData = image->getData() + imageSize;
00638 row_stride = cinfo.output_width * cinfo.output_components;
00639 imagebuffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) & cinfo, JPOOL_IMAGE, row_stride, 1);
00640 while(cinfo.output_scanline < cinfo.output_height)
00641 {
00642 destData -= row_stride;
00643 jpeg_read_scanlines(&cinfo, imagebuffer, 1);
00644 memcpy(destData, *imagebuffer, row_stride);
00645 }
00646
00647 retCode = imageSize;
00648 }
00649 else
00650 retCode = 0;
00651
00652 jpeg_finish_decompress(&cinfo);
00653 jpeg_destroy_decompress(&cinfo);
00654
00655 return retCode;
00656
00657 #else
00658 SWARNING <<
00659 getMimeType() <<
00660 " read is not compiled into the current binary " <<
00661 std::endl;
00662 return 0;
00663 #endif
00664 }
00665
00666
00671 UInt64 JPGImageFileType::storeData(const ImagePtr &OSG_JPG_ARG(image ),
00672 UChar8 *OSG_JPG_ARG(buffer ),
00673 Int32 OSG_JPG_ARG(memSize))
00674 {
00675 #ifdef OSG_WITH_JPG
00676 if((image->getBpp() != 1 && image->getBpp() != 3)
00677 || image->getDepth() != 1)
00678 {
00679 SWARNING <<
00680 getMimeType() <<
00681 " JPEG storeData only works for 2D 1 or 3 bpp images " <<
00682 std::endl;
00683 return 0;
00684 }
00685
00686 struct local_error_mgr
00687 {
00688 struct jpeg_error_mgr pub;
00689 jmp_buf setjmp_buffer;
00690 };
00691
00692 typedef struct local_error_mgr *local_error_ptr;
00693
00694 struct local_error_mgr jerr;
00695 struct jpeg_compress_struct cinfo;
00696 JSAMPARRAY imagebuffer;
00697 UChar8 *data;
00698
00699 cinfo.err = jpeg_std_error(&jerr.pub);
00700 if(setjmp(jerr.setjmp_buffer))
00701 {
00702 jpeg_destroy_compress(&cinfo);
00703 return 0;
00704 }
00705
00706 jpeg_create_compress(&cinfo);
00707 jpeg_memory_dest(&cinfo, buffer, memSize);
00708
00709 cinfo.image_width = image->getWidth();
00710 cinfo.image_height = image->getHeight();
00711 cinfo.input_components = image->getBpp();
00712 cinfo.in_color_space = (image->getBpp() == 1) ? JCS_GRAYSCALE : JCS_RGB;
00713
00714 jpeg_set_defaults(&cinfo);
00715 jpeg_set_quality(&cinfo, _quality, TRUE);
00716 jpeg_start_compress(&cinfo, TRUE);
00717
00718 imagebuffer = &data;
00719 while(cinfo.next_scanline < cinfo.image_height)
00720 {
00721 data = image->getData() +
00722 (image->getHeight() - 1 - cinfo.next_scanline) *
00723 image->getWidth() *
00724 image->getBpp();
00725 jpeg_write_scanlines(&cinfo, imagebuffer, 1);
00726 }
00727
00728 jpeg_finish_compress(&cinfo);
00729 jpeg_destroy_compress(&cinfo);
00730
00731 return jpeg_mem.dataSize;
00732
00733 #else
00734 SWARNING <<
00735 getMimeType() <<
00736 " write is not compiled into the current binary " <<
00737 std::endl;
00738 return 0;
00739 #endif
00740 }
00741
00742
00746 JPGImageFileType::JPGImageFileType( const Char8 *mimeType,
00747 const Char8 *suffixArray[],
00748 UInt16 suffixByteCount,
00749 UInt32 flags) :
00750 ImageFileType(mimeType, suffixArray, suffixByteCount, flags),
00751 _quality(90)
00752 {}
00753
00754
00758 JPGImageFileType::~JPGImageFileType(void) {}