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 #ifndef OSG_DO_DOC
00066 # ifdef OSG_WITH_JPG
00067 # define OSG_JPG_ARG(ARG) ARG
00068 # else
00069 # define OSG_JPG_ARG(ARG)
00070 # endif
00071 #else
00072 # define OSG_JPG_ARG(ARG) ARG
00073 #endif
00074
00075 OSG_USING_NAMESPACE
00076
00092 #ifdef OSG_WITH_JPG
00093
00094 struct jpeg_mem
00095 {
00096 struct jpeg_destination_mgr dest;
00097 struct jpeg_source_mgr src;
00098 UChar8 *buffer;
00099 UInt32 memSize;
00100 UInt32 dataSize;
00101 } jpeg_mem;
00102
00103
00104 static void jpeg_mem_init_source(j_decompress_ptr OSG_CHECK_ARG(cinfo))
00105 {
00106 jpeg_mem.src.next_input_byte = (JOCTET *) jpeg_mem.buffer;
00107 jpeg_mem.src.bytes_in_buffer = (size_t) jpeg_mem.dataSize;
00108 }
00109
00110
00111 static boolean jpeg_mem_fill_input_buffer(j_decompress_ptr OSG_CHECK_ARG(cinfo))
00112 {
00113 SFATAL << "Missing data. Given data block to small." << std::endl;
00114 return false;
00115 }
00116
00117
00118 static void jpeg_mem_skip_input_data(j_decompress_ptr OSG_CHECK_ARG(cinfo ),
00119 long OSG_CHECK_ARG(num_bytes))
00120 {
00121 }
00122
00123
00124 static boolean jpeg_mem_resync_to_restart(j_decompress_ptr OSG_CHECK_ARG(cinfo ),
00125 int OSG_CHECK_ARG(desired))
00126 {
00127 return false;
00128 }
00129
00130
00131 static void jpeg_mem_term_source(j_decompress_ptr OSG_CHECK_ARG(cinfo))
00132 {
00133 }
00134
00135
00136 static void jpeg_mem_init_destination(j_compress_ptr OSG_CHECK_ARG(cinfo))
00137 {
00138 jpeg_mem.dest.next_output_byte = (JOCTET *) jpeg_mem.buffer;
00139 jpeg_mem.dest.free_in_buffer = (size_t) jpeg_mem.memSize;
00140 }
00141
00142
00143 static boolean jpeg_mem_empty_output_buffer(j_compress_ptr OSG_CHECK_ARG(cinfo))
00144 {
00145 SFATAL << "Not enough space left in buffer." << std::endl;
00146 return false;
00147 }
00148
00149
00150 static void jpeg_mem_term_destination(j_compress_ptr OSG_CHECK_ARG(cinfo))
00151 {
00152 jpeg_mem.dataSize = ((UChar8 *) jpeg_mem.dest.next_output_byte) - ((UChar8 *) jpeg_mem.buffer);
00153 }
00154
00155
00156 static void jpeg_memory_dest(struct jpeg_compress_struct *cinfo,
00157 UChar8 *buffer,
00158 UInt32 memSize)
00159 {
00160 jpeg_mem.buffer=buffer;
00161 jpeg_mem.memSize=memSize;
00162 jpeg_mem.dest.init_destination = jpeg_mem_init_destination;
00163 jpeg_mem.dest.empty_output_buffer = jpeg_mem_empty_output_buffer;
00164 jpeg_mem.dest.term_destination = jpeg_mem_term_destination;
00165 cinfo->dest=&jpeg_mem.dest;
00166 }
00167
00168
00169 static void jpeg_memory_src(struct jpeg_decompress_struct *cinfo,
00170 const UChar8 *buffer,
00171 UInt32 dataSize)
00172 {
00173 jpeg_mem.buffer = const_cast < UChar8 * > (buffer);
00174 jpeg_mem.dataSize = dataSize;
00175 jpeg_mem.src.init_source = jpeg_mem_init_source;
00176 jpeg_mem.src.fill_input_buffer = jpeg_mem_fill_input_buffer;
00177 jpeg_mem.src.skip_input_data = jpeg_mem_skip_input_data;
00178 jpeg_mem.src.resync_to_restart = jpeg_mem_resync_to_restart;
00179 jpeg_mem.src.term_source = jpeg_mem_term_source;
00180 cinfo->src = &jpeg_mem.src;
00181 }
00182 #endif
00183
00184
00185
00186
00187
00188
00189
00190
00191 static const Char8 *suffixArray[] = { "jpg", "jpeg" };
00192
00193 JPGImageFileType JPGImageFileType:: _the("jpeg",
00194 suffixArray, sizeof(suffixArray),
00195 OSG_READ_SUPPORTED |
00196 OSG_WRITE_SUPPORTED );
00197
00198
00199
00200
00201
00202
00203
00207 JPGImageFileType& JPGImageFileType::the (void)
00208 {
00209 return _the;
00210 }
00211
00212
00213
00214
00215
00216 void JPGImageFileType::setQuality(UInt32 cl)
00217 {
00218 if(cl > 100)
00219 cl = 100;
00220
00221 _quality = cl;
00222 }
00223
00224 UInt32 JPGImageFileType::getQuality(void)
00225 {
00226 return _quality;
00227 }
00228
00229
00234 bool JPGImageFileType::read( ImagePtr &OSG_JPG_ARG(image),
00235 const Char8 *OSG_JPG_ARG(fileName))
00236 {
00237 #ifdef OSG_WITH_JPG
00238 bool retCode = false;
00239 struct local_error_mgr
00240 {
00241 struct jpeg_error_mgr pub;
00242 jmp_buf setjmp_buffer;
00243 };
00244
00245 unsigned char *destData;
00246 Image::PixelFormat pixelFormat = osg::Image::OSG_INVALID_PF;
00247
00248 unsigned long imageSize;
00249 typedef struct local_error_mgr *local_error_ptr;
00250 struct local_error_mgr jerr;
00251 struct jpeg_decompress_struct cinfo;
00252 FILE *infile;
00253 JSAMPARRAY buffer;
00254
00255 int row_stride;
00256
00257 if((infile = fopen(fileName, "rb")))
00258 {
00259 cinfo.err = jpeg_std_error(&jerr.pub);
00260 if(setjmp(jerr.setjmp_buffer))
00261 {
00262 jpeg_destroy_decompress(&cinfo);
00263 fclose(infile);
00264 return retCode;
00265 }
00266
00267 jpeg_create_decompress(&cinfo);
00268 jpeg_stdio_src(&cinfo, infile);
00269 jpeg_read_header(&cinfo, TRUE);
00270 jpeg_start_decompress(&cinfo);
00271
00272 switch(cinfo.output_components)
00273 {
00274 case 1:
00275 pixelFormat = Image::OSG_L_PF;
00276 break;
00277 case 2:
00278 pixelFormat = Image::OSG_LA_PF;
00279 break;
00280 case 3:
00281 pixelFormat = Image::OSG_RGB_PF;
00282 break;
00283 case 4:
00284 pixelFormat = Image::OSG_RGBA_PF;
00285 break;
00286 };
00287
00288 if(image->set(pixelFormat, cinfo.output_width, cinfo.output_height))
00289 {
00290 imageSize = image->getSize();
00291 destData = image->getData() + imageSize;
00292 row_stride = cinfo.output_width * cinfo.output_components;
00293 buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) & cinfo, JPOOL_IMAGE, row_stride, 1);
00294 while(cinfo.output_scanline < cinfo.output_height)
00295 {
00296 destData -= row_stride;
00297 jpeg_read_scanlines(&cinfo, buffer, 1);
00298 memcpy(destData, *buffer, row_stride);
00299 }
00300
00301 retCode = true;
00302 }
00303 else
00304 retCode = false;
00305
00306 jpeg_finish_decompress(&cinfo);
00307 jpeg_destroy_decompress(&cinfo);
00308 fclose(infile);
00309 }
00310
00311 return retCode;
00312
00313 #else
00314 SWARNING <<
00315 getMimeType() <<
00316 " read is not compiled into the current binary " <<
00317 std::endl;
00318 return false;
00319 #endif
00320 }
00321
00322
00327 bool JPGImageFileType::write(const ImagePtr &OSG_JPG_ARG(image),
00328 const Char8 *OSG_JPG_ARG(fileName))
00329 {
00330 #ifdef OSG_WITH_JPG
00331 if((image->getBpp() != 1 &&
00332 image->getBpp() != 3) || image->getDepth() != 1)
00333 {
00334 SWARNING <<
00335 getMimeType() <<
00336 " JPEG write only works for 2D 1 or 3 bpp images " <<
00337 std::endl;
00338 return false;
00339 }
00340
00341 bool retCode = false;
00342
00343 struct local_error_mgr
00344 {
00345 struct jpeg_error_mgr pub;
00346 jmp_buf setjmp_buffer;
00347 };
00348
00349 typedef struct local_error_mgr *local_error_ptr;
00350
00351 struct local_error_mgr jerr;
00352 struct jpeg_compress_struct cinfo;
00353 FILE *outfile;
00354 JSAMPARRAY buffer;
00355 UChar8 *data;
00356
00357 if((outfile = fopen(fileName, "wb")) == NULL)
00358 {
00359 fprintf(stderr, "can't open %s\n", fileName);
00360 return retCode;
00361 }
00362
00363 cinfo.err = jpeg_std_error(&jerr.pub);
00364 if(setjmp(jerr.setjmp_buffer))
00365 {
00366 jpeg_destroy_compress(&cinfo);
00367 fclose(outfile);
00368 return 0;
00369 }
00370
00371 jpeg_create_compress(&cinfo);
00372 jpeg_stdio_dest(&cinfo, outfile);
00373
00374 cinfo.image_width = image->getWidth();
00375 cinfo.image_height = image->getHeight();
00376 cinfo.input_components = image->getBpp();
00377 cinfo.in_color_space = (image->getBpp() == 1) ? JCS_GRAYSCALE : JCS_RGB;
00378
00379 jpeg_set_defaults(&cinfo);
00380 jpeg_set_quality(&cinfo, _quality, TRUE);
00381 jpeg_start_compress(&cinfo, TRUE);
00382
00383 buffer = &data;
00384 while(cinfo.next_scanline < cinfo.image_height)
00385 {
00386 data = image->getData() +
00387 (image->getHeight() - 1 - cinfo.next_scanline) *
00388 image->getWidth() *
00389 image->getBpp();
00390 jpeg_write_scanlines(&cinfo, buffer, 1);
00391 }
00392
00393 jpeg_finish_compress(&cinfo);
00394 jpeg_destroy_compress(&cinfo);
00395 fclose(outfile);
00396
00397 return true;
00398
00399 #else
00400 SWARNING <<
00401 getMimeType() <<
00402 " write is not compiled into the current binary " <<
00403 std::endl;
00404 return false;
00405 #endif
00406 }
00407
00408 bool JPGImageFileType::validateHeader( const Char8 *fileName, bool &implemented )
00409 {
00410 implemented = true;
00411
00412 if(fileName == NULL)
00413 return false;
00414
00415 FILE *file = fopen(fileName, "rb");
00416 if(file == NULL)
00417 return false;
00418
00419 UInt16 magic = 0;
00420 fread((void *) &magic, sizeof(magic), 1, file);
00421 fclose(file);
00422
00423 #if BYTE_ORDER == LITTLE_ENDIAN
00424 if(magic == 0xd8ff)
00425 #else
00426 if(magic == 0xffd8)
00427 #endif
00428 {
00429 return true;
00430 }
00431
00432 return false;
00433 }
00434
00435
00436
00437 UInt64 JPGImageFileType::restoreData( ImagePtr &OSG_JPG_ARG(image ),
00438 const UChar8 *OSG_JPG_ARG(buffer ),
00439 Int32 OSG_JPG_ARG(memSize))
00440 {
00441 #ifdef OSG_WITH_JPG
00442 UInt64 retCode = 0;
00443 struct local_error_mgr
00444 {
00445 struct jpeg_error_mgr pub;
00446 jmp_buf setjmp_buffer;
00447 };
00448
00449 unsigned char *destData;
00450 Image::PixelFormat pixelFormat = osg::Image::OSG_INVALID_PF;
00451
00452 unsigned long imageSize;
00453 typedef struct local_error_mgr *local_error_ptr;
00454 struct local_error_mgr jerr;
00455 struct jpeg_decompress_struct cinfo;
00456 JSAMPARRAY imagebuffer;
00457
00458 int row_stride;
00459
00460 cinfo.err = jpeg_std_error(&jerr.pub);
00461 if(setjmp(jerr.setjmp_buffer))
00462 {
00463 jpeg_destroy_decompress(&cinfo);
00464 return 0;
00465 }
00466
00467 jpeg_create_decompress(&cinfo);
00468 jpeg_memory_src(&cinfo, buffer, memSize);
00469 jpeg_read_header(&cinfo, TRUE);
00470 jpeg_start_decompress(&cinfo);
00471
00472 switch(cinfo.output_components)
00473 {
00474 case 1:
00475 pixelFormat = Image::OSG_L_PF;
00476 break;
00477 case 2:
00478 pixelFormat = Image::OSG_LA_PF;
00479 break;
00480 case 3:
00481 pixelFormat = Image::OSG_RGB_PF;
00482 break;
00483 case 4:
00484 pixelFormat = Image::OSG_RGBA_PF;
00485 break;
00486 };
00487
00488 if(image->set(pixelFormat, cinfo.output_width, cinfo.output_height))
00489 {
00490 imageSize = image->getSize();
00491 destData = image->getData() + imageSize;
00492 row_stride = cinfo.output_width * cinfo.output_components;
00493 imagebuffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) & cinfo, JPOOL_IMAGE, row_stride, 1);
00494 while(cinfo.output_scanline < cinfo.output_height)
00495 {
00496 destData -= row_stride;
00497 jpeg_read_scanlines(&cinfo, imagebuffer, 1);
00498 memcpy(destData, *imagebuffer, row_stride);
00499 }
00500
00501 retCode = imageSize;
00502 }
00503 else
00504 retCode = 0;
00505
00506 jpeg_finish_decompress(&cinfo);
00507 jpeg_destroy_decompress(&cinfo);
00508
00509 return retCode;
00510
00511 #else
00512 SWARNING <<
00513 getMimeType() <<
00514 " read is not compiled into the current binary " <<
00515 std::endl;
00516 return 0;
00517 #endif
00518 }
00519
00520
00525 UInt64 JPGImageFileType::storeData(const ImagePtr &OSG_JPG_ARG(image ),
00526 UChar8 *OSG_JPG_ARG(buffer ),
00527 Int32 OSG_JPG_ARG(memSize))
00528 {
00529 #ifdef OSG_WITH_JPG
00530 if((image->getBpp() != 1 && image->getBpp() != 3)
00531 || image->getDepth() != 1)
00532 {
00533 SWARNING <<
00534 getMimeType() <<
00535 " JPEG storeData only works for 2D 1 or 3 bpp images " <<
00536 std::endl;
00537 return 0;
00538 }
00539
00540 struct local_error_mgr
00541 {
00542 struct jpeg_error_mgr pub;
00543 jmp_buf setjmp_buffer;
00544 };
00545
00546 typedef struct local_error_mgr *local_error_ptr;
00547
00548 struct local_error_mgr jerr;
00549 struct jpeg_compress_struct cinfo;
00550 JSAMPARRAY imagebuffer;
00551 UChar8 *data;
00552
00553 cinfo.err = jpeg_std_error(&jerr.pub);
00554 if(setjmp(jerr.setjmp_buffer))
00555 {
00556 jpeg_destroy_compress(&cinfo);
00557 return 0;
00558 }
00559
00560 jpeg_create_compress(&cinfo);
00561 jpeg_memory_dest(&cinfo, buffer, memSize);
00562
00563 cinfo.image_width = image->getWidth();
00564 cinfo.image_height = image->getHeight();
00565 cinfo.input_components = image->getBpp();
00566 cinfo.in_color_space = (image->getBpp() == 1) ? JCS_GRAYSCALE : JCS_RGB;
00567
00568 jpeg_set_defaults(&cinfo);
00569 jpeg_set_quality(&cinfo, _quality, TRUE);
00570 jpeg_start_compress(&cinfo, TRUE);
00571
00572 imagebuffer = &data;
00573 while(cinfo.next_scanline < cinfo.image_height)
00574 {
00575 data = image->getData() +
00576 (image->getHeight() - 1 - cinfo.next_scanline) *
00577 image->getWidth() *
00578 image->getBpp();
00579 jpeg_write_scanlines(&cinfo, imagebuffer, 1);
00580 }
00581
00582 jpeg_finish_compress(&cinfo);
00583 jpeg_destroy_compress(&cinfo);
00584
00585 return jpeg_mem.dataSize;
00586
00587 #else
00588 SWARNING <<
00589 getMimeType() <<
00590 " write is not compiled into the current binary " <<
00591 std::endl;
00592 return 0;
00593 #endif
00594 }
00595
00596
00600 JPGImageFileType::JPGImageFileType( const Char8 *mimeType,
00601 const Char8 *suffixArray[],
00602 UInt16 suffixByteCount,
00603 UInt32 flags) :
00604 ImageFileType(mimeType, suffixArray, suffixByteCount, flags),
00605 _quality(90)
00606 {
00607 return;
00608 }
00609
00610
00614 JPGImageFileType::JPGImageFileType(const JPGImageFileType &obj) :
00615 ImageFileType(obj),
00616 _quality(obj._quality)
00617 {
00618 return;
00619 }
00620
00621
00625 JPGImageFileType::~JPGImageFileType(void)
00626 {
00627 return;
00628 }