1 |
william |
31 |
///////////////////////////////////////////////////////////////////////////// |
2 |
|
|
// Name: src/common/imagtiff.cpp |
3 |
|
|
// Purpose: wxImage TIFF handler |
4 |
|
|
// Author: Robert Roebling |
5 |
|
|
// RCS-ID: $Id: imagtiff.cpp 48694 2007-09-14 23:21:29Z VZ $ |
6 |
|
|
// Copyright: (c) Robert Roebling |
7 |
|
|
// Licence: wxWindows licence |
8 |
|
|
///////////////////////////////////////////////////////////////////////////// |
9 |
|
|
|
10 |
|
|
// For compilers that support precompilation, includes "wx.h". |
11 |
|
|
#include "wx/wxprec.h" |
12 |
|
|
|
13 |
|
|
#ifdef __BORLANDC__ |
14 |
|
|
#pragma hdrstop |
15 |
|
|
#endif |
16 |
|
|
|
17 |
|
|
#if wxUSE_IMAGE && wxUSE_LIBTIFF |
18 |
|
|
|
19 |
|
|
#include "wx/imagtiff.h" |
20 |
|
|
|
21 |
|
|
#ifndef WX_PRECOMP |
22 |
|
|
#include "wx/log.h" |
23 |
|
|
#include "wx/app.h" |
24 |
|
|
#include "wx/intl.h" |
25 |
|
|
#include "wx/bitmap.h" |
26 |
|
|
#include "wx/module.h" |
27 |
|
|
#endif |
28 |
|
|
|
29 |
|
|
extern "C" |
30 |
|
|
{ |
31 |
|
|
#include "tiff.h" |
32 |
|
|
#include "tiffio.h" |
33 |
|
|
} |
34 |
|
|
#include "wx/filefn.h" |
35 |
|
|
#include "wx/wfstream.h" |
36 |
|
|
|
37 |
|
|
#ifndef TIFFLINKAGEMODE |
38 |
|
|
#if defined(__WATCOMC__) && defined(__WXMGL__) |
39 |
|
|
#define TIFFLINKAGEMODE cdecl |
40 |
|
|
#else |
41 |
|
|
#define TIFFLINKAGEMODE LINKAGEMODE |
42 |
|
|
#endif |
43 |
|
|
#endif |
44 |
|
|
|
45 |
|
|
//----------------------------------------------------------------------------- |
46 |
|
|
// wxTIFFHandler |
47 |
|
|
//----------------------------------------------------------------------------- |
48 |
|
|
|
49 |
|
|
IMPLEMENT_DYNAMIC_CLASS(wxTIFFHandler,wxImageHandler) |
50 |
|
|
|
51 |
|
|
#if wxUSE_STREAMS |
52 |
|
|
|
53 |
|
|
// helper to translate our, possibly 64 bit, wxFileOffset to TIFF, always 32 |
54 |
|
|
// bit, toff_t |
55 |
|
|
static toff_t wxFileOffsetToTIFF(wxFileOffset ofs) |
56 |
|
|
{ |
57 |
|
|
if ( ofs == wxInvalidOffset ) |
58 |
|
|
return (toff_t)-1; |
59 |
|
|
|
60 |
|
|
toff_t tofs = wx_truncate_cast(toff_t, ofs); |
61 |
|
|
wxCHECK_MSG( (wxFileOffset)tofs == ofs, (toff_t)-1, |
62 |
|
|
_T("TIFF library doesn't support large files") ); |
63 |
|
|
|
64 |
|
|
return tofs; |
65 |
|
|
} |
66 |
|
|
|
67 |
|
|
// another helper to convert standard seek mode to our |
68 |
|
|
static wxSeekMode wxSeekModeFromTIFF(int whence) |
69 |
|
|
{ |
70 |
|
|
switch ( whence ) |
71 |
|
|
{ |
72 |
|
|
case SEEK_SET: |
73 |
|
|
return wxFromStart; |
74 |
|
|
|
75 |
|
|
case SEEK_CUR: |
76 |
|
|
return wxFromCurrent; |
77 |
|
|
|
78 |
|
|
case SEEK_END: |
79 |
|
|
return wxFromEnd; |
80 |
|
|
|
81 |
|
|
default: |
82 |
|
|
return wxFromCurrent; |
83 |
|
|
} |
84 |
|
|
} |
85 |
|
|
|
86 |
|
|
extern "C" |
87 |
|
|
{ |
88 |
|
|
|
89 |
|
|
tsize_t TIFFLINKAGEMODE |
90 |
|
|
wxTIFFNullProc(thandle_t WXUNUSED(handle), |
91 |
|
|
tdata_t WXUNUSED(buf), |
92 |
|
|
tsize_t WXUNUSED(size)) |
93 |
|
|
{ |
94 |
|
|
return (tsize_t) -1; |
95 |
|
|
} |
96 |
|
|
|
97 |
|
|
tsize_t TIFFLINKAGEMODE |
98 |
|
|
wxTIFFReadProc(thandle_t handle, tdata_t buf, tsize_t size) |
99 |
|
|
{ |
100 |
|
|
wxInputStream *stream = (wxInputStream*) handle; |
101 |
|
|
stream->Read( (void*) buf, (size_t) size ); |
102 |
|
|
return wx_truncate_cast(tsize_t, stream->LastRead()); |
103 |
|
|
} |
104 |
|
|
|
105 |
|
|
tsize_t TIFFLINKAGEMODE |
106 |
|
|
wxTIFFWriteProc(thandle_t handle, tdata_t buf, tsize_t size) |
107 |
|
|
{ |
108 |
|
|
wxOutputStream *stream = (wxOutputStream*) handle; |
109 |
|
|
stream->Write( (void*) buf, (size_t) size ); |
110 |
|
|
return wx_truncate_cast(tsize_t, stream->LastWrite()); |
111 |
|
|
} |
112 |
|
|
|
113 |
|
|
toff_t TIFFLINKAGEMODE |
114 |
|
|
wxTIFFSeekIProc(thandle_t handle, toff_t off, int whence) |
115 |
|
|
{ |
116 |
|
|
wxInputStream *stream = (wxInputStream*) handle; |
117 |
|
|
|
118 |
|
|
return wxFileOffsetToTIFF(stream->SeekI((wxFileOffset)off, |
119 |
|
|
wxSeekModeFromTIFF(whence))); |
120 |
|
|
} |
121 |
|
|
|
122 |
|
|
toff_t TIFFLINKAGEMODE |
123 |
|
|
wxTIFFSeekOProc(thandle_t handle, toff_t off, int whence) |
124 |
|
|
{ |
125 |
|
|
wxOutputStream *stream = (wxOutputStream*) handle; |
126 |
|
|
|
127 |
|
|
return wxFileOffsetToTIFF(stream->SeekO((wxFileOffset)off, |
128 |
|
|
wxSeekModeFromTIFF(whence))); |
129 |
|
|
} |
130 |
|
|
|
131 |
|
|
int TIFFLINKAGEMODE |
132 |
|
|
wxTIFFCloseIProc(thandle_t WXUNUSED(handle)) |
133 |
|
|
{ |
134 |
|
|
// there is no need to close the input stream |
135 |
|
|
return 0; |
136 |
|
|
} |
137 |
|
|
|
138 |
|
|
int TIFFLINKAGEMODE |
139 |
|
|
wxTIFFCloseOProc(thandle_t handle) |
140 |
|
|
{ |
141 |
|
|
wxOutputStream *stream = (wxOutputStream*) handle; |
142 |
|
|
|
143 |
|
|
return stream->Close() ? 0 : -1; |
144 |
|
|
} |
145 |
|
|
|
146 |
|
|
toff_t TIFFLINKAGEMODE |
147 |
|
|
wxTIFFSizeProc(thandle_t handle) |
148 |
|
|
{ |
149 |
|
|
wxStreamBase *stream = (wxStreamBase*) handle; |
150 |
|
|
return (toff_t) stream->GetSize(); |
151 |
|
|
} |
152 |
|
|
|
153 |
|
|
int TIFFLINKAGEMODE |
154 |
|
|
wxTIFFMapProc(thandle_t WXUNUSED(handle), |
155 |
|
|
tdata_t* WXUNUSED(pbase), |
156 |
|
|
toff_t* WXUNUSED(psize)) |
157 |
|
|
{ |
158 |
|
|
return 0; |
159 |
|
|
} |
160 |
|
|
|
161 |
|
|
void TIFFLINKAGEMODE |
162 |
|
|
wxTIFFUnmapProc(thandle_t WXUNUSED(handle), |
163 |
|
|
tdata_t WXUNUSED(base), |
164 |
|
|
toff_t WXUNUSED(size)) |
165 |
|
|
{ |
166 |
|
|
} |
167 |
|
|
|
168 |
|
|
static void |
169 |
|
|
TIFFwxWarningHandler(const char* module, |
170 |
|
|
const char* WXUNUSED_IN_UNICODE(fmt), |
171 |
|
|
va_list WXUNUSED_IN_UNICODE(ap)) |
172 |
|
|
{ |
173 |
|
|
if (module != NULL) |
174 |
|
|
wxLogWarning(_("tiff module: %s"), wxString::FromAscii(module).c_str()); |
175 |
|
|
|
176 |
|
|
// FIXME: this is not terrible informative but better than crashing! |
177 |
|
|
#if wxUSE_UNICODE |
178 |
|
|
wxLogWarning(_("TIFF library warning.")); |
179 |
|
|
#else |
180 |
|
|
wxVLogWarning(fmt, ap); |
181 |
|
|
#endif |
182 |
|
|
} |
183 |
|
|
|
184 |
|
|
static void |
185 |
|
|
TIFFwxErrorHandler(const char* module, |
186 |
|
|
const char* WXUNUSED_IN_UNICODE(fmt), |
187 |
|
|
va_list WXUNUSED_IN_UNICODE(ap)) |
188 |
|
|
{ |
189 |
|
|
if (module != NULL) |
190 |
|
|
wxLogError(_("tiff module: %s"), wxString::FromAscii(module).c_str()); |
191 |
|
|
|
192 |
|
|
// FIXME: as above |
193 |
|
|
#if wxUSE_UNICODE |
194 |
|
|
wxLogError(_("TIFF library error.")); |
195 |
|
|
#else |
196 |
|
|
wxVLogError(fmt, ap); |
197 |
|
|
#endif |
198 |
|
|
} |
199 |
|
|
|
200 |
|
|
} // extern "C" |
201 |
|
|
|
202 |
|
|
TIFF* |
203 |
|
|
TIFFwxOpen(wxInputStream &stream, const char* name, const char* mode) |
204 |
|
|
{ |
205 |
|
|
TIFF* tif = TIFFClientOpen(name, mode, |
206 |
|
|
(thandle_t) &stream, |
207 |
|
|
wxTIFFReadProc, wxTIFFNullProc, |
208 |
|
|
wxTIFFSeekIProc, wxTIFFCloseIProc, wxTIFFSizeProc, |
209 |
|
|
wxTIFFMapProc, wxTIFFUnmapProc); |
210 |
|
|
|
211 |
|
|
return tif; |
212 |
|
|
} |
213 |
|
|
|
214 |
|
|
TIFF* |
215 |
|
|
TIFFwxOpen(wxOutputStream &stream, const char* name, const char* mode) |
216 |
|
|
{ |
217 |
|
|
TIFF* tif = TIFFClientOpen(name, mode, |
218 |
|
|
(thandle_t) &stream, |
219 |
|
|
wxTIFFNullProc, wxTIFFWriteProc, |
220 |
|
|
wxTIFFSeekOProc, wxTIFFCloseOProc, wxTIFFSizeProc, |
221 |
|
|
wxTIFFMapProc, wxTIFFUnmapProc); |
222 |
|
|
|
223 |
|
|
return tif; |
224 |
|
|
} |
225 |
|
|
|
226 |
|
|
wxTIFFHandler::wxTIFFHandler() |
227 |
|
|
{ |
228 |
|
|
m_name = wxT("TIFF file"); |
229 |
|
|
m_extension = wxT("tif"); |
230 |
|
|
m_type = wxBITMAP_TYPE_TIF; |
231 |
|
|
m_mime = wxT("image/tiff"); |
232 |
|
|
TIFFSetWarningHandler((TIFFErrorHandler) TIFFwxWarningHandler); |
233 |
|
|
TIFFSetErrorHandler((TIFFErrorHandler) TIFFwxErrorHandler); |
234 |
|
|
} |
235 |
|
|
|
236 |
|
|
bool wxTIFFHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int index ) |
237 |
|
|
{ |
238 |
|
|
if (index == -1) |
239 |
|
|
index = 0; |
240 |
|
|
|
241 |
|
|
image->Destroy(); |
242 |
|
|
|
243 |
|
|
TIFF *tif = TIFFwxOpen( stream, "image", "r" ); |
244 |
|
|
|
245 |
|
|
if (!tif) |
246 |
|
|
{ |
247 |
|
|
if (verbose) |
248 |
|
|
wxLogError( _("TIFF: Error loading image.") ); |
249 |
|
|
|
250 |
|
|
return false; |
251 |
|
|
} |
252 |
|
|
|
253 |
|
|
if (!TIFFSetDirectory( tif, (tdir_t)index )) |
254 |
|
|
{ |
255 |
|
|
if (verbose) |
256 |
|
|
wxLogError( _("Invalid TIFF image index.") ); |
257 |
|
|
|
258 |
|
|
TIFFClose( tif ); |
259 |
|
|
|
260 |
|
|
return false; |
261 |
|
|
} |
262 |
|
|
|
263 |
|
|
uint32 w, h; |
264 |
|
|
uint32 npixels; |
265 |
|
|
uint32 *raster; |
266 |
|
|
|
267 |
|
|
TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &w ); |
268 |
|
|
TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &h ); |
269 |
|
|
|
270 |
|
|
uint16 extraSamples; |
271 |
|
|
uint16* samplesInfo; |
272 |
|
|
TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, |
273 |
|
|
&extraSamples, &samplesInfo); |
274 |
|
|
const bool hasAlpha = (extraSamples == 1 && |
275 |
|
|
(samplesInfo[0] == EXTRASAMPLE_ASSOCALPHA || |
276 |
|
|
samplesInfo[0] == EXTRASAMPLE_UNASSALPHA)); |
277 |
|
|
|
278 |
|
|
npixels = w * h; |
279 |
|
|
|
280 |
|
|
raster = (uint32*) _TIFFmalloc( npixels * sizeof(uint32) ); |
281 |
|
|
|
282 |
|
|
if (!raster) |
283 |
|
|
{ |
284 |
|
|
if (verbose) |
285 |
|
|
wxLogError( _("TIFF: Couldn't allocate memory.") ); |
286 |
|
|
|
287 |
|
|
TIFFClose( tif ); |
288 |
|
|
|
289 |
|
|
return false; |
290 |
|
|
} |
291 |
|
|
|
292 |
|
|
image->Create( (int)w, (int)h ); |
293 |
|
|
if (!image->Ok()) |
294 |
|
|
{ |
295 |
|
|
if (verbose) |
296 |
|
|
wxLogError( _("TIFF: Couldn't allocate memory.") ); |
297 |
|
|
|
298 |
|
|
_TIFFfree( raster ); |
299 |
|
|
TIFFClose( tif ); |
300 |
|
|
|
301 |
|
|
return false; |
302 |
|
|
} |
303 |
|
|
|
304 |
|
|
if ( hasAlpha ) |
305 |
|
|
image->SetAlpha(); |
306 |
|
|
|
307 |
|
|
if (!TIFFReadRGBAImage( tif, w, h, raster, 0 )) |
308 |
|
|
{ |
309 |
|
|
if (verbose) |
310 |
|
|
wxLogError( _("TIFF: Error reading image.") ); |
311 |
|
|
|
312 |
|
|
_TIFFfree( raster ); |
313 |
|
|
image->Destroy(); |
314 |
|
|
TIFFClose( tif ); |
315 |
|
|
|
316 |
|
|
return false; |
317 |
|
|
} |
318 |
|
|
|
319 |
|
|
unsigned char *ptr = image->GetData(); |
320 |
|
|
ptr += w*3*(h-1); |
321 |
|
|
|
322 |
|
|
unsigned char *alpha = hasAlpha ? image->GetAlpha() : NULL; |
323 |
|
|
if ( hasAlpha ) |
324 |
|
|
alpha += w*(h-1); |
325 |
|
|
|
326 |
|
|
uint32 pos = 0; |
327 |
|
|
|
328 |
|
|
for (uint32 i = 0; i < h; i++) |
329 |
|
|
{ |
330 |
|
|
for (uint32 j = 0; j < w; j++) |
331 |
|
|
{ |
332 |
|
|
*(ptr++) = (unsigned char)TIFFGetR(raster[pos]); |
333 |
|
|
*(ptr++) = (unsigned char)TIFFGetG(raster[pos]); |
334 |
|
|
*(ptr++) = (unsigned char)TIFFGetB(raster[pos]); |
335 |
|
|
if ( hasAlpha ) |
336 |
|
|
*(alpha++) = (unsigned char)TIFFGetA(raster[pos]); |
337 |
|
|
|
338 |
|
|
pos++; |
339 |
|
|
} |
340 |
|
|
|
341 |
|
|
// subtract line we just added plus one line: |
342 |
|
|
ptr -= 2*w*3; |
343 |
|
|
if ( hasAlpha ) |
344 |
|
|
alpha -= 2*w; |
345 |
|
|
} |
346 |
|
|
|
347 |
|
|
_TIFFfree( raster ); |
348 |
|
|
|
349 |
|
|
TIFFClose( tif ); |
350 |
|
|
|
351 |
|
|
return true; |
352 |
|
|
} |
353 |
|
|
|
354 |
|
|
int wxTIFFHandler::GetImageCount( wxInputStream& stream ) |
355 |
|
|
{ |
356 |
|
|
TIFF *tif = TIFFwxOpen( stream, "image", "r" ); |
357 |
|
|
|
358 |
|
|
if (!tif) |
359 |
|
|
return 0; |
360 |
|
|
|
361 |
|
|
int dircount = 0; // according to the libtiff docs, dircount should be set to 1 here??? |
362 |
|
|
do { |
363 |
|
|
dircount++; |
364 |
|
|
} while (TIFFReadDirectory(tif)); |
365 |
|
|
|
366 |
|
|
TIFFClose( tif ); |
367 |
|
|
|
368 |
|
|
return dircount; |
369 |
|
|
} |
370 |
|
|
|
371 |
|
|
bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose ) |
372 |
|
|
{ |
373 |
|
|
TIFF *tif = TIFFwxOpen( stream, "image", "w" ); |
374 |
|
|
|
375 |
|
|
if (!tif) |
376 |
|
|
{ |
377 |
|
|
if (verbose) |
378 |
|
|
wxLogError( _("TIFF: Error saving image.") ); |
379 |
|
|
|
380 |
|
|
return false; |
381 |
|
|
} |
382 |
|
|
|
383 |
|
|
TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); |
384 |
|
|
TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (uint32)image->GetWidth()); |
385 |
|
|
TIFFSetField(tif, TIFFTAG_IMAGELENGTH, (uint32)image->GetHeight()); |
386 |
|
|
TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); |
387 |
|
|
TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); |
388 |
|
|
|
389 |
|
|
if ( image->HasOption(wxIMAGE_OPTION_RESOLUTIONX) && |
390 |
|
|
image->HasOption(wxIMAGE_OPTION_RESOLUTIONY) ) |
391 |
|
|
{ |
392 |
|
|
TIFFSetField(tif, TIFFTAG_XRESOLUTION, |
393 |
|
|
(float)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONX)); |
394 |
|
|
TIFFSetField(tif, TIFFTAG_YRESOLUTION, |
395 |
|
|
(float)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONY)); |
396 |
|
|
} |
397 |
|
|
|
398 |
|
|
int spp = image->GetOptionInt(wxIMAGE_OPTION_SAMPLESPERPIXEL); |
399 |
|
|
if ( !spp ) |
400 |
|
|
spp = 3; |
401 |
|
|
|
402 |
|
|
int bpp = image->GetOptionInt(wxIMAGE_OPTION_BITSPERSAMPLE); |
403 |
|
|
if ( !bpp ) |
404 |
|
|
bpp=8; |
405 |
|
|
|
406 |
|
|
int compression = image->GetOptionInt(wxIMAGE_OPTION_COMPRESSION); |
407 |
|
|
if ( !compression ) |
408 |
|
|
{ |
409 |
|
|
// we can't use COMPRESSION_LZW because current version of libtiff |
410 |
|
|
// doesn't implement it ("no longer implemented due to Unisys patent |
411 |
|
|
// enforcement") and other compression methods are lossy so we |
412 |
|
|
// shouldn't use them by default -- and the only remaining one is none |
413 |
|
|
compression = COMPRESSION_NONE; |
414 |
|
|
} |
415 |
|
|
|
416 |
|
|
TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, spp); |
417 |
|
|
TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bpp); |
418 |
|
|
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, spp*bpp == 1 ? PHOTOMETRIC_MINISBLACK |
419 |
|
|
: PHOTOMETRIC_RGB); |
420 |
|
|
TIFFSetField(tif, TIFFTAG_COMPRESSION, compression); |
421 |
|
|
|
422 |
|
|
// scanlinesize if determined by spp and bpp |
423 |
|
|
tsize_t linebytes = (tsize_t)image->GetWidth() * spp * bpp / 8; |
424 |
|
|
|
425 |
|
|
if ( (image->GetWidth() % 8 > 0) && (spp * bpp < 8) ) |
426 |
|
|
linebytes+=1; |
427 |
|
|
|
428 |
|
|
unsigned char *buf; |
429 |
|
|
|
430 |
|
|
if (TIFFScanlineSize(tif) > linebytes || (spp * bpp < 24)) |
431 |
|
|
{ |
432 |
|
|
buf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(tif)); |
433 |
|
|
if (!buf) |
434 |
|
|
{ |
435 |
|
|
if (verbose) |
436 |
|
|
wxLogError( _("TIFF: Couldn't allocate memory.") ); |
437 |
|
|
|
438 |
|
|
TIFFClose( tif ); |
439 |
|
|
|
440 |
|
|
return false; |
441 |
|
|
} |
442 |
|
|
} |
443 |
|
|
else |
444 |
|
|
{ |
445 |
|
|
buf = NULL; |
446 |
|
|
} |
447 |
|
|
|
448 |
|
|
TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP,TIFFDefaultStripSize(tif, (uint32) -1)); |
449 |
|
|
|
450 |
|
|
unsigned char *ptr = image->GetData(); |
451 |
|
|
for ( int row = 0; row < image->GetHeight(); row++ ) |
452 |
|
|
{ |
453 |
|
|
if ( buf ) |
454 |
|
|
{ |
455 |
|
|
if ( spp * bpp > 1 ) |
456 |
|
|
{ |
457 |
|
|
// color image |
458 |
|
|
memcpy(buf, ptr, image->GetWidth()); |
459 |
|
|
} |
460 |
|
|
else // black and white image |
461 |
|
|
{ |
462 |
|
|
for ( int column = 0; column < linebytes; column++ ) |
463 |
|
|
{ |
464 |
|
|
uint8 reverse = 0; |
465 |
|
|
for ( int bp = 0; bp < 8; bp++ ) |
466 |
|
|
{ |
467 |
|
|
if ( ptr[column*24 + bp*3] > 0 ) |
468 |
|
|
{ |
469 |
|
|
// check only red as this is sufficient |
470 |
|
|
reverse = (uint8)(reverse | 128 >> bp); |
471 |
|
|
} |
472 |
|
|
} |
473 |
|
|
|
474 |
|
|
buf[column] = reverse; |
475 |
|
|
} |
476 |
|
|
} |
477 |
|
|
} |
478 |
|
|
|
479 |
|
|
if ( TIFFWriteScanline(tif, buf ? buf : ptr, (uint32)row, 0) < 0 ) |
480 |
|
|
{ |
481 |
|
|
if (verbose) |
482 |
|
|
wxLogError( _("TIFF: Error writing image.") ); |
483 |
|
|
|
484 |
|
|
TIFFClose( tif ); |
485 |
|
|
if (buf) |
486 |
|
|
_TIFFfree(buf); |
487 |
|
|
|
488 |
|
|
return false; |
489 |
|
|
} |
490 |
|
|
|
491 |
|
|
ptr += image->GetWidth()*3; |
492 |
|
|
} |
493 |
|
|
|
494 |
|
|
(void) TIFFClose(tif); |
495 |
|
|
|
496 |
|
|
if (buf) |
497 |
|
|
_TIFFfree(buf); |
498 |
|
|
|
499 |
|
|
return true; |
500 |
|
|
} |
501 |
|
|
|
502 |
|
|
bool wxTIFFHandler::DoCanRead( wxInputStream& stream ) |
503 |
|
|
{ |
504 |
|
|
unsigned char hdr[2]; |
505 |
|
|
|
506 |
|
|
if ( !stream.Read(&hdr[0], WXSIZEOF(hdr)) ) |
507 |
|
|
return false; |
508 |
|
|
|
509 |
|
|
return (hdr[0] == 'I' && hdr[1] == 'I') || |
510 |
|
|
(hdr[0] == 'M' && hdr[1] == 'M'); |
511 |
|
|
} |
512 |
|
|
|
513 |
|
|
#endif // wxUSE_STREAMS |
514 |
|
|
|
515 |
|
|
#endif // wxUSE_LIBTIFF |