]> git.saurik.com Git - wxWidgets.git/blame - src/common/imagtiff.cpp
patch from Dimitri fixing crashes when decoding the invalid GIFs
[wxWidgets.git] / src / common / imagtiff.cpp
CommitLineData
257bcf28 1/////////////////////////////////////////////////////////////////////////////
8f493002
VS
2// Name: imagtiff.cpp
3// Purpose: wxImage TIFF handler
4// Author: Robert Roebling
257bcf28 5// RCS-ID: $Id$
8f493002 6// Copyright: (c) Robert Roebling
257bcf28
RR
7// Licence: wxWindows licence
8/////////////////////////////////////////////////////////////////////////////
9
8f493002
VS
10#ifdef __GNUG__
11#pragma implementation "imagtiff.h"
12#endif
257bcf28
RR
13
14// For compilers that support precompilation, includes "wx.h".
15#include "wx/wxprec.h"
16
17#ifdef __BORLANDC__
18#pragma hdrstop
19#endif
20
21#include "wx/defs.h"
22
c96ea657 23#if wxUSE_IMAGE && wxUSE_LIBTIFF
257bcf28 24
8f493002 25#include "wx/imagtiff.h"
257bcf28
RR
26#include "wx/bitmap.h"
27#include "wx/debug.h"
28#include "wx/log.h"
29#include "wx/app.h"
30extern "C"
31{
32 #include "tiff.h"
33 #include "tiffio.h"
257bcf28
RR
34}
35#include "wx/filefn.h"
36#include "wx/wfstream.h"
37#include "wx/intl.h"
38#include "wx/module.h"
39
0729bd19
VS
40#ifndef TIFFLINKAGEMODE
41 #define TIFFLINKAGEMODE LINKAGEMODE
19193a2c 42#endif
0729bd19 43
257bcf28
RR
44//-----------------------------------------------------------------------------
45// wxTIFFHandler
46//-----------------------------------------------------------------------------
47
257bcf28 48IMPLEMENT_DYNAMIC_CLASS(wxTIFFHandler,wxImageHandler)
257bcf28 49
0729bd19 50static tsize_t TIFFLINKAGEMODE
f6bcfd97 51_tiffNullProc(thandle_t WXUNUSED(handle),
19193a2c
KB
52 tdata_t WXUNUSED(buf),
53 tsize_t WXUNUSED(size))
f6bcfd97
BP
54{
55 return (tsize_t) -1;
56}
57
0729bd19 58static tsize_t TIFFLINKAGEMODE
257bcf28
RR
59_tiffReadProc(thandle_t handle, tdata_t buf, tsize_t size)
60{
61 wxInputStream *stream = (wxInputStream*) handle;
62 stream->Read( (void*) buf, (size_t) size );
0b72db08 63 return stream->LastRead();
257bcf28
RR
64}
65
0729bd19 66static tsize_t TIFFLINKAGEMODE
257bcf28
RR
67_tiffWriteProc(thandle_t handle, tdata_t buf, tsize_t size)
68{
69 wxOutputStream *stream = (wxOutputStream*) handle;
70 stream->Write( (void*) buf, (size_t) size );
0b72db08 71 return stream->LastWrite();
257bcf28
RR
72}
73
0729bd19 74static toff_t TIFFLINKAGEMODE
f6bcfd97 75_tiffSeekIProc(thandle_t handle, toff_t off, int whence)
257bcf28
RR
76{
77 wxInputStream *stream = (wxInputStream*) handle;
78 wxSeekMode mode;
79 switch (whence)
80 {
81 case SEEK_SET: mode = wxFromStart; break;
82 case SEEK_CUR: mode = wxFromCurrent; break;
83 case SEEK_END: mode = wxFromEnd; break;
84 default: mode = wxFromCurrent; break;
85 }
13111b2a 86
257bcf28
RR
87 return (toff_t)stream->SeekI( (off_t)off, mode );
88}
89
0729bd19 90static toff_t TIFFLINKAGEMODE
f6bcfd97
BP
91_tiffSeekOProc(thandle_t handle, toff_t off, int whence)
92{
93 wxOutputStream *stream = (wxOutputStream*) handle;
94 wxSeekMode mode;
95 switch (whence)
96 {
97 case SEEK_SET: mode = wxFromStart; break;
98 case SEEK_CUR: mode = wxFromCurrent; break;
99 case SEEK_END: mode = wxFromEnd; break;
100 default: mode = wxFromCurrent; break;
101 }
102
103 return (toff_t)stream->SeekO( (off_t)off, mode );
104}
105
0729bd19 106static int TIFFLINKAGEMODE
257bcf28
RR
107_tiffCloseProc(thandle_t WXUNUSED(handle))
108{
109 return 0; // ?
110}
111
0729bd19 112static toff_t TIFFLINKAGEMODE
257bcf28
RR
113_tiffSizeProc(thandle_t handle)
114{
f6bcfd97 115 wxStreamBase *stream = (wxStreamBase*) handle;
0b72db08 116 return (toff_t) stream->GetSize();
257bcf28
RR
117}
118
0729bd19 119static int TIFFLINKAGEMODE
13111b2a
VZ
120_tiffMapProc(thandle_t WXUNUSED(handle),
121 tdata_t* WXUNUSED(pbase),
122 toff_t* WXUNUSED(psize))
257bcf28
RR
123{
124 return 0;
125}
126
0729bd19 127static void TIFFLINKAGEMODE
13111b2a
VZ
128_tiffUnmapProc(thandle_t WXUNUSED(handle),
129 tdata_t WXUNUSED(base),
130 toff_t WXUNUSED(size))
257bcf28
RR
131{
132}
133
134TIFF*
135TIFFwxOpen(wxInputStream &stream, const char* name, const char* mode)
136{
137 TIFF* tif = TIFFClientOpen(name, mode,
138 (thandle_t) &stream,
f6bcfd97
BP
139 _tiffReadProc, _tiffNullProc,
140 _tiffSeekIProc, _tiffCloseProc, _tiffSizeProc,
257bcf28
RR
141 _tiffMapProc, _tiffUnmapProc);
142
257bcf28
RR
143 return tif;
144}
145
f6bcfd97
BP
146TIFF*
147TIFFwxOpen(wxOutputStream &stream, const char* name, const char* mode)
148{
149 TIFF* tif = TIFFClientOpen(name, mode,
150 (thandle_t) &stream,
151 _tiffNullProc, _tiffWriteProc,
152 _tiffSeekOProc, _tiffCloseProc, _tiffSizeProc,
153 _tiffMapProc, _tiffUnmapProc);
154
155 return tif;
156}
257bcf28 157
700ec454 158bool wxTIFFHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int index )
257bcf28 159{
60d43ad8
VS
160 if (index == -1)
161 index = 0;
162
257bcf28 163 image->Destroy();
13111b2a 164
0b72db08 165 TIFF *tif = TIFFwxOpen( stream, "image", "r" );
13111b2a 166
257bcf28
RR
167 if (!tif)
168 {
169 if (verbose)
58c837a4 170 wxLogError( _("TIFF: Error loading image.") );
13111b2a
VZ
171
172 return FALSE;
257bcf28 173 }
13111b2a 174
700ec454
RR
175 if (!TIFFSetDirectory( tif, (tdir_t)index ))
176 {
177 if (verbose)
178 wxLogError( _("Invalid TIFF image index.") );
13111b2a 179
700ec454 180 TIFFClose( tif );
13111b2a
VZ
181
182 return FALSE;
700ec454 183 }
257bcf28
RR
184
185 uint32 w, h;
13111b2a 186 uint32 npixels;
257bcf28 187 uint32 *raster;
13111b2a 188
257bcf28
RR
189 TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &w );
190 TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &h );
13111b2a 191
257bcf28 192 npixels = w * h;
13111b2a 193
257bcf28 194 raster = (uint32*) _TIFFmalloc( npixels * sizeof(uint32) );
13111b2a 195
257bcf28
RR
196 if (!raster)
197 {
198 if (verbose)
58c837a4 199 wxLogError( _("TIFF: Couldn't allocate memory.") );
38755449 200
f6bcfd97 201 TIFFClose( tif );
13111b2a
VZ
202
203 return FALSE;
257bcf28
RR
204 }
205
479cd5de 206 image->Create( (int)w, (int)h );
13111b2a 207 if (!image->Ok())
257bcf28
RR
208 {
209 if (verbose)
58c837a4 210 wxLogError( _("TIFF: Couldn't allocate memory.") );
13111b2a
VZ
211
212 _TIFFfree( raster );
f6bcfd97 213 TIFFClose( tif );
13111b2a 214
257bcf28
RR
215 return FALSE;
216 }
13111b2a 217
257bcf28
RR
218 if (!TIFFReadRGBAImage( tif, w, h, raster, 0 ))
219 {
220 if (verbose)
58c837a4 221 wxLogError( _("TIFF: Error reading image.") );
13111b2a
VZ
222
223 _TIFFfree( raster );
224 image->Destroy();
f6bcfd97 225 TIFFClose( tif );
13111b2a
VZ
226
227 return FALSE;
257bcf28 228 }
13111b2a 229
257bcf28 230 bool hasmask = FALSE;
13111b2a 231
257bcf28 232 unsigned char *ptr = image->GetData();
5c5ab9eb 233 ptr += w*3*(h-1);
257bcf28 234 uint32 pos = 0;
13111b2a 235
257bcf28
RR
236 for (uint32 i = 0; i < h; i++)
237 {
ff7c6c9c 238 for (uint32 j = 0; j < w; j++)
13111b2a 239 {
5c5ab9eb 240 unsigned char alpha = (unsigned char)TIFFGetA(raster[pos]);
13111b2a
VZ
241 if (alpha < 127)
242 {
243 hasmask = TRUE;
244 ptr[0] = image->GetMaskRed();
245 ptr++;
246 ptr[0] = image->GetMaskGreen();
247 ptr++;
248 ptr[0] = image->GetMaskBlue();
249 ptr++;
250 }
251 else
252 {
5c5ab9eb 253 ptr[0] = (unsigned char)TIFFGetR(raster[pos]);
13111b2a 254 ptr++;
5c5ab9eb 255 ptr[0] = (unsigned char)TIFFGetG(raster[pos]);
13111b2a 256 ptr++;
5c5ab9eb 257 ptr[0] = (unsigned char)TIFFGetB(raster[pos]);
13111b2a
VZ
258 ptr++;
259 }
260 pos++;
261 }
5c5ab9eb 262 ptr -= 2*w*3; // subtract line we just added plus one line
257bcf28 263 }
13111b2a 264
257bcf28 265 _TIFFfree( raster );
13111b2a 266
257bcf28 267 TIFFClose( tif );
13111b2a 268
257bcf28 269 image->SetMask( hasmask );
13111b2a 270
257bcf28
RR
271 return TRUE;
272}
273
649d13e8 274int wxTIFFHandler::GetImageCount( wxInputStream& stream )
700ec454
RR
275{
276 TIFF *tif = TIFFwxOpen( stream, "image", "r" );
13111b2a 277
700ec454 278 if (!tif)
13111b2a 279 return 0;
257bcf28 280
700ec454
RR
281 int dircount = 0; // according to the libtiff docs, dircount should be set to 1 here???
282 do {
283 dircount++;
284 } while (TIFFReadDirectory(tif));
13111b2a 285
700ec454 286 TIFFClose( tif );
13111b2a 287
700ec454
RR
288 return dircount;
289}
257bcf28 290
f6bcfd97 291bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose )
257bcf28 292{
f6bcfd97
BP
293 TIFF *tif = TIFFwxOpen( stream, "image", "w" );
294
295 if (!tif)
296 {
297 if (verbose)
298 wxLogError( _("TIFF: Error saving image.") );
299
300 return FALSE;
301 }
302
303 TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (uint32)image->GetWidth());
304 TIFFSetField(tif, TIFFTAG_IMAGELENGTH, (uint32)image->GetHeight());
305 TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
306 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
307 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
308 TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
309 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
310 TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
38755449 311
f6bcfd97
BP
312 tsize_t linebytes = (tsize_t)image->GetWidth() * 3;
313 unsigned char *buf;
38755449
DW
314
315 if (TIFFScanlineSize(tif) > linebytes)
f6bcfd97
BP
316 {
317 buf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(tif));
318 if (!buf)
319 {
320 if (verbose)
321 wxLogError( _("TIFF: Couldn't allocate memory.") );
322
323 TIFFClose( tif );
324
325 return FALSE;
326 }
38755449
DW
327 }
328 else
f6bcfd97
BP
329 {
330 buf = NULL;
331 }
332
333 TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP,
334 TIFFDefaultStripSize(tif, (uint32) -1));
38755449 335
f6bcfd97 336 unsigned char *ptr = image->GetData();
38755449 337 for (int row = 0; row < image->GetHeight(); row++)
f6bcfd97 338 {
19193a2c
KB
339 if (buf)
340 memcpy(buf, ptr, image->GetWidth());
38755449 341
19193a2c 342 if (TIFFWriteScanline(tif, buf ? buf : ptr, (uint32)row, 0) < 0)
f6bcfd97 343 {
19193a2c
KB
344 if (verbose)
345 wxLogError( _("TIFF: Error writing image.") );
38755449 346
f6bcfd97
BP
347 TIFFClose( tif );
348 if (buf)
349 _TIFFfree(buf);
38755449 350
f6bcfd97
BP
351 return FALSE;
352 }
353 ptr += image->GetWidth()*3;
354 }
355
356 (void) TIFFClose(tif);
357
358 if (buf)
359 _TIFFfree(buf);
360
361 return TRUE;
257bcf28
RR
362}
363
364bool wxTIFFHandler::DoCanRead( wxInputStream& stream )
365{
0b72db08 366 unsigned char hdr[2];
257bcf28 367
0b72db08
RR
368 stream.Read(&hdr, 2);
369 stream.SeekI(-2, wxFromCurrent);
13111b2a 370
0b72db08
RR
371 return ((hdr[0] == 0x49 && hdr[1] == 0x49) ||
372 (hdr[0] == 0x4D && hdr[1] == 0x4D));
257bcf28
RR
373}
374
375
376#endif
377 // wxUSE_LIBTIFF
378
379