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