1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxImage TIFF handler
4 // Author: Robert Roebling
6 // Copyright: (c) Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
11 #pragma implementation "imagtiff.h"
14 // For compilers that support precompilation, includes "wx.h".
15 #include "wx/wxprec.h"
23 #if wxUSE_IMAGE && wxUSE_LIBTIFF
25 #include "wx/imagtiff.h"
26 #include "wx/bitmap.h"
35 #include "wx/filefn.h"
36 #include "wx/wfstream.h"
38 #include "wx/module.h"
40 #ifndef TIFFLINKAGEMODE
41 #define TIFFLINKAGEMODE LINKAGEMODE
44 //-----------------------------------------------------------------------------
46 //-----------------------------------------------------------------------------
48 IMPLEMENT_DYNAMIC_CLASS(wxTIFFHandler
,wxImageHandler
)
55 tsize_t TIFFLINKAGEMODE
56 _tiffNullProc(thandle_t
WXUNUSED(handle
),
57 tdata_t
WXUNUSED(buf
),
58 tsize_t
WXUNUSED(size
))
63 tsize_t TIFFLINKAGEMODE
64 _tiffReadProc(thandle_t handle
, tdata_t buf
, tsize_t size
)
66 wxInputStream
*stream
= (wxInputStream
*) handle
;
67 stream
->Read( (void*) buf
, (size_t) size
);
68 return stream
->LastRead();
71 tsize_t TIFFLINKAGEMODE
72 _tiffWriteProc(thandle_t handle
, tdata_t buf
, tsize_t size
)
74 wxOutputStream
*stream
= (wxOutputStream
*) handle
;
75 stream
->Write( (void*) buf
, (size_t) size
);
76 return stream
->LastWrite();
79 toff_t TIFFLINKAGEMODE
80 _tiffSeekIProc(thandle_t handle
, toff_t off
, int whence
)
82 wxInputStream
*stream
= (wxInputStream
*) handle
;
86 case SEEK_SET
: mode
= wxFromStart
; break;
87 case SEEK_CUR
: mode
= wxFromCurrent
; break;
88 case SEEK_END
: mode
= wxFromEnd
; break;
89 default: mode
= wxFromCurrent
; break;
92 return (toff_t
)stream
->SeekI( (wxFileOffset
)off
, mode
);
95 toff_t TIFFLINKAGEMODE
96 _tiffSeekOProc(thandle_t handle
, toff_t off
, int whence
)
98 wxOutputStream
*stream
= (wxOutputStream
*) handle
;
102 case SEEK_SET
: mode
= wxFromStart
; break;
103 case SEEK_CUR
: mode
= wxFromCurrent
; break;
104 case SEEK_END
: mode
= wxFromEnd
; break;
105 default: mode
= wxFromCurrent
; break;
108 return (toff_t
)stream
->SeekO( (wxFileOffset
)off
, mode
);
112 _tiffCloseProc(thandle_t
WXUNUSED(handle
))
117 toff_t TIFFLINKAGEMODE
118 _tiffSizeProc(thandle_t handle
)
120 wxStreamBase
*stream
= (wxStreamBase
*) handle
;
121 return (toff_t
) stream
->GetSize();
125 _tiffMapProc(thandle_t
WXUNUSED(handle
),
126 tdata_t
* WXUNUSED(pbase
),
127 toff_t
* WXUNUSED(psize
))
133 _tiffUnmapProc(thandle_t
WXUNUSED(handle
),
134 tdata_t
WXUNUSED(base
),
135 toff_t
WXUNUSED(size
))
140 TIFFwxWarningHandler(const char* module,
141 const char* WXUNUSED_IN_UNICODE(fmt
),
142 va_list WXUNUSED_IN_UNICODE(ap
))
145 wxLogWarning(_("tiff module: %s"), wxString::FromAscii(module).c_str());
147 // FIXME: this is not terrible informative but better than crashing!
149 wxLogWarning(_("TIFF library warning."));
151 wxVLogWarning(fmt
, ap
);
156 TIFFwxErrorHandler(const char* module,
157 const char* WXUNUSED_IN_UNICODE(fmt
),
158 va_list WXUNUSED_IN_UNICODE(ap
))
161 wxLogError(_("tiff module: %s"), wxString::FromAscii(module).c_str());
165 wxLogError(_("TIFF library error."));
167 wxVLogError(fmt
, ap
);
174 TIFFwxOpen(wxInputStream
&stream
, const char* name
, const char* mode
)
176 TIFF
* tif
= TIFFClientOpen(name
, mode
,
178 _tiffReadProc
, _tiffNullProc
,
179 _tiffSeekIProc
, _tiffCloseProc
, _tiffSizeProc
,
180 _tiffMapProc
, _tiffUnmapProc
);
186 TIFFwxOpen(wxOutputStream
&stream
, const char* name
, const char* mode
)
188 TIFF
* tif
= TIFFClientOpen(name
, mode
,
190 _tiffNullProc
, _tiffWriteProc
,
191 _tiffSeekOProc
, _tiffCloseProc
, _tiffSizeProc
,
192 _tiffMapProc
, _tiffUnmapProc
);
197 wxTIFFHandler::wxTIFFHandler()
199 m_name
= wxT("TIFF file");
200 m_extension
= wxT("tif");
201 m_type
= wxBITMAP_TYPE_TIF
;
202 m_mime
= wxT("image/tiff");
203 TIFFSetWarningHandler((TIFFErrorHandler
) TIFFwxWarningHandler
);
204 TIFFSetErrorHandler((TIFFErrorHandler
) TIFFwxErrorHandler
);
207 bool wxTIFFHandler::LoadFile( wxImage
*image
, wxInputStream
& stream
, bool verbose
, int index
)
214 TIFF
*tif
= TIFFwxOpen( stream
, "image", "r" );
219 wxLogError( _("TIFF: Error loading image.") );
224 if (!TIFFSetDirectory( tif
, (tdir_t
)index
))
227 wxLogError( _("Invalid TIFF image index.") );
238 TIFFGetField( tif
, TIFFTAG_IMAGEWIDTH
, &w
);
239 TIFFGetField( tif
, TIFFTAG_IMAGELENGTH
, &h
);
243 raster
= (uint32
*) _TIFFmalloc( npixels
* sizeof(uint32
) );
248 wxLogError( _("TIFF: Couldn't allocate memory.") );
255 image
->Create( (int)w
, (int)h
);
259 wxLogError( _("TIFF: Couldn't allocate memory.") );
267 if (!TIFFReadRGBAImage( tif
, w
, h
, raster
, 0 ))
270 wxLogError( _("TIFF: Error reading image.") );
279 bool hasmask
= false;
281 unsigned char *ptr
= image
->GetData();
285 for (uint32 i
= 0; i
< h
; i
++)
287 for (uint32 j
= 0; j
< w
; j
++)
289 unsigned char alpha
= (unsigned char)TIFFGetA(raster
[pos
]);
293 ptr
[0] = image
->GetMaskRed();
295 ptr
[0] = image
->GetMaskGreen();
297 ptr
[0] = image
->GetMaskBlue();
302 ptr
[0] = (unsigned char)TIFFGetR(raster
[pos
]);
304 ptr
[0] = (unsigned char)TIFFGetG(raster
[pos
]);
306 ptr
[0] = (unsigned char)TIFFGetB(raster
[pos
]);
311 ptr
-= 2*w
*3; // subtract line we just added plus one line
318 image
->SetMask( hasmask
);
323 int wxTIFFHandler::GetImageCount( wxInputStream
& stream
)
325 TIFF
*tif
= TIFFwxOpen( stream
, "image", "r" );
330 int dircount
= 0; // according to the libtiff docs, dircount should be set to 1 here???
333 } while (TIFFReadDirectory(tif
));
340 bool wxTIFFHandler::SaveFile( wxImage
*image
, wxOutputStream
& stream
, bool verbose
)
342 TIFF
*tif
= TIFFwxOpen( stream
, "image", "w" );
347 wxLogError( _("TIFF: Error saving image.") );
352 TIFFSetField(tif
, TIFFTAG_ORIENTATION
, ORIENTATION_TOPLEFT
);
353 TIFFSetField(tif
, TIFFTAG_IMAGEWIDTH
, (uint32
)image
->GetWidth());
354 TIFFSetField(tif
, TIFFTAG_IMAGELENGTH
, (uint32
)image
->GetHeight());
355 TIFFSetField(tif
, TIFFTAG_ORIENTATION
, ORIENTATION_TOPLEFT
);
356 TIFFSetField(tif
, TIFFTAG_PLANARCONFIG
, PLANARCONFIG_CONTIG
);
358 if ( image
->HasOption(wxIMAGE_OPTION_RESOLUTIONX
) &&
359 image
->HasOption(wxIMAGE_OPTION_RESOLUTIONY
) )
361 TIFFSetField(tif
, TIFFTAG_XRESOLUTION
,
362 (float)image
->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONX
));
363 TIFFSetField(tif
, TIFFTAG_YRESOLUTION
,
364 (float)image
->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONY
));
367 int spp
= image
->GetOptionInt(wxIMAGE_OPTION_SAMPLESPERPIXEL
);
371 int bpp
= image
->GetOptionInt(wxIMAGE_OPTION_BITSPERSAMPLE
);
375 int compression
= image
->GetOptionInt(wxIMAGE_OPTION_COMPRESSION
);
377 compression
=COMPRESSION_LZW
;
379 TIFFSetField(tif
, TIFFTAG_SAMPLESPERPIXEL
, spp
);
380 TIFFSetField(tif
, TIFFTAG_BITSPERSAMPLE
, bpp
);
381 TIFFSetField(tif
, TIFFTAG_PHOTOMETRIC
, spp
*bpp
== 1 ? PHOTOMETRIC_MINISBLACK
383 TIFFSetField(tif
, TIFFTAG_COMPRESSION
, compression
);
385 // scanlinesize if determined by spp and bpp
386 tsize_t linebytes
= (tsize_t
)image
->GetWidth() * spp
* bpp
/ 8;
388 if ( (image
->GetWidth() % 8 > 0) && (spp
* bpp
< 8) )
393 if (TIFFScanlineSize(tif
) > linebytes
|| (spp
* bpp
< 24))
395 buf
= (unsigned char *)_TIFFmalloc(TIFFScanlineSize(tif
));
399 wxLogError( _("TIFF: Couldn't allocate memory.") );
411 TIFFSetField(tif
, TIFFTAG_ROWSPERSTRIP
,TIFFDefaultStripSize(tif
, (uint32
) -1));
413 unsigned char *ptr
= image
->GetData();
414 for ( int row
= 0; row
< image
->GetHeight(); row
++ )
421 memcpy(buf
, ptr
, image
->GetWidth());
423 else // black and white image
425 for ( int column
= 0; column
< linebytes
; column
++ )
428 for ( int bp
= 0; bp
< 8; bp
++ )
430 if ( ptr
[column
*24 + bp
*3] > 0 )
432 // check only red as this is sufficient
433 reverse
= reverse
| 128 >> bp
;
437 buf
[column
] = reverse
;
442 if ( TIFFWriteScanline(tif
, buf
? buf
: ptr
, (uint32
)row
, 0) < 0 )
445 wxLogError( _("TIFF: Error writing image.") );
454 ptr
+= image
->GetWidth()*3;
457 (void) TIFFClose(tif
);
465 bool wxTIFFHandler::DoCanRead( wxInputStream
& stream
)
467 unsigned char hdr
[2];
469 if ( !stream
.Read(&hdr
[0], WXSIZEOF(hdr
)) )
472 return (hdr
[0] == 'I' && hdr
[1] == 'I') ||
473 (hdr
[0] == 'M' && hdr
[1] == 'M');
476 #endif // wxUSE_STREAMS
478 #endif // wxUSE_LIBTIFF