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"
27 #include "wx/bitmap.h"
34 #include "wx/filefn.h"
35 #include "wx/wfstream.h"
36 #include "wx/module.h"
38 #ifndef TIFFLINKAGEMODE
39 #if defined(__WATCOMC__) && defined(__WXMGL__)
40 #define TIFFLINKAGEMODE cdecl
42 #define TIFFLINKAGEMODE LINKAGEMODE
46 //-----------------------------------------------------------------------------
48 //-----------------------------------------------------------------------------
50 IMPLEMENT_DYNAMIC_CLASS(wxTIFFHandler
,wxImageHandler
)
54 // helper to translate our, possibly 64 bit, wxFileOffset to TIFF, always 32
56 static toff_t
wxFileOffsetToTIFF(wxFileOffset ofs
)
58 if ( ofs
== wxInvalidOffset
)
61 toff_t tofs
= wx_truncate_cast(toff_t
, ofs
);
62 wxCHECK_MSG( (wxFileOffset
)tofs
== ofs
, (toff_t
)-1,
63 _T("TIFF library doesn't support large files") );
68 // another helper to convert standard seek mode to our
69 static wxSeekMode
wxSeekModeFromTIFF(int whence
)
90 tsize_t TIFFLINKAGEMODE
91 _tiffNullProc(thandle_t
WXUNUSED(handle
),
92 tdata_t
WXUNUSED(buf
),
93 tsize_t
WXUNUSED(size
))
98 tsize_t TIFFLINKAGEMODE
99 _tiffReadProc(thandle_t handle
, tdata_t buf
, tsize_t size
)
101 wxInputStream
*stream
= (wxInputStream
*) handle
;
102 stream
->Read( (void*) buf
, (size_t) size
);
103 return wx_truncate_cast(tsize_t
, stream
->LastRead());
106 tsize_t TIFFLINKAGEMODE
107 _tiffWriteProc(thandle_t handle
, tdata_t buf
, tsize_t size
)
109 wxOutputStream
*stream
= (wxOutputStream
*) handle
;
110 stream
->Write( (void*) buf
, (size_t) size
);
111 return wx_truncate_cast(tsize_t
, stream
->LastWrite());
114 toff_t TIFFLINKAGEMODE
115 _tiffSeekIProc(thandle_t handle
, toff_t off
, int whence
)
117 wxInputStream
*stream
= (wxInputStream
*) handle
;
119 return wxFileOffsetToTIFF(stream
->SeekI((wxFileOffset
)off
,
120 wxSeekModeFromTIFF(whence
)));
123 toff_t TIFFLINKAGEMODE
124 _tiffSeekOProc(thandle_t handle
, toff_t off
, int whence
)
126 wxOutputStream
*stream
= (wxOutputStream
*) handle
;
128 return wxFileOffsetToTIFF(stream
->SeekO((wxFileOffset
)off
,
129 wxSeekModeFromTIFF(whence
)));
133 _tiffCloseProc(thandle_t
WXUNUSED(handle
))
138 toff_t TIFFLINKAGEMODE
139 _tiffSizeProc(thandle_t handle
)
141 wxStreamBase
*stream
= (wxStreamBase
*) handle
;
142 return (toff_t
) stream
->GetSize();
146 _tiffMapProc(thandle_t
WXUNUSED(handle
),
147 tdata_t
* WXUNUSED(pbase
),
148 toff_t
* WXUNUSED(psize
))
154 _tiffUnmapProc(thandle_t
WXUNUSED(handle
),
155 tdata_t
WXUNUSED(base
),
156 toff_t
WXUNUSED(size
))
161 TIFFwxWarningHandler(const char* module,
162 const char* WXUNUSED_IN_UNICODE(fmt
),
163 va_list WXUNUSED_IN_UNICODE(ap
))
166 wxLogWarning(_("tiff module: %s"), wxString::FromAscii(module).c_str());
168 // FIXME: this is not terrible informative but better than crashing!
170 wxLogWarning(_("TIFF library warning."));
172 wxVLogWarning(fmt
, ap
);
177 TIFFwxErrorHandler(const char* module,
178 const char* WXUNUSED_IN_UNICODE(fmt
),
179 va_list WXUNUSED_IN_UNICODE(ap
))
182 wxLogError(_("tiff module: %s"), wxString::FromAscii(module).c_str());
186 wxLogError(_("TIFF library error."));
188 wxVLogError(fmt
, ap
);
195 TIFFwxOpen(wxInputStream
&stream
, const char* name
, const char* mode
)
197 TIFF
* tif
= TIFFClientOpen(name
, mode
,
199 _tiffReadProc
, _tiffNullProc
,
200 _tiffSeekIProc
, _tiffCloseProc
, _tiffSizeProc
,
201 _tiffMapProc
, _tiffUnmapProc
);
207 TIFFwxOpen(wxOutputStream
&stream
, const char* name
, const char* mode
)
209 TIFF
* tif
= TIFFClientOpen(name
, mode
,
211 _tiffNullProc
, _tiffWriteProc
,
212 _tiffSeekOProc
, _tiffCloseProc
, _tiffSizeProc
,
213 _tiffMapProc
, _tiffUnmapProc
);
218 wxTIFFHandler::wxTIFFHandler()
220 m_name
= wxT("TIFF file");
221 m_extension
= wxT("tif");
222 m_type
= wxBITMAP_TYPE_TIF
;
223 m_mime
= wxT("image/tiff");
224 TIFFSetWarningHandler((TIFFErrorHandler
) TIFFwxWarningHandler
);
225 TIFFSetErrorHandler((TIFFErrorHandler
) TIFFwxErrorHandler
);
228 bool wxTIFFHandler::LoadFile( wxImage
*image
, wxInputStream
& stream
, bool verbose
, int index
)
235 TIFF
*tif
= TIFFwxOpen( stream
, "image", "r" );
240 wxLogError( _("TIFF: Error loading image.") );
245 if (!TIFFSetDirectory( tif
, (tdir_t
)index
))
248 wxLogError( _("Invalid TIFF image index.") );
259 TIFFGetField( tif
, TIFFTAG_IMAGEWIDTH
, &w
);
260 TIFFGetField( tif
, TIFFTAG_IMAGELENGTH
, &h
);
264 raster
= (uint32
*) _TIFFmalloc( npixels
* sizeof(uint32
) );
269 wxLogError( _("TIFF: Couldn't allocate memory.") );
276 image
->Create( (int)w
, (int)h
);
280 wxLogError( _("TIFF: Couldn't allocate memory.") );
288 if (!TIFFReadRGBAImage( tif
, w
, h
, raster
, 0 ))
291 wxLogError( _("TIFF: Error reading image.") );
300 bool hasmask
= false;
302 unsigned char *ptr
= image
->GetData();
306 for (uint32 i
= 0; i
< h
; i
++)
308 for (uint32 j
= 0; j
< w
; j
++)
310 unsigned char alpha
= (unsigned char)TIFFGetA(raster
[pos
]);
314 ptr
[0] = image
->GetMaskRed();
316 ptr
[0] = image
->GetMaskGreen();
318 ptr
[0] = image
->GetMaskBlue();
323 ptr
[0] = (unsigned char)TIFFGetR(raster
[pos
]);
325 ptr
[0] = (unsigned char)TIFFGetG(raster
[pos
]);
327 ptr
[0] = (unsigned char)TIFFGetB(raster
[pos
]);
332 ptr
-= 2*w
*3; // subtract line we just added plus one line
339 image
->SetMask( hasmask
);
344 int wxTIFFHandler::GetImageCount( wxInputStream
& stream
)
346 TIFF
*tif
= TIFFwxOpen( stream
, "image", "r" );
351 int dircount
= 0; // according to the libtiff docs, dircount should be set to 1 here???
354 } while (TIFFReadDirectory(tif
));
361 bool wxTIFFHandler::SaveFile( wxImage
*image
, wxOutputStream
& stream
, bool verbose
)
363 TIFF
*tif
= TIFFwxOpen( stream
, "image", "w" );
368 wxLogError( _("TIFF: Error saving image.") );
373 TIFFSetField(tif
, TIFFTAG_ORIENTATION
, ORIENTATION_TOPLEFT
);
374 TIFFSetField(tif
, TIFFTAG_IMAGEWIDTH
, (uint32
)image
->GetWidth());
375 TIFFSetField(tif
, TIFFTAG_IMAGELENGTH
, (uint32
)image
->GetHeight());
376 TIFFSetField(tif
, TIFFTAG_ORIENTATION
, ORIENTATION_TOPLEFT
);
377 TIFFSetField(tif
, TIFFTAG_PLANARCONFIG
, PLANARCONFIG_CONTIG
);
379 if ( image
->HasOption(wxIMAGE_OPTION_RESOLUTIONX
) &&
380 image
->HasOption(wxIMAGE_OPTION_RESOLUTIONY
) )
382 TIFFSetField(tif
, TIFFTAG_XRESOLUTION
,
383 (float)image
->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONX
));
384 TIFFSetField(tif
, TIFFTAG_YRESOLUTION
,
385 (float)image
->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONY
));
388 int spp
= image
->GetOptionInt(wxIMAGE_OPTION_SAMPLESPERPIXEL
);
392 int bpp
= image
->GetOptionInt(wxIMAGE_OPTION_BITSPERSAMPLE
);
396 int compression
= image
->GetOptionInt(wxIMAGE_OPTION_COMPRESSION
);
399 // we can't use COMPRESSION_LZW because current version of libtiff
400 // doesn't implement it ("no longer implemented due to Unisys patent
401 // enforcement") and other compression methods are lossy so we
402 // shouldn't use them by default -- and the only remaining one is none
403 compression
= COMPRESSION_NONE
;
406 TIFFSetField(tif
, TIFFTAG_SAMPLESPERPIXEL
, spp
);
407 TIFFSetField(tif
, TIFFTAG_BITSPERSAMPLE
, bpp
);
408 TIFFSetField(tif
, TIFFTAG_PHOTOMETRIC
, spp
*bpp
== 1 ? PHOTOMETRIC_MINISBLACK
410 TIFFSetField(tif
, TIFFTAG_COMPRESSION
, compression
);
412 // scanlinesize if determined by spp and bpp
413 tsize_t linebytes
= (tsize_t
)image
->GetWidth() * spp
* bpp
/ 8;
415 if ( (image
->GetWidth() % 8 > 0) && (spp
* bpp
< 8) )
420 if (TIFFScanlineSize(tif
) > linebytes
|| (spp
* bpp
< 24))
422 buf
= (unsigned char *)_TIFFmalloc(TIFFScanlineSize(tif
));
426 wxLogError( _("TIFF: Couldn't allocate memory.") );
438 TIFFSetField(tif
, TIFFTAG_ROWSPERSTRIP
,TIFFDefaultStripSize(tif
, (uint32
) -1));
440 unsigned char *ptr
= image
->GetData();
441 for ( int row
= 0; row
< image
->GetHeight(); row
++ )
448 memcpy(buf
, ptr
, image
->GetWidth());
450 else // black and white image
452 for ( int column
= 0; column
< linebytes
; column
++ )
455 for ( int bp
= 0; bp
< 8; bp
++ )
457 if ( ptr
[column
*24 + bp
*3] > 0 )
459 // check only red as this is sufficient
460 reverse
= (uint8
)(reverse
| 128 >> bp
);
464 buf
[column
] = reverse
;
469 if ( TIFFWriteScanline(tif
, buf
? buf
: ptr
, (uint32
)row
, 0) < 0 )
472 wxLogError( _("TIFF: Error writing image.") );
481 ptr
+= image
->GetWidth()*3;
484 (void) TIFFClose(tif
);
492 bool wxTIFFHandler::DoCanRead( wxInputStream
& stream
)
494 unsigned char hdr
[2];
496 if ( !stream
.Read(&hdr
[0], WXSIZEOF(hdr
)) )
499 return (hdr
[0] == 'I' && hdr
[1] == 'I') ||
500 (hdr
[0] == 'M' && hdr
[1] == 'M');
503 #endif // wxUSE_STREAMS
505 #endif // wxUSE_LIBTIFF