(temporary) hotfix for Watcom/DOS and PNGLINKAGEMODE
[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 #if defined(__WATCOMC__) && !defined(__DOS__)
41 #ifdef LINKAGEMODE
42 #undef LINKAGEMODE
43 #define LINKAGEMODE __cdecl
44 #endif
45 #endif
46 //-----------------------------------------------------------------------------
47 // wxTIFFHandler
48 //-----------------------------------------------------------------------------
49
50 IMPLEMENT_DYNAMIC_CLASS(wxTIFFHandler,wxImageHandler)
51
52 static tsize_t LINKAGEMODE
53 _tiffNullProc(thandle_t WXUNUSED(handle),
54 tdata_t WXUNUSED(buf),
55 tsize_t WXUNUSED(size))
56 {
57 return (tsize_t) -1;
58 }
59
60 static tsize_t LINKAGEMODE
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 );
65 return stream->LastRead();
66 }
67
68 static tsize_t LINKAGEMODE
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 );
73 return stream->LastWrite();
74 }
75
76 static toff_t LINKAGEMODE
77 _tiffSeekIProc(thandle_t handle, toff_t off, int whence)
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 }
88
89 return (toff_t)stream->SeekI( (off_t)off, mode );
90 }
91
92 static toff_t LINKAGEMODE
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
108 static int LINKAGEMODE
109 _tiffCloseProc(thandle_t WXUNUSED(handle))
110 {
111 return 0; // ?
112 }
113
114 static toff_t LINKAGEMODE
115 _tiffSizeProc(thandle_t handle)
116 {
117 wxStreamBase *stream = (wxStreamBase*) handle;
118 return (toff_t) stream->GetSize();
119 }
120
121 static int LINKAGEMODE
122 _tiffMapProc(thandle_t WXUNUSED(handle),
123 tdata_t* WXUNUSED(pbase),
124 toff_t* WXUNUSED(psize))
125 {
126 return 0;
127 }
128
129 static void LINKAGEMODE
130 _tiffUnmapProc(thandle_t WXUNUSED(handle),
131 tdata_t WXUNUSED(base),
132 toff_t WXUNUSED(size))
133 {
134 }
135
136 TIFF*
137 TIFFwxOpen(wxInputStream &stream, const char* name, const char* mode)
138 {
139 TIFF* tif = TIFFClientOpen(name, mode,
140 (thandle_t) &stream,
141 _tiffReadProc, _tiffNullProc,
142 _tiffSeekIProc, _tiffCloseProc, _tiffSizeProc,
143 _tiffMapProc, _tiffUnmapProc);
144
145 return tif;
146 }
147
148 TIFF*
149 TIFFwxOpen(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 }
159
160 bool wxTIFFHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int index )
161 {
162 image->Destroy();
163
164 TIFF *tif = TIFFwxOpen( stream, "image", "r" );
165
166 if (!tif)
167 {
168 if (verbose)
169 wxLogError( _("TIFF: Error loading image.") );
170
171 return FALSE;
172 }
173
174 if (!TIFFSetDirectory( tif, (tdir_t)index ))
175 {
176 if (verbose)
177 wxLogError( _("Invalid TIFF image index.") );
178
179 TIFFClose( tif );
180
181 return FALSE;
182 }
183
184 uint32 w, h;
185 uint32 npixels;
186 uint32 *raster;
187
188 TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &w );
189 TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &h );
190
191 npixels = w * h;
192
193 raster = (uint32*) _TIFFmalloc( npixels * sizeof(uint32) );
194
195 if (!raster)
196 {
197 if (verbose)
198 wxLogError( _("TIFF: Couldn't allocate memory.") );
199
200 TIFFClose( tif );
201
202 return FALSE;
203 }
204
205 image->Create( (int)w, (int)h );
206 if (!image->Ok())
207 {
208 if (verbose)
209 wxLogError( _("TIFF: Couldn't allocate memory.") );
210
211 _TIFFfree( raster );
212 TIFFClose( tif );
213
214 return FALSE;
215 }
216
217 if (!TIFFReadRGBAImage( tif, w, h, raster, 0 ))
218 {
219 if (verbose)
220 wxLogError( _("TIFF: Error reading image.") );
221
222 _TIFFfree( raster );
223 image->Destroy();
224 TIFFClose( tif );
225
226 return FALSE;
227 }
228
229 bool hasmask = FALSE;
230
231 unsigned char *ptr = image->GetData();
232 ptr += w*3*(h-1);
233 uint32 pos = 0;
234
235 for (uint32 i = 0; i < h; i++)
236 {
237 for (uint32 j = 0; j < w; j++)
238 {
239 unsigned char alpha = (unsigned char)TIFFGetA(raster[pos]);
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 {
252 ptr[0] = (unsigned char)TIFFGetR(raster[pos]);
253 ptr++;
254 ptr[0] = (unsigned char)TIFFGetG(raster[pos]);
255 ptr++;
256 ptr[0] = (unsigned char)TIFFGetB(raster[pos]);
257 ptr++;
258 }
259 pos++;
260 }
261 ptr -= 2*w*3; // subtract line we just added plus one line
262 }
263
264 _TIFFfree( raster );
265
266 TIFFClose( tif );
267
268 image->SetMask( hasmask );
269
270 return TRUE;
271 }
272
273 int wxTIFFHandler::GetImageCount( wxInputStream& stream )
274 {
275 TIFF *tif = TIFFwxOpen( stream, "image", "r" );
276
277 if (!tif)
278 return 0;
279
280 int dircount = 0; // according to the libtiff docs, dircount should be set to 1 here???
281 do {
282 dircount++;
283 } while (TIFFReadDirectory(tif));
284
285 TIFFClose( tif );
286
287 return dircount;
288 }
289
290 bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose )
291 {
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);
310
311 tsize_t linebytes = (tsize_t)image->GetWidth() * 3;
312 unsigned char *buf;
313
314 if (TIFFScanlineSize(tif) > linebytes)
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 }
326 }
327 else
328 {
329 buf = NULL;
330 }
331
332 TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP,
333 TIFFDefaultStripSize(tif, (uint32) -1));
334
335 unsigned char *ptr = image->GetData();
336 for (int row = 0; row < image->GetHeight(); row++)
337 {
338 if (buf)
339 memcpy(buf, ptr, image->GetWidth());
340
341 if (TIFFWriteScanline(tif, buf ? buf : ptr, (uint32)row, 0) < 0)
342 {
343 if (verbose)
344 wxLogError( _("TIFF: Error writing image.") );
345
346 TIFFClose( tif );
347 if (buf)
348 _TIFFfree(buf);
349
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;
361 }
362
363 bool wxTIFFHandler::DoCanRead( wxInputStream& stream )
364 {
365 unsigned char hdr[2];
366
367 stream.Read(&hdr, 2);
368 stream.SeekI(-2, wxFromCurrent);
369
370 return ((hdr[0] == 0x49 && hdr[1] == 0x49) ||
371 (hdr[0] == 0x4D && hdr[1] == 0x4D));
372 }
373
374
375 #endif
376 // wxUSE_LIBTIFF
377
378