1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/common/imagtiff.cpp 
   3 // Purpose:     wxImage TIFF handler 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) Robert Roebling 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  10 // For compilers that support precompilation, includes "wx.h". 
  11 #include "wx/wxprec.h" 
  17 #if wxUSE_IMAGE && wxUSE_LIBTIFF 
  19 #include "wx/imagtiff.h" 
  25     #include "wx/bitmap.h" 
  33 #include "wx/filefn.h" 
  34 #include "wx/wfstream.h" 
  35 #include "wx/module.h" 
  37 #ifndef TIFFLINKAGEMODE 
  38     #if defined(__WATCOMC__) && defined(__WXMGL__) 
  39         #define TIFFLINKAGEMODE cdecl 
  41         #define TIFFLINKAGEMODE LINKAGEMODE 
  45 //----------------------------------------------------------------------------- 
  47 //----------------------------------------------------------------------------- 
  49 IMPLEMENT_DYNAMIC_CLASS(wxTIFFHandler
,wxImageHandler
) 
  53 // helper to translate our, possibly 64 bit, wxFileOffset to TIFF, always 32 
  55 static toff_t 
wxFileOffsetToTIFF(wxFileOffset ofs
) 
  57     if ( ofs 
== wxInvalidOffset 
) 
  60     toff_t tofs 
= wx_truncate_cast(toff_t
, ofs
); 
  61     wxCHECK_MSG( (wxFileOffset
)tofs 
== ofs
, (toff_t
)-1, 
  62                     _T("TIFF library doesn't support large files") ); 
  67 // another helper to convert standard seek mode to our 
  68 static wxSeekMode 
wxSeekModeFromTIFF(int whence
) 
  89 tsize_t TIFFLINKAGEMODE
 
  90 _tiffNullProc(thandle_t 
WXUNUSED(handle
), 
  91           tdata_t 
WXUNUSED(buf
), 
  92           tsize_t 
WXUNUSED(size
)) 
  97 tsize_t TIFFLINKAGEMODE
 
  98 _tiffReadProc(thandle_t handle
, tdata_t buf
, tsize_t size
) 
 100     wxInputStream 
*stream 
= (wxInputStream
*) handle
; 
 101     stream
->Read( (void*) buf
, (size_t) size 
); 
 102     return wx_truncate_cast(tsize_t
, stream
->LastRead()); 
 105 tsize_t TIFFLINKAGEMODE
 
 106 _tiffWriteProc(thandle_t handle
, tdata_t buf
, tsize_t size
) 
 108     wxOutputStream 
*stream 
= (wxOutputStream
*) handle
; 
 109     stream
->Write( (void*) buf
, (size_t) size 
); 
 110     return wx_truncate_cast(tsize_t
, stream
->LastWrite()); 
 113 toff_t TIFFLINKAGEMODE
 
 114 _tiffSeekIProc(thandle_t handle
, toff_t off
, int whence
) 
 116     wxInputStream 
*stream 
= (wxInputStream
*) handle
; 
 118     return wxFileOffsetToTIFF(stream
->SeekI((wxFileOffset
)off
, 
 119                                             wxSeekModeFromTIFF(whence
))); 
 122 toff_t TIFFLINKAGEMODE
 
 123 _tiffSeekOProc(thandle_t handle
, toff_t off
, int whence
) 
 125     wxOutputStream 
*stream 
= (wxOutputStream
*) handle
; 
 127     return wxFileOffsetToTIFF(stream
->SeekO((wxFileOffset
)off
, 
 128                                             wxSeekModeFromTIFF(whence
))); 
 132 _tiffCloseProc(thandle_t 
WXUNUSED(handle
)) 
 137 toff_t TIFFLINKAGEMODE
 
 138 _tiffSizeProc(thandle_t handle
) 
 140     wxStreamBase 
*stream 
= (wxStreamBase
*) handle
; 
 141     return (toff_t
) stream
->GetSize(); 
 145 _tiffMapProc(thandle_t 
WXUNUSED(handle
), 
 146              tdata_t
* WXUNUSED(pbase
), 
 147              toff_t
* WXUNUSED(psize
)) 
 153 _tiffUnmapProc(thandle_t 
WXUNUSED(handle
), 
 154                tdata_t 
WXUNUSED(base
), 
 155                toff_t 
WXUNUSED(size
)) 
 160 TIFFwxWarningHandler(const char* module, 
 161                      const char* WXUNUSED_IN_UNICODE(fmt
), 
 162                      va_list WXUNUSED_IN_UNICODE(ap
)) 
 165         wxLogWarning(_("tiff module: %s"), wxString::FromAscii(module).c_str()); 
 167     // FIXME: this is not terrible informative but better than crashing! 
 169     wxLogWarning(_("TIFF library warning.")); 
 171     wxVLogWarning(fmt
, ap
); 
 176 TIFFwxErrorHandler(const char* module, 
 177                    const char* WXUNUSED_IN_UNICODE(fmt
), 
 178                    va_list WXUNUSED_IN_UNICODE(ap
)) 
 181         wxLogError(_("tiff module: %s"), wxString::FromAscii(module).c_str()); 
 185     wxLogError(_("TIFF library error.")); 
 187     wxVLogError(fmt
, ap
); 
 194 TIFFwxOpen(wxInputStream 
&stream
, const char* name
, const char* mode
) 
 196     TIFF
