fixed: auto_ptr -> unique_ptr
[opensg.git] / Source / System / Image / FileIO / OSGTIFImageFileType.cpp
blobf2266f015ac14ac404cfee256a6417498fe44ede
1 /*---------------------------------------------------------------------------*\
2 * OpenSG *
3 * *
4 * *
5 * Copyright (C) 2000-2002 by the OpenSG Forum *
6 * *
7 * www.opensg.org *
8 * *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
10 * *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
13 * License *
14 * *
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. *
18 * *
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. *
23 * *
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. *
27 * *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
30 * Changes *
31 * *
32 * *
33 * *
34 * *
35 * *
36 * *
37 \*---------------------------------------------------------------------------*/
38 //-------------------------------
39 // Includes
40 //-------------------------------
42 #ifdef __hpux // prevent int32 clash (model.h/tiff.h)
43 #define _INT32
44 #endif
46 #include <cstdlib>
47 #include <cstdio>
49 #include "OSGConfig.h"
51 #include "OSGTIFImageFileType.h"
53 #ifdef OSG_WITH_TIF
54 #include <tiffio.h>
55 #endif
56 #include "OSGLog.h"
58 #ifndef OSG_DO_DOC
59 # ifdef OSG_WITH_TIF
60 # define OSG_TIF_ARG(ARG) ARG
61 # else
62 # define OSG_TIF_ARG(ARG)
63 # endif
64 #else
65 # define OSG_TIF_ARG(ARG) ARG
66 #endif
68 // Static Class Varible implementations:
69 static const OSG::Char8 *suffixArray[] =
71 "tif", "tiff"
74 OSG_BEGIN_NAMESPACE
77 /*! \class TIFImageFileType
79 Image File Type to read/write and store/restore Image objects as
80 TIF (tif/tiff suffix) data.
82 To be able to load TIFF images you need the IJG TIFF library,
83 (check the Prerequisites page on www.opensg.org).
84 The lib comes with all Linux distributions.
86 You have to --enable-tif in the configure line to enable
87 the singleton object.
91 #ifdef OSG_WITH_TIF
93 static tsize_t isReadProc(thandle_t fd, tdata_t buf, tsize_t size)
95 std::istream *is = reinterpret_cast<std::istream*>(fd);
96 is->read(static_cast<char*>(buf), size);
97 return is->gcount();
100 static tsize_t osReadProc(thandle_t fd, tdata_t buf, tsize_t size)
102 return 0;
105 static tsize_t isWriteProc(thandle_t fd, tdata_t buf, tsize_t size)
107 return 0;
110 static tsize_t osWriteProc(thandle_t fd, tdata_t buf, tsize_t size)
112 std::ostream *os = reinterpret_cast<std::ostream*>(fd);
113 os->write(static_cast<char*>(buf), size);
114 return os->good() ? size : 0;
117 static toff_t isSeekProc(thandle_t fd, toff_t off, int i)
119 std::istream *is = reinterpret_cast<std::istream*>(fd);
120 switch (i)
122 case SEEK_SET:
123 is->seekg(off, std::ios::beg);
124 break;
125 case SEEK_CUR:
126 is->seekg(off, std::ios::cur);
127 break;
128 case SEEK_END:
129 is->seekg(off, std::ios::end);
130 break;
132 return is->tellg();
135 static toff_t osSeekProc(thandle_t fd, toff_t off, int i)
137 std::ostream *os = reinterpret_cast<std::ostream*>(fd);
138 switch (i)
140 case SEEK_SET:
141 os->seekp(off, std::ios::beg);
142 break;
143 case SEEK_CUR:
144 os->seekp(off, std::ios::cur);
145 break;
146 case SEEK_END:
147 os->seekp(off, std::ios::end);
148 break;
150 return os->tellp();
153 static int closeProc(thandle_t fd)
155 return 0; // no action necessary
158 static toff_t isSizeProc(thandle_t fd)
160 std::istream *is = reinterpret_cast<std::istream*>(fd);
161 std::ios::pos_type pos = is->tellg();
162 is->seekg(0, std::ios::end);
163 std::ios::pos_type size = is->tellg();
164 is->seekg(pos, std::ios::beg);
165 return size;
168 static toff_t osSizeProc(thandle_t fd)
170 std::ostream *os = reinterpret_cast<std::ostream*>(fd);
171 std::ios::pos_type pos = os->tellp();
172 os->seekp(0, std::ios::end);
173 std::ios::pos_type size = os->tellp();
174 os->seekp(pos, std::ios::beg);
175 return size;
178 static int mapFileProc(thandle_t fd, tdata_t *buf, toff_t *size)
180 return 0;
183 static void unmapFileProc(thandle_t fd, tdata_t buf, toff_t size)
187 static void warningHandler(const char *module, const char *fmt, va_list ap)
189 Char8 buffer[4096];
191 #ifdef OSG_HAS_VSNPRINTF
192 vsnprintf(buffer, sizeof(buffer) - 1, fmt, ap);
193 #else
194 vsprintf(buffer, fmt, ap);
195 #endif
197 FWARNING(("TiffLib: %s;%s\n", module ? module : "Mod", buffer));
200 static void errorHandler(const char *module, const char *fmt, va_list ap)
202 Char8 buffer[4096];
204 #ifdef OSG_HAS_VSNPRINTF
205 vsnprintf(buffer, sizeof(buffer) - 1, fmt, ap);
206 #else
207 vsprintf(buffer, fmt, ap);
208 #endif
210 FFATAL(("TiffLib: %s;%s\n", module ? module : "Mod", buffer));
212 #endif // OSG_WITH_TIF
215 TIFImageFileType TIFImageFileType:: _the("image/tiff",
216 suffixArray,
217 sizeof(suffixArray),
218 (OSG_READ_SUPPORTED |
219 OSG_WRITE_SUPPORTED));
222 //-------------------------------------------------------------------------
223 /*! Tries to fill the image object with the data read from
224 the given fileName. Returns true on success.
227 bool TIFImageFileType::read( Image *OSG_TIF_ARG(pImage),
228 std::istream &OSG_TIF_ARG(is),
229 const std::string &OSG_TIF_ARG(mimetype))
231 #ifdef OSG_WITH_TIF
233 TIFF *in = TIFFClientOpen("dummy", "rm", thandle_t(&is),
234 isReadProc,
235 isWriteProc,
236 isSeekProc,
237 closeProc,
238 isSizeProc,
239 mapFileProc,
240 unmapFileProc);
241 if (in == 0)
242 return false;
244 uint32 w, h;
245 TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &w);
246 TIFFGetField(in, TIFFTAG_IMAGELENGTH, &h);
248 float res_x, res_y;
249 uint16 res_unit;
250 TIFFGetField(in, TIFFTAG_XRESOLUTION, &res_x);
251 TIFFGetField(in, TIFFTAG_YRESOLUTION, &res_y);
252 TIFFGetField(in, TIFFTAG_RESOLUTIONUNIT, &res_unit);
253 if (res_unit == RESUNIT_CENTIMETER)
255 // convert it to dpi.
256 res_x *= 2.54f;
257 res_y *= 2.54f;
258 res_unit = Image::OSG_RESUNIT_INCH;
261 uint16 bpp;
262 TIFFGetFieldDefaulted(in, TIFFTAG_SAMPLESPERPIXEL, &bpp);
263 if (bpp == 4)
264 { // accept unspecified extra samples as associated alpha
265 uint16 *sampleinfo;
266 uint16 extrasamples;
267 TIFFGetFieldDefaulted(in,
268 TIFFTAG_EXTRASAMPLES,
269 &extrasamples,
270 &sampleinfo);
271 if (sampleinfo && sampleinfo[0] == EXTRASAMPLE_UNSPECIFIED)
273 uint16 si = EXTRASAMPLE_ASSOCALPHA;
274 TIFFSetField(in, TIFFTAG_EXTRASAMPLES, 1, &si);
277 Image::PixelFormat type = Image::OSG_INVALID_PF;
278 switch (bpp)
280 case 1:
281 type = Image::OSG_L_PF;
282 break;
283 case 2:
284 type = Image::OSG_LA_PF;
285 break;
286 case 3:
287 type = Image::OSG_RGB_PF;
288 break;
289 case 4:
290 type = Image::OSG_RGBA_PF;
291 break;
294 char errorMessage[1024];
295 if (TIFFRGBAImageOK(in, errorMessage) == 0)
297 SWARNING << "Tiff reader failed: " << errorMessage << std::endl;
298 TIFFClose(in);
299 return false;
302 UInt32 numPixels = w * h;
303 uint32 *buffer = new uint32[numPixels];
304 if (TIFFReadRGBAImage(in, w, h, buffer, 1) == 0)
306 delete [] buffer;
307 TIFFClose(in);
308 return false;
311 TIFFClose(in);
313 pImage->set(type, w, h);
314 pImage->setResX(res_x);
315 pImage->setResY(res_y);
316 pImage->setResUnit(res_unit);
318 UChar8 *dst = pImage->editData();
319 uint32 *src = buffer;
320 switch (bpp)
322 case 4:
323 for (UInt32 i = numPixels; i > 0; --i)
325 *dst++ = TIFFGetR(*src);
326 *dst++ = TIFFGetG(*src);
327 *dst++ = TIFFGetB(*src);
328 *dst++ = TIFFGetA(*src++);
330 break;
331 case 3:
332 for (UInt32 i = numPixels; i > 0; --i)
334 *dst++ = TIFFGetR(*src);
335 *dst++ = TIFFGetG(*src);
336 *dst++ = TIFFGetB(*src++);
338 break;
339 case 2:
340 for (UInt32 i = numPixels; i > 0; --i)
342 *dst++ = TIFFGetG(*src);
343 *dst++ = TIFFGetA(*src++);
345 break;
346 case 1:
347 for (UInt32 i = numPixels; i > 0; --i)
348 *dst++ = TIFFGetG(*src++);
349 break;
352 delete [] buffer;
354 return true;
356 #else
358 SWARNING << getMimeType()
359 << " read is not compiled into the current binary "
360 << std::endl;
361 return false;
363 #endif // OSG_WITH_TIF
366 //-------------------------------------------------------------------------
367 /*! Tries to write the image object to the given output stream.
368 Returns true on success.
371 bool TIFImageFileType::write(const Image *OSG_TIF_ARG(pImage),
372 std::ostream &OSG_TIF_ARG(os),
373 const std::string &OSG_TIF_ARG(mimetype))
375 bool retCode = false;
377 #ifdef OSG_WITH_TIF
378 if(pImage->getDimension() < 1 || pImage->getDimension() > 2)
380 FWARNING(("TIFImageFileType::write: invalid dimension %d!\n",
381 pImage->getDimension()));
383 return false;
386 TIFF *out = TIFFClientOpen("dummy", "wm", thandle_t(&os),
387 osReadProc,
388 osWriteProc,
389 osSeekProc,
390 closeProc,
391 osSizeProc,
392 mapFileProc,
393 unmapFileProc);
395 int lineSize = pImage->getWidth() * pImage->getBpp();
396 int photometric = 0;
397 int samplesPerPixel = 0;
398 const UChar8 *data;
399 int row;
401 // TODO: implement all cases correct
402 switch(pImage->getBpp())
404 case 1:
405 samplesPerPixel = 1;
406 photometric = PHOTOMETRIC_MINISBLACK;
407 break;
408 case 2:
409 samplesPerPixel = 2;
410 photometric = PHOTOMETRIC_MINISBLACK;
411 break;
412 case 3:
413 samplesPerPixel = 3;
414 photometric = PHOTOMETRIC_RGB;
415 break;
416 case 4:
417 samplesPerPixel = 4;
418 photometric = PHOTOMETRIC_RGB;
419 break;
420 case 12: // RGB 32bit float
421 samplesPerPixel = 3;
422 photometric = PHOTOMETRIC_RGB;
423 break;
424 case 16: // RGBA 32bit float
425 samplesPerPixel = 4;
426 photometric = PHOTOMETRIC_RGB;
427 break;
430 int bps = 8;
431 int fmt = SAMPLEFORMAT_UINT;
432 switch(pImage->getDataType())
434 case Image::OSG_UINT8_IMAGEDATA:
435 bps = 8;
436 fmt = SAMPLEFORMAT_UINT;
437 break;
438 case Image::OSG_FLOAT32_IMAGEDATA:
439 bps = 32;
440 fmt = SAMPLEFORMAT_IEEEFP;
441 break;
442 default:
443 FWARNING(("TIFImageFileType::write: image data type not "
444 "supported!\n"));
445 return false;
446 break;
449 if(out)
451 TIFFSetField(out, TIFFTAG_IMAGEWIDTH, pImage->getWidth());
452 TIFFSetField(out, TIFFTAG_IMAGELENGTH, pImage->getHeight());
453 TIFFSetField(out, TIFFTAG_XRESOLUTION, pImage->getResX());
454 TIFFSetField(out, TIFFTAG_YRESOLUTION, pImage->getResY());
455 TIFFSetField(out, TIFFTAG_RESOLUTIONUNIT, pImage->getResUnit());
456 TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
457 TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, samplesPerPixel);
458 TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, bps);
459 TIFFSetField(out, TIFFTAG_SAMPLEFORMAT, fmt);
460 TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
461 TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric);
463 std::string compressionType;
464 if(getOption("compressionType", compressionType) &&
465 compressionType == "LZW" )
467 TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
469 else
471 TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
474 TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(out, 0));
476 for(row = 0; row < pImage->getHeight(); row++)
478 data =
479 pImage->getData() +
480 ((pImage->getHeight() - row - 1) * lineSize);
482 if(TIFFWriteScanline(out,
483 tdata_t(const_cast<UChar8 *>(data)),
484 row,
485 0) < 0)
487 break;
491 TIFFClose(out);
493 retCode = true;
496 #else
497 SWARNING << getMimeType()
498 << " write is not compiled into the current binary "
499 << std::endl;
500 #endif
502 return retCode;
505 bool TIFImageFileType::validateHeader(const Char8 *fileName, bool &implemented)
507 implemented = true;
509 if(fileName == NULL)
510 return false;
512 FILE *file = fopen(fileName, "rb");
514 if(file == NULL)
515 return false;
517 std::string magic;
518 magic.resize(2);
519 fread(static_cast<void *>(&magic[0]), 2, 1, file);
520 fclose(file);
522 if(magic == "MM" || magic == "II")
524 return true;
527 return false;
530 //-------------------------------------------------------------------------
532 Tries to determine the mime type of the data provided by an input stream
533 by searching for magic bytes. Returns the mime type or an empty string
534 when the function could not determine the mime type.
537 std::string TIFImageFileType::determineMimetypeFromStream(std::istream &is)
539 char filecode[4];
541 is.read(filecode, 4);
542 is.seekg(-4, std::ios::cur);
544 if(strncmp(filecode, "MM\x00\x2a", 4) == 0)
545 return std::string(getMimeType());
547 if(strncmp(filecode, "II\x2a\x00", 4) == 0)
548 return std::string(getMimeType());
550 return std::string();
553 //-------------------------------------------------------------------------
554 /*! Constructor used for the singleton object
557 TIFImageFileType::TIFImageFileType(const Char8 *mimeType,
558 const Char8 *suffixArray[],
559 UInt16 suffixByteCount,
560 UInt32 flags) :
561 Inherited(mimeType,
562 suffixArray,
563 suffixByteCount,
564 flags )
566 static bool initTIFFLib = true;
568 #ifdef OSG_WITH_TIF
569 if(initTIFFLib)
571 initTIFFLib = false;
573 TIFFSetWarningHandler(&warningHandler);
574 TIFFSetErrorHandler (&errorHandler );
576 #endif
579 //-------------------------------------------------------------------------
580 /*! Destructor
583 TIFImageFileType::~TIFImageFileType(void)
587 OSG_END_NAMESPACE