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