* tif 
= TIFFClientOpen(name
, mode
, 
 198         _tiffReadProc
, _tiffNullProc
, 
 199         _tiffSeekIProc
, _tiffCloseProc
, _tiffSizeProc
, 
 200         _tiffMapProc
, _tiffUnmapProc
); 
 206 TIFFwxOpen(wxOutputStream 
&stream
, const char* name
, const char* mode
) 
 208     TIFF
* tif 
= TIFFClientOpen(name
, mode
, 
 210         _tiffNullProc
, _tiffWriteProc
, 
 211         _tiffSeekOProc
, _tiffCloseProc
, _tiffSizeProc
, 
 212         _tiffMapProc
, _tiffUnmapProc
); 
 217 wxTIFFHandler::wxTIFFHandler() 
 219     m_name 
= wxT("TIFF file"); 
 220     m_extension 
= wxT("tif"); 
 221     m_type 
= wxBITMAP_TYPE_TIF
; 
 222     m_mime 
= wxT("image/tiff"); 
 223     TIFFSetWarningHandler((TIFFErrorHandler
) TIFFwxWarningHandler
); 
 224     TIFFSetErrorHandler((TIFFErrorHandler
) TIFFwxErrorHandler
); 
 227 bool wxTIFFHandler::LoadFile( wxImage 
*image
, wxInputStream
& stream
, bool verbose
, int index 
) 
 234     TIFF 
*tif 
= TIFFwxOpen( stream
, "image", "r" ); 
 239             wxLogError( _("TIFF: Error loading image.") ); 
 244     if (!TIFFSetDirectory( tif
, (tdir_t
)index 
)) 
 247             wxLogError( _("Invalid TIFF image index.") ); 
 258     TIFFGetField( tif
, TIFFTAG_IMAGEWIDTH
, &w 
); 
 259     TIFFGetField( tif
, TIFFTAG_IMAGELENGTH
, &h 
); 
 263     raster 
= (uint32
*) _TIFFmalloc( npixels 
* sizeof(uint32
) ); 
 268             wxLogError( _("TIFF: Couldn't allocate memory.") ); 
 275     image
->Create( (int)w
, (int)h 
); 
 279             wxLogError( _("TIFF: Couldn't allocate memory.") ); 
 287     if (!TIFFReadRGBAImage( tif
, w
, h
, raster
, 0 )) 
 290             wxLogError( _("TIFF: Error reading image.") ); 
 299     bool hasmask 
= false; 
 301     unsigned char *ptr 
= image
->GetData(); 
 305     for (uint32 i 
= 0; i 
< h
; i
++) 
 307         for (uint32 j 
= 0; j 
< w
; j
++) 
 309             unsigned char alpha 
= (unsigned char)TIFFGetA(raster
[pos
]); 
 313                 ptr
[0] = image
->GetMaskRed(); 
 315                 ptr
[0] = image
->GetMaskGreen(); 
 317                 ptr
[0] = image
->GetMaskBlue(); 
 322                 ptr
[0] = (unsigned char)TIFFGetR(raster
[pos
]); 
 324                 ptr
[0] = (unsigned char)TIFFGetG(raster
[pos
]); 
 326                 ptr
[0] = (unsigned char)TIFFGetB(raster
[pos
]); 
 331         ptr 
-= 2*w
*3; // subtract line we just added plus one line 
 338     image
->SetMask( hasmask 
); 
 343 int wxTIFFHandler::GetImageCount( wxInputStream
& stream 
) 
 345     TIFF 
*tif 
= TIFFwxOpen( stream
, "image", "r" ); 
 350     int dircount 
= 0;  // according to the libtiff docs, dircount should be set to 1 here??? 
 353     } while (TIFFReadDirectory(tif
)); 
 360 bool wxTIFFHandler::SaveFile( wxImage 
*image
, wxOutputStream
& stream
, bool verbose 
) 
 362     TIFF 
