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