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
00042 #ifdef __hpux // prevent int32 clash (model.h/tiff.h)
00043 #define _INT32
00044 #endif
00045
00046 #include <stdlib.h>
00047 #include <stdio.h>
00048
00049 #include "OSGConfig.h"
00050
00051 #include "OSGTIFImageFileType.h"
00052
00053 #ifdef OSG_WITH_TIF
00054 #include <tiffio.h>
00055 #endif
00056 #include <OSGLog.h>
00057
00058 #include <iostream>
00059
00060 #ifndef OSG_DO_DOC
00061 # ifdef OSG_WITH_TIF
00062 # define OSG_TIF_ARG(ARG) ARG
00063 # else
00064 # define OSG_TIF_ARG(ARG)
00065 # endif
00066 #else
00067 # define OSG_TIF_ARG(ARG) ARG
00068 #endif
00069
00070
00071 OSG_USING_NAMESPACE
00072
00073
00089 #ifdef OSG_WITH_TIF
00090
00091 static tsize_t isReadProc(thandle_t fd, tdata_t buf, tsize_t size)
00092 {
00093 std::istream *is = reinterpret_cast<std::istream*>(fd);
00094 is->read(static_cast<char*>(buf), size);
00095 return is->gcount();
00096 }
00097
00098 static tsize_t osReadProc(thandle_t fd, tdata_t buf, tsize_t size)
00099 {
00100 return 0;
00101 }
00102
00103 static tsize_t isWriteProc(thandle_t fd, tdata_t buf, tsize_t size)
00104 {
00105 return 0;
00106 }
00107
00108 static tsize_t osWriteProc(thandle_t fd, tdata_t buf, tsize_t size)
00109 {
00110 std::ostream *os = reinterpret_cast<std::ostream*>(fd);
00111 os->write(static_cast<char*>(buf), size);
00112 return os->good() ? size : 0;
00113 }
00114
00115 static toff_t isSeekProc(thandle_t fd, toff_t off, int i)
00116 {
00117 std::istream *is = reinterpret_cast<std::istream*>(fd);
00118 switch (i)
00119 {
00120 case SEEK_SET:
00121 is->seekg(off, std::ios::beg);
00122 break;
00123 case SEEK_CUR:
00124 is->seekg(off, std::ios::cur);
00125 break;
00126 case SEEK_END:
00127 is->seekg(off, std::ios::end);
00128 break;
00129 }
00130 return is->tellg();
00131 }
00132
00133 static toff_t osSeekProc(thandle_t fd, toff_t off, int i)
00134 {
00135 std::ostream *os = reinterpret_cast<std::ostream*>(fd);
00136 switch (i)
00137 {
00138 case SEEK_SET:
00139 os->seekp(off, std::ios::beg);
00140 break;
00141 case SEEK_CUR:
00142 os->seekp(off, std::ios::cur);
00143 break;
00144 case SEEK_END:
00145 os->seekp(off, std::ios::end);
00146 break;
00147 }
00148 return os->tellp();
00149 }
00150
00151 static int closeProc(thandle_t fd)
00152 {
00153 return 0;
00154 }
00155
00156 static toff_t isSizeProc(thandle_t fd)
00157 {
00158 std::istream *is = reinterpret_cast<std::istream*>(fd);
00159 std::ios::pos_type pos = is->tellg();
00160 is->seekg(0, std::ios::end);
00161 std::ios::pos_type size = is->tellg();
00162 is->seekg(pos, std::ios::beg);
00163 return size;
00164 }
00165
00166 static toff_t osSizeProc(thandle_t fd)
00167 {
00168 std::ostream *os = reinterpret_cast<std::ostream*>(fd);
00169 std::ios::pos_type pos = os->tellp();
00170 os->seekp(0, std::ios::end);
00171 std::ios::pos_type size = os->tellp();
00172 os->seekp(pos, std::ios::beg);
00173 return size;
00174 }
00175
00176 static int mapFileProc(thandle_t fd, tdata_t *buf, toff_t *size)
00177 {
00178 return 0;
00179 }
00180
00181 static void unmapFileProc(thandle_t fd, tdata_t buf, toff_t size) {}
00182
00183 static void warningHandler (const char *module, const char *fmt, va_list ap)
00184 {
00185 Char8 buffer[4096];
00186
00187 #ifdef OSG_HAS_VSNPRINTF
00188 vsnprintf(buffer, sizeof(buffer) - 1, fmt, ap);
00189 #else
00190 vsprintf(buffer, fmt, ap);
00191 #endif
00192
00193 FWARNING (("TiffLib: %s;%s\n", module ? module : "Mod", buffer));
00194 }
00195
00196 static void errorHandler (const char *module, const char *fmt, va_list ap)
00197 {
00198 Char8 buffer[4096];
00199
00200 #ifdef OSG_HAS_VSNPRINTF
00201 vsnprintf(buffer, sizeof(buffer) - 1, fmt, ap);
00202 #else
00203 vsprintf(buffer, fmt, ap);
00204 #endif
00205
00206 FFATAL (("TiffLib: %s;%s\n", module ? module : "Mod", buffer));
00207 }
00208
00209 #endif // OSG_WITH_TIF
00210
00211
00212 static const Char8 *suffixArray[] = {
00213 "tif", "tiff"
00214 };
00215
00216 TIFImageFileType TIFImageFileType:: _the("image/tiff",
00217 suffixArray, sizeof(suffixArray),
00218 OSG_READ_SUPPORTED |
00219 OSG_WRITE_SUPPORTED);
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00253 TIFImageFileType& TIFImageFileType::the(void)
00254 {
00255 return _the;
00256 }
00257
00258
00259
00260
00261
00262
00263
00268 bool TIFImageFileType::read(ImagePtr &OSG_TIF_ARG(image), std::istream &OSG_TIF_ARG(is),
00269 const std::string &OSG_TIF_ARG(mimetype))
00270 {
00271 bool valid = false;
00272
00273 #ifdef OSG_WITH_TIF
00274 TIFF *in = TIFFClientOpen("dummy", "rm", (thandle_t)&is,
00275 isReadProc, isWriteProc, isSeekProc, closeProc,
00276 isSizeProc, mapFileProc, unmapFileProc);
00277 UChar8 *data = 0, *line = 0, *dest;
00278 UInt32 w, h, u, v;
00279 Real32 res_x, res_y;
00280 UInt16 res_unit;
00281 UInt16 bpp;
00282 Char8 errorMessage[1024];
00283 UInt16 *sampleinfo;
00284 UInt16 extrasamples;
00285 UInt16 si;
00286 UInt16 red, green, blue, alpha;
00287
00288 if(in)
00289 {
00290 TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &w);
00291 TIFFGetField(in, TIFFTAG_IMAGELENGTH, &h);
00292
00293 TIFFGetField(in, TIFFTAG_XRESOLUTION, &res_x);
00294 TIFFGetField(in, TIFFTAG_YRESOLUTION, &res_y);
00295 TIFFGetField(in, TIFFTAG_RESOLUTIONUNIT, &res_unit);
00296
00297 TIFFGetFieldDefaulted(in, TIFFTAG_SAMPLESPERPIXEL, &bpp);
00298
00299 if(bpp == 4)
00300 {
00301 TIFFGetFieldDefaulted(in, TIFFTAG_EXTRASAMPLES, &extrasamples,
00302 &sampleinfo);
00303
00304 if(sampleinfo && sampleinfo[0] == EXTRASAMPLE_UNSPECIFIED)
00305 {
00306 si = EXTRASAMPLE_ASSOCALPHA;
00307 TIFFSetField(in, TIFFTAG_EXTRASAMPLES, 1, &si);
00308 }
00309 }
00310
00311 data = new UChar8[w * h * 4];
00312 if(TIFFRGBAImageOK(in, errorMessage) &&
00313 TIFFReadRGBAImage(in, w, h, (uint32 *) data, 1))
00314 valid = true;
00315 else
00316 {
00317 SWARNING << "Tiff reader failed: " << errorMessage << std::endl;
00318 valid = false;
00319 }
00320
00321 if(valid)
00322 {
00323 Image::PixelFormat type = osg::Image::OSG_INVALID_PF;
00324 switch(bpp)
00325 {
00326 case 1:
00327 type = Image::OSG_L_PF;
00328 break;
00329 case 2:
00330 type = Image::OSG_LA_PF;
00331 break;
00332 case 3:
00333 type = Image::OSG_RGB_PF;
00334 break;
00335 case 4:
00336 type = Image::OSG_RGBA_PF;
00337 break;
00338 }
00339
00340 image->set(type, w, h);
00341 if(res_unit == RESUNIT_CENTIMETER)
00342 {
00343
00344 res_x *= 2.54f;
00345 res_y *= 2.54f;
00346 res_unit = Image::OSG_RESUNIT_INCH;
00347 }
00348 image->setResX(res_x);
00349 image->setResY(res_y);
00350 image->setResUnit(res_unit);
00351 dest = image->getData();
00352
00353 #if defined(__linux) || defined(_WIN32)
00354 red = 0;
00355 green = 1;
00356 blue = 2;
00357 alpha = 3;
00358
00359 #else
00360 red = 3;
00361 green = 2;
00362 blue = 1;
00363 alpha = 0;
00364 #endif
00365 for(v = 0; v < h; v++)
00366 {
00367 line = data + ((v) * (w * 4));
00368 for(u = 0; u < w; u++)
00369 {
00370 switch(bpp)
00371 {
00372 case 4:
00373 *dest++ = line[red];
00374 *dest++ = line[green];
00375 *dest++ = line[blue];
00376 *dest++ = line[alpha];
00377 break;
00378 case 3:
00379 *dest++ = line[red];
00380 *dest++ = line[green];
00381 *dest++ = line[blue];
00382 break;
00383 case 2:
00384 *dest++ = line[red];
00385 *dest++ = line[green];
00386 break;
00387 case 1:
00388 *dest++ = line[red];
00389 break;
00390 }
00391
00392 line += 4;
00393 }
00394 }
00395
00396 TIFFClose(in);
00397 delete[] data;
00398 data = 0;
00399 }
00400 }
00401
00402 #else
00403 SWARNING <<
00404 getMimeType() <<
00405 " read is not compiled into the current binary " <<
00406 std::endl;
00407 #endif
00408 return valid;
00409 }
00410
00411
00416 bool TIFImageFileType::write(const ImagePtr &OSG_TIF_ARG(image), std::ostream &OSG_TIF_ARG(os),
00417 const std::string &OSG_TIF_ARG(mimetype))
00418 {
00419 bool retCode = false;
00420
00421 #ifdef OSG_WITH_TIF
00422
00423 if(image->getDimension() < 1 || image->getDimension() > 2)
00424 {
00425 FWARNING(("TIFImageFileType::write: invalid dimension %d!\n",
00426 image->getDimension()));
00427 return false;
00428 }
00429
00430 TIFF *out = TIFFClientOpen("dummy", "wm", (thandle_t)&os,
00431 osReadProc, osWriteProc, osSeekProc, closeProc,
00432 osSizeProc, mapFileProc, unmapFileProc);
00433 int lineSize = image->getWidth() * image->getBpp();
00434 int photometric = 0, samplesPerPixel = 0;
00435 const UChar8 *data;
00436 int row;
00437
00438
00439 switch(image->getBpp())
00440 {
00441 case 1:
00442 samplesPerPixel = 1;
00443 photometric = PHOTOMETRIC_MINISBLACK;
00444 break;
00445 case 2:
00446 samplesPerPixel = 2;
00447 photometric = PHOTOMETRIC_MINISBLACK;
00448 break;
00449 case 3:
00450 samplesPerPixel = 3;
00451 photometric = PHOTOMETRIC_RGB;
00452 break;
00453 case 4:
00454 samplesPerPixel = 4;
00455 photometric = PHOTOMETRIC_RGB;
00456 break;
00457 }
00458
00459 if(out)
00460 {
00461 TIFFSetField(out, TIFFTAG_IMAGEWIDTH, image->getWidth());
00462 TIFFSetField(out, TIFFTAG_IMAGELENGTH, image->getHeight());
00463 TIFFSetField(out, TIFFTAG_XRESOLUTION, image->getResX());
00464 TIFFSetField(out, TIFFTAG_YRESOLUTION, image->getResY());
00465 TIFFSetField(out, TIFFTAG_RESOLUTIONUNIT, image->getResUnit());
00466 TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
00467 TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, samplesPerPixel);
00468 TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 8);
00469 TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
00470 TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric);
00471
00472 if(_options.find("compressionType=LZW") != std::string::npos)
00473 TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
00474 else
00475 TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
00476
00477 TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(out, 0));
00478
00479 for(row = 0; row < image->getHeight(); row++)
00480 {
00481 data = image->getData() + ((image->getHeight() - row - 1) * lineSize);
00482 if(TIFFWriteScanline(out,
00483 (tdata_t) const_cast<UChar8 *>(data),
00484 row,
00485 0) < 0)
00486 break;
00487 }
00488
00489 TIFFClose(out);
00490 retCode = true;
00491 }
00492
00493 #else
00494 SWARNING <<
00495 getMimeType() <<
00496 " write is not compiled into the current binary " <<
00497 std::endl;
00498 #endif
00499 return retCode;
00500 }
00501
00502
00508 std::string TIFImageFileType::determineMimetypeFromStream(std::istream &is)
00509 {
00510 char filecode[4];
00511 is.read(filecode, 4);
00512 is.seekg(-4, std::ios::cur);
00513 if (strncmp(filecode, "MM\x00\x2a", 4) == 0)
00514 return std::string(getMimeType());
00515 if (strncmp(filecode, "II\x2a\x00", 4) == 0)
00516 return std::string(getMimeType());
00517 return std::string();
00518 }
00519
00520
00521
00522 bool TIFImageFileType::validateHeader( const Char8 *fileName, bool &implemented)
00523 {
00524 implemented = true;
00525
00526 if(fileName == NULL)
00527 return false;
00528
00529 FILE *file = fopen(fileName, "rb");
00530 if(file == NULL)
00531 return false;
00532
00533 std::string magic;
00534 magic.resize(2);
00535 fread((void *) &magic[0], 2, 1, file);
00536 fclose(file);
00537
00538 if(magic == "MM" || magic == "II")
00539 {
00540 return true;
00541 }
00542
00543 return false;
00544 }
00545
00546
00550 TIFImageFileType::TIFImageFileType(const Char8 *mimeType,
00551 const Char8 *suffixArray[],
00552 UInt16 suffixByteCount,
00553 UInt32 flags) :
00554 ImageFileType(mimeType, suffixArray, suffixByteCount, flags)
00555 {
00556 #ifdef OSG_WITH_TIF
00557 TIFFSetWarningHandler(&warningHandler);
00558 TIFFSetErrorHandler(&errorHandler);
00559 #endif
00560 }
00561
00562
00566 TIFImageFileType::~TIFImageFileType(void) {}