*tif 
= TIFFwxOpen( stream
, "image", "w" ); 
 367             wxLogError( _("TIFF: Error saving image.") ); 
 372     TIFFSetField(tif
, TIFFTAG_ORIENTATION
, ORIENTATION_TOPLEFT
); 
 373     TIFFSetField(tif
, TIFFTAG_IMAGEWIDTH
,  (uint32
)image
->GetWidth()); 
 374     TIFFSetField(tif
, TIFFTAG_IMAGELENGTH
, (uint32
)image
->GetHeight()); 
 375     TIFFSetField(tif
, TIFFTAG_ORIENTATION
, ORIENTATION_TOPLEFT
); 
 376     TIFFSetField(tif
, TIFFTAG_PLANARCONFIG
, PLANARCONFIG_CONTIG
); 
 378     if ( image
->HasOption(wxIMAGE_OPTION_RESOLUTIONX
) && 
 379             image
->HasOption(wxIMAGE_OPTION_RESOLUTIONY
) ) 
 381         TIFFSetField(tif
, TIFFTAG_XRESOLUTION
, 
 382                         (float)image
->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONX
)); 
 383         TIFFSetField(tif
, TIFFTAG_YRESOLUTION
, 
 384                         (float)image
->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONY
)); 
 387     int spp 
= image
->GetOptionInt(wxIMAGE_OPTION_SAMPLESPERPIXEL
); 
 391     int bpp 
= image
->GetOptionInt(wxIMAGE_OPTION_BITSPERSAMPLE
); 
 395     int compression 
= image
->GetOptionInt(wxIMAGE_OPTION_COMPRESSION
); 
 398         // we can't use COMPRESSION_LZW because current version of libtiff 
 399         // doesn't implement it ("no longer implemented due to Unisys patent 
 400         // enforcement") and other compression methods are lossy so we 
 401         // shouldn't use them by default -- and the only remaining one is none 
 402         compression 
= COMPRESSION_NONE
; 
 405     TIFFSetField(tif
, TIFFTAG_SAMPLESPERPIXEL
, spp
); 
 406     TIFFSetField(tif
, TIFFTAG_BITSPERSAMPLE
, bpp
); 
 407     TIFFSetField(tif
, TIFFTAG_PHOTOMETRIC
, spp
*bpp 
== 1 ? PHOTOMETRIC_MINISBLACK
 
 409     TIFFSetField(tif
, TIFFTAG_COMPRESSION
, compression
); 
 411     // scanlinesize if determined by spp and bpp 
 412     tsize_t linebytes 
= (tsize_t
)image
->GetWidth() * spp 
* bpp 
/ 8; 
 414     if ( (image
->GetWidth() % 8 > 0) && (spp 
* bpp 
< 8) ) 
 419     if (TIFFScanlineSize(tif
) > linebytes 
|| (spp 
* bpp 
< 24)) 
 421         buf 
= (unsigned char *)_TIFFmalloc(TIFFScanlineSize(tif
)); 
 425                 wxLogError( _("TIFF: Couldn't allocate memory.") ); 
 437     TIFFSetField(tif
, TIFFTAG_ROWSPERSTRIP
,TIFFDefaultStripSize(tif
, (uint32
) -1)); 
 439     unsigned char *ptr 
= image
->GetData(); 
 440     for ( int row 
= 0; row 
< image
->GetHeight(); row
++ ) 
 447                 memcpy(buf
, ptr
, image
->GetWidth()); 
 449             else // black and white image 
 451                 for ( int column 
= 0; column 
< linebytes
; column
++ ) 
 454                     for ( int bp 
= 0; bp 
< 8; bp
++ ) 
 456                         if ( ptr
[column
*24 + bp
*3] > 0 ) 
 458                             // check only red as this is sufficient 
 459                             reverse 
= (uint8
)(reverse 
| 128 >> bp
); 
 463                     buf
[column
] = reverse
; 
 468         if ( TIFFWriteScanline(tif
, buf 
? buf 
: ptr
, (uint32
)row
, 0) < 0 ) 
 471                 wxLogError( _("TIFF: Error writing image.") ); 
 480         ptr 
+= image
->GetWidth()*3; 
 483     (void) TIFFClose(tif
); 
 491 bool wxTIFFHandler::DoCanRead( wxInputStream
& stream 
) 
 493     unsigned char hdr
[2]; 
 495     if ( !stream
.Read(&hdr
[0], WXSIZEOF(hdr
)) ) 
 498     return (hdr
[0] == 'I' && hdr
[1] == 'I') || 
 499            (hdr
[0] == 'M' && hdr
[1] == 'M'); 
 502 #endif  // wxUSE_STREAMS 
 504 #endif  // wxUSE_LIBTIFF