]> git.saurik.com Git - wxWidgets.git/blame - src/common/imagtiff.cpp
Restored wxNotebook::HitTest for wxOSX-Carbon.
[wxWidgets.git] / src / common / imagtiff.cpp
CommitLineData
257bcf28 1/////////////////////////////////////////////////////////////////////////////
38d4b1e4 2// Name: src/common/imagtiff.cpp
8f493002
VS
3// Purpose: wxImage TIFF handler
4// Author: Robert Roebling
257bcf28 5// RCS-ID: $Id$
8f493002 6// Copyright: (c) Robert Roebling
65571936 7// Licence: wxWindows licence
257bcf28
RR
8/////////////////////////////////////////////////////////////////////////////
9
426272a3
VZ
10// ============================================================================
11// declarations
12// ============================================================================
13
14// ----------------------------------------------------------------------------
15// headers
16// ----------------------------------------------------------------------------
17
257bcf28
RR
18// For compilers that support precompilation, includes "wx.h".
19#include "wx/wxprec.h"
20
21#ifdef __BORLANDC__
8898456d 22 #pragma hdrstop
257bcf28
RR
23#endif
24
c96ea657 25#if wxUSE_IMAGE && wxUSE_LIBTIFF
257bcf28 26
88a7a4e1 27#include "wx/imagtiff.h"
ccec9093 28#include "wx/versioninfo.h"
88a7a4e1 29
8898456d
WS
30#ifndef WX_PRECOMP
31 #include "wx/log.h"
32 #include "wx/app.h"
88a7a4e1 33 #include "wx/intl.h"
0bca0373 34 #include "wx/bitmap.h"
02761f6c 35 #include "wx/module.h"
34deb5cd 36 #include "wx/wxcrtvararg.h"
8898456d
WS
37#endif
38
257bcf28
RR
39extern "C"
40{
8df068ca
CE
41#ifdef __DMC__
42 #include "tif_config.h"
426272a3 43#endif
257bcf28
RR
44 #include "tiff.h"
45 #include "tiffio.h"
257bcf28
RR
46}
47#include "wx/filefn.h"
48#include "wx/wfstream.h"
257bcf28 49
0729bd19 50#ifndef TIFFLINKAGEMODE
0bca0373
WS
51 #if defined(__WATCOMC__) && defined(__WXMGL__)
52 #define TIFFLINKAGEMODE cdecl
53 #else
54 #define TIFFLINKAGEMODE LINKAGEMODE
55 #endif
19193a2c 56#endif
0729bd19 57
426272a3
VZ
58// ============================================================================
59// implementation
60// ============================================================================
61
62// ----------------------------------------------------------------------------
63// TIFF library error/warning handlers
64// ----------------------------------------------------------------------------
65
34deb5cd
VS
66static wxString
67FormatTiffMessage(const char *module, const char *fmt, va_list ap)
68{
69 char buf[512];
70 if ( wxCRT_VsnprintfA(buf, WXSIZEOF(buf), fmt, ap) <= 0 )
71 {
72 // this isn't supposed to happen, but if it does, it's better
73 // than nothing
74 strcpy(buf, "Incorrectly formatted TIFF message");
75 }
76 buf[WXSIZEOF(buf)-1] = 0; // make sure it is always NULL-terminated
77
78 wxString msg(buf);
79 if ( module )
80 msg += wxString::Format(_(" (in module \"%s\")"), module);
81
82 return msg;
83}
84
426272a3
VZ
85extern "C"
86{
87
88static void
34deb5cd 89TIFFwxWarningHandler(const char* module, const char *fmt, va_list ap)
426272a3 90{
34deb5cd 91 wxLogWarning("%s", FormatTiffMessage(module, fmt, ap));
426272a3
VZ
92}
93
94static void
34deb5cd 95TIFFwxErrorHandler(const char* module, const char *fmt, va_list ap)
426272a3 96{
34deb5cd 97 wxLogError("%s", FormatTiffMessage(module, fmt, ap));
426272a3
VZ
98}
99
100} // extern "C"
101
257bcf28
RR
102//-----------------------------------------------------------------------------
103// wxTIFFHandler
104//-----------------------------------------------------------------------------
105
257bcf28 106IMPLEMENT_DYNAMIC_CLASS(wxTIFFHandler,wxImageHandler)
257bcf28 107
426272a3
VZ
108wxTIFFHandler::wxTIFFHandler()
109{
110 m_name = wxT("TIFF file");
111 m_extension = wxT("tif");
ba4800d3 112 m_altExtensions.Add(wxT("tiff"));
426272a3
VZ
113 m_type = wxBITMAP_TYPE_TIF;
114 m_mime = wxT("image/tiff");
115 TIFFSetWarningHandler((TIFFErrorHandler) TIFFwxWarningHandler);
116 TIFFSetErrorHandler((TIFFErrorHandler) TIFFwxErrorHandler);
117}
118
e30285ab
VZ
119#if wxUSE_STREAMS
120
ec524671
VZ
121// helper to translate our, possibly 64 bit, wxFileOffset to TIFF, always 32
122// bit, toff_t
123static toff_t wxFileOffsetToTIFF(wxFileOffset ofs)
124{
125 if ( ofs == wxInvalidOffset )
126 return (toff_t)-1;
127
128 toff_t tofs = wx_truncate_cast(toff_t, ofs);
38d4b1e4 129 wxCHECK_MSG( (wxFileOffset)tofs == ofs, (toff_t)-1,
9a83f860 130 wxT("TIFF library doesn't support large files") );
ec524671
VZ
131
132 return tofs;
133}
134
135// another helper to convert standard seek mode to our
136static wxSeekMode wxSeekModeFromTIFF(int whence)
137{
138 switch ( whence )
139 {
140 case SEEK_SET:
141 return wxFromStart;
142
143 case SEEK_CUR:
144 return wxFromCurrent;
145
146 case SEEK_END:
147 return wxFromEnd;
148
149 default:
150 return wxFromCurrent;
151 }
152}
153
90350682
VZ
154extern "C"
155{
156
157tsize_t TIFFLINKAGEMODE
46f36538 158wxTIFFNullProc(thandle_t WXUNUSED(handle),
19193a2c
KB
159 tdata_t WXUNUSED(buf),
160 tsize_t WXUNUSED(size))
f6bcfd97
BP
161{
162 return (tsize_t) -1;
163}
164
90350682 165tsize_t TIFFLINKAGEMODE
46f36538 166wxTIFFReadProc(thandle_t handle, tdata_t buf, tsize_t size)
257bcf28
RR
167{
168 wxInputStream *stream = (wxInputStream*) handle;
169 stream->Read( (void*) buf, (size_t) size );
4a10ea8b 170 return wx_truncate_cast(tsize_t, stream->LastRead());
257bcf28
RR
171}
172
90350682 173tsize_t TIFFLINKAGEMODE
46f36538 174wxTIFFWriteProc(thandle_t handle, tdata_t buf, tsize_t size)
257bcf28
RR
175{
176 wxOutputStream *stream = (wxOutputStream*) handle;
177 stream->Write( (void*) buf, (size_t) size );
4a10ea8b 178 return wx_truncate_cast(tsize_t, stream->LastWrite());
257bcf28
RR
179}
180
90350682 181toff_t TIFFLINKAGEMODE
46f36538 182wxTIFFSeekIProc(thandle_t handle, toff_t off, int whence)
257bcf28
RR
183{
184 wxInputStream *stream = (wxInputStream*) handle;
13111b2a 185
ec524671
VZ
186 return wxFileOffsetToTIFF(stream->SeekI((wxFileOffset)off,
187 wxSeekModeFromTIFF(whence)));
257bcf28
RR
188}
189
90350682 190toff_t TIFFLINKAGEMODE
46f36538 191wxTIFFSeekOProc(thandle_t handle, toff_t off, int whence)
f6bcfd97
BP
192{
193 wxOutputStream *stream = (wxOutputStream*) handle;
f6bcfd97 194
ec524671
VZ
195 return wxFileOffsetToTIFF(stream->SeekO((wxFileOffset)off,
196 wxSeekModeFromTIFF(whence)));
f6bcfd97
BP
197}
198
90350682 199int TIFFLINKAGEMODE
46f36538 200wxTIFFCloseIProc(thandle_t WXUNUSED(handle))
257bcf28 201{
be0d315e
VZ
202 // there is no need to close the input stream
203 return 0;
204}
205
206int TIFFLINKAGEMODE
46f36538 207wxTIFFCloseOProc(thandle_t handle)
be0d315e
VZ
208{
209 wxOutputStream *stream = (wxOutputStream*) handle;
210
211 return stream->Close() ? 0 : -1;
257bcf28
RR
212}
213
90350682 214toff_t TIFFLINKAGEMODE
46f36538 215wxTIFFSizeProc(thandle_t handle)
257bcf28 216{
f6bcfd97 217 wxStreamBase *stream = (wxStreamBase*) handle;
0b72db08 218 return (toff_t) stream->GetSize();
257bcf28
RR
219}
220
90350682 221int TIFFLINKAGEMODE
46f36538 222wxTIFFMapProc(thandle_t WXUNUSED(handle),
13111b2a
VZ
223 tdata_t* WXUNUSED(pbase),
224 toff_t* WXUNUSED(psize))
257bcf28
RR
225{
226 return 0;
227}
228
90350682 229void TIFFLINKAGEMODE
46f36538 230wxTIFFUnmapProc(thandle_t WXUNUSED(handle),
13111b2a
VZ
231 tdata_t WXUNUSED(base),
232 toff_t WXUNUSED(size))
257bcf28
RR
233{
234}
235
90350682
VZ
236} // extern "C"
237
257bcf28
RR
238TIFF*
239TIFFwxOpen(wxInputStream &stream, const char* name, const char* mode)
240{
241 TIFF* tif = TIFFClientOpen(name, mode,
242 (thandle_t) &stream,
46f36538
VZ
243 wxTIFFReadProc, wxTIFFNullProc,
244 wxTIFFSeekIProc, wxTIFFCloseIProc, wxTIFFSizeProc,
245 wxTIFFMapProc, wxTIFFUnmapProc);
257bcf28 246
257bcf28
RR
247 return tif;
248}
249
f6bcfd97
BP
250TIFF*
251TIFFwxOpen(wxOutputStream &stream, const char* name, const char* mode)
252{
253 TIFF* tif = TIFFClientOpen(name, mode,
254 (thandle_t) &stream,
46f36538
VZ
255 wxTIFFNullProc, wxTIFFWriteProc,
256 wxTIFFSeekOProc, wxTIFFCloseOProc, wxTIFFSizeProc,
257 wxTIFFMapProc, wxTIFFUnmapProc);
f6bcfd97
BP
258
259 return tif;
260}
257bcf28 261
700ec454 262bool wxTIFFHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int index )
257bcf28 263{
60d43ad8
VS
264 if (index == -1)
265 index = 0;
266
257bcf28 267 image->Destroy();
13111b2a 268
0b72db08 269 TIFF *tif = TIFFwxOpen( stream, "image", "r" );
13111b2a 270
257bcf28
RR
271 if (!tif)
272 {
273 if (verbose)
af588446 274 {
58c837a4 275 wxLogError( _("TIFF: Error loading image.") );
af588446 276 }
13111b2a 277
7beb59f3 278 return false;
257bcf28 279 }
13111b2a 280
700ec454
RR
281 if (!TIFFSetDirectory( tif, (tdir_t)index ))
282 {
283 if (verbose)
af588446 284 {
700ec454 285 wxLogError( _("Invalid TIFF image index.") );
af588446 286 }
13111b2a 287
700ec454 288 TIFFClose( tif );
13111b2a 289
7beb59f3 290 return false;
700ec454 291 }
257bcf28
RR
292
293 uint32 w, h;
257bcf28 294 uint32 *raster;
13111b2a 295
257bcf28
RR
296 TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &w );
297 TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &h );
13111b2a 298
3d59540f
DS
299 uint16 photometric;
300 uint16 samplesPerPixel;
b6ac40dc
VS
301 uint16 extraSamples;
302 uint16* samplesInfo;
3d59540f 303 TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesPerPixel);
b6ac40dc
VS
304 TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES,
305 &extraSamples, &samplesInfo);
3d59540f
DS
306 if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric))
307 {
308 photometric = PHOTOMETRIC_MINISWHITE;
309 }
310 const bool hasAlpha = (extraSamples >= 1
311 && ((samplesInfo[0] == EXTRASAMPLE_UNSPECIFIED && samplesPerPixel > 3)
312 || samplesInfo[0] == EXTRASAMPLE_ASSOCALPHA
313 || samplesInfo[0] == EXTRASAMPLE_UNASSALPHA))
314 || (extraSamples == 0 && samplesPerPixel == 4
315 && photometric == PHOTOMETRIC_RGB);
b6ac40dc 316
5beedebb
VZ
317 // guard against integer overflow during multiplication which could result
318 // in allocating a too small buffer and then overflowing it
ca588225 319 const double bytesNeeded = (double)w * (double)h * sizeof(uint32);
5beedebb
VZ
320 if ( bytesNeeded >= wxUINT32_MAX )
321 {
322 if ( verbose )
af588446 323 {
5beedebb 324 wxLogError( _("TIFF: Image size is abnormally big.") );
af588446 325 }
5beedebb
VZ
326
327 TIFFClose(tif);
328
329 return false;
330 }
13111b2a 331
8f2a8de6 332 raster = (uint32*) _TIFFmalloc( (uint32)bytesNeeded );
13111b2a 333
257bcf28
RR
334 if (!raster)
335 {
336 if (verbose)
af588446 337 {
58c837a4 338 wxLogError( _("TIFF: Couldn't allocate memory.") );
af588446 339 }
38755449 340
f6bcfd97 341 TIFFClose( tif );
13111b2a 342
7beb59f3 343 return false;
257bcf28
RR
344 }
345
479cd5de 346 image->Create( (int)w, (int)h );
13111b2a 347 if (!image->Ok())
257bcf28
RR
348 {
349 if (verbose)
af588446 350 {
58c837a4 351 wxLogError( _("TIFF: Couldn't allocate memory.") );
af588446 352 }
13111b2a
VZ
353
354 _TIFFfree( raster );
f6bcfd97 355 TIFFClose( tif );
13111b2a 356
7beb59f3 357 return false;
257bcf28 358 }
13111b2a 359
b6ac40dc
VS
360 if ( hasAlpha )
361 image->SetAlpha();
362
257bcf28
RR
363 if (!TIFFReadRGBAImage( tif, w, h, raster, 0 ))
364 {
365 if (verbose)
af588446 366 {
58c837a4 367 wxLogError( _("TIFF: Error reading image.") );
af588446 368 }
13111b2a
VZ
369
370 _TIFFfree( raster );
371 image->Destroy();
f6bcfd97 372 TIFFClose( tif );
13111b2a 373
7beb59f3 374 return false;
257bcf28 375 }
13111b2a 376
257bcf28 377 unsigned char *ptr = image->GetData();
5c5ab9eb 378 ptr += w*3*(h-1);
b6ac40dc
VS
379
380 unsigned char *alpha = hasAlpha ? image->GetAlpha() : NULL;
381 if ( hasAlpha )
382 alpha += w*(h-1);
383
257bcf28 384 uint32 pos = 0;
13111b2a 385
257bcf28
RR
386 for (uint32 i = 0; i < h; i++)
387 {
ff7c6c9c 388 for (uint32 j = 0; j < w; j++)
13111b2a 389 {
b6ac40dc
VS
390 *(ptr++) = (unsigned char)TIFFGetR(raster[pos]);
391 *(ptr++) = (unsigned char)TIFFGetG(raster[pos]);
392 *(ptr++) = (unsigned char)TIFFGetB(raster[pos]);
393 if ( hasAlpha )
394 *(alpha++) = (unsigned char)TIFFGetA(raster[pos]);
395
13111b2a
VZ
396 pos++;
397 }
b6ac40dc
VS
398
399 // subtract line we just added plus one line:
400 ptr -= 2*w*3;
401 if ( hasAlpha )
402 alpha -= 2*w;
257bcf28 403 }
13111b2a 404
4d37f425
DS
405
406 uint16 spp, bpp, compression;
407 /*
408 Read some baseline TIFF tags which helps when re-saving a TIFF
409 to be similar to the original image.
410 */
411 if ( TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &spp) )
412 {
413 image->SetOption(wxIMAGE_OPTION_SAMPLESPERPIXEL, spp);
414 }
415
416 if ( TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bpp) )
417 {
418 image->SetOption(wxIMAGE_OPTION_BITSPERSAMPLE, bpp);
419 }
420
421 if ( TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &compression) )
422 {
423 image->SetOption(wxIMAGE_OPTION_COMPRESSION, compression);
424 }
425
426 // Set the resolution unit.
427 wxImageResolution resUnit = wxIMAGE_RESOLUTION_NONE;
37ba70a5 428 uint16 tiffRes;
4d37f425 429 if ( TIFFGetFieldDefaulted(tif, TIFFTAG_RESOLUTIONUNIT, &tiffRes) )
37ba70a5 430 {
4d37f425 431 switch (tiffRes)
37ba70a5
VZ
432 {
433 default:
434 wxLogWarning(_("Unknown TIFF resolution unit %d ignored"),
4d37f425 435 tiffRes);
37ba70a5
VZ
436 // fall through
437
438 case RESUNIT_NONE:
4d37f425 439 resUnit = wxIMAGE_RESOLUTION_NONE;
37ba70a5
VZ
440 break;
441
442 case RESUNIT_INCH:
4d37f425 443 resUnit = wxIMAGE_RESOLUTION_INCHES;
37ba70a5
VZ
444 break;
445
446 case RESUNIT_CENTIMETER:
4d37f425 447 resUnit = wxIMAGE_RESOLUTION_CM;
37ba70a5
VZ
448 break;
449 }
4d37f425 450 }
37ba70a5 451
4d37f425 452 image->SetOption(wxIMAGE_OPTION_RESOLUTIONUNIT, resUnit);
37ba70a5 453
4d37f425
DS
454 /*
455 Set the image resolution if it's available. Resolution tag is not
456 dependant on RESOLUTIONUNIT != RESUNIT_NONE (according to TIFF spec).
457 */
458 float resX, resY;
459
460 if ( TIFFGetField(tif, TIFFTAG_XRESOLUTION, &resX) )
461 {
462 /*
463 Use a string value to not lose precision.
464 rounding to int as cm and then converting to inch may
465 result in whole integer rounding error, eg. 201 instead of 200 dpi.
466 If an app wants an int, GetOptionInt will convert and round down.
467 */
468 image->SetOption(wxIMAGE_OPTION_RESOLUTIONX,
469 wxString::FromCDouble((double) resX));
37ba70a5
VZ
470 }
471
4d37f425
DS
472 if ( TIFFGetField(tif, TIFFTAG_YRESOLUTION, &resY) )
473 {
474 image->SetOption(wxIMAGE_OPTION_RESOLUTIONY,
475 wxString::FromCDouble((double) resY));
476 }
37ba70a5 477
257bcf28 478 _TIFFfree( raster );
13111b2a 479
257bcf28 480 TIFFClose( tif );
13111b2a 481
7beb59f3 482 return true;
257bcf28
RR
483}
484
8faef7cc 485int wxTIFFHandler::DoGetImageCount( wxInputStream& stream )
700ec454
RR
486{
487 TIFF *tif = TIFFwxOpen( stream, "image", "r" );
13111b2a 488
700ec454 489 if (!tif)
13111b2a 490 return 0;
257bcf28 491
700ec454
RR
492 int dircount = 0; // according to the libtiff docs, dircount should be set to 1 here???
493 do {
494 dircount++;
495 } while (TIFFReadDirectory(tif));
13111b2a 496
700ec454 497 TIFFClose( tif );
03647350 498
8faef7cc
FM
499 // NOTE: this function modifies the current stream position but it's ok
500 // (see wxImageHandler::GetImageCount)
13111b2a 501
700ec454
RR
502 return dircount;
503}
257bcf28 504
f6bcfd97 505bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose )
257bcf28 506{
f6bcfd97
BP
507 TIFF *tif = TIFFwxOpen( stream, "image", "w" );
508
509 if (!tif)
510 {
511 if (verbose)
af588446 512 {
f6bcfd97 513 wxLogError( _("TIFF: Error saving image.") );
af588446 514 }
f6bcfd97 515
7beb59f3 516 return false;
f6bcfd97
BP
517 }
518
fe9308c6 519 TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
f6bcfd97
BP
520 TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (uint32)image->GetWidth());
521 TIFFSetField(tif, TIFFTAG_IMAGELENGTH, (uint32)image->GetHeight());
522 TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
f6bcfd97 523 TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
38755449 524
37ba70a5
VZ
525 // save the image resolution if we have it
526 int xres, yres;
527 const wxImageResolution res = GetResolutionFromOptions(*image, &xres, &yres);
528 uint16 tiffRes;
529 switch ( res )
fe9308c6 530 {
37ba70a5 531 default:
9a83f860 532 wxFAIL_MSG( wxT("unknown image resolution units") );
37ba70a5
VZ
533 // fall through
534
535 case wxIMAGE_RESOLUTION_NONE:
536 tiffRes = RESUNIT_NONE;
537 break;
538
539 case wxIMAGE_RESOLUTION_INCHES:
540 tiffRes = RESUNIT_INCH;
541 break;
542
543 case wxIMAGE_RESOLUTION_CM:
544 tiffRes = RESUNIT_CENTIMETER;
545 break;
fe9308c6
VZ
546 }
547
37ba70a5
VZ
548 if ( tiffRes != RESUNIT_NONE )
549 {
550 TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, tiffRes);
551 TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)xres);
552 TIFFSetField(tif, TIFFTAG_YRESOLUTION, (float)yres);
553 }
554
555
fe9308c6
VZ
556 int spp = image->GetOptionInt(wxIMAGE_OPTION_SAMPLESPERPIXEL);
557 if ( !spp )
558 spp = 3;
559
560 int bpp = image->GetOptionInt(wxIMAGE_OPTION_BITSPERSAMPLE);
561 if ( !bpp )
37ba70a5 562 bpp = 8;
fe9308c6
VZ
563
564 int compression = image->GetOptionInt(wxIMAGE_OPTION_COMPRESSION);
565 if ( !compression )
f5e20985
VZ
566 {
567 // we can't use COMPRESSION_LZW because current version of libtiff
568 // doesn't implement it ("no longer implemented due to Unisys patent
569 // enforcement") and other compression methods are lossy so we
570 // shouldn't use them by default -- and the only remaining one is none
571 compression = COMPRESSION_NONE;
572 }
fe9308c6
VZ
573
574 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, spp);
575 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bpp);
576 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, spp*bpp == 1 ? PHOTOMETRIC_MINISBLACK
577 : PHOTOMETRIC_RGB);
578 TIFFSetField(tif, TIFFTAG_COMPRESSION, compression);
579
580 // scanlinesize if determined by spp and bpp
581 tsize_t linebytes = (tsize_t)image->GetWidth() * spp * bpp / 8;
582
583 if ( (image->GetWidth() % 8 > 0) && (spp * bpp < 8) )
584 linebytes+=1;
585
f6bcfd97 586 unsigned char *buf;
38755449 587
fe9308c6 588 if (TIFFScanlineSize(tif) > linebytes || (spp * bpp < 24))
f6bcfd97
BP
589 {
590 buf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(tif));
591 if (!buf)
592 {
593 if (verbose)
af588446 594 {
f6bcfd97 595 wxLogError( _("TIFF: Couldn't allocate memory.") );
af588446 596 }
f6bcfd97
BP
597
598 TIFFClose( tif );
599
7beb59f3 600 return false;
f6bcfd97 601 }
38755449
DW
602 }
603 else
f6bcfd97
BP
604 {
605 buf = NULL;
606 }
607
fe9308c6
VZ
608 TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP,TIFFDefaultStripSize(tif, (uint32) -1));
609
f6bcfd97 610 unsigned char *ptr = image->GetData();
fe9308c6 611 for ( int row = 0; row < image->GetHeight(); row++ )
f6bcfd97 612 {
fe9308c6
VZ
613 if ( buf )
614 {
615 if ( spp * bpp > 1 )
616 {
617 // color image
618 memcpy(buf, ptr, image->GetWidth());
619 }
620 else // black and white image
621 {
622 for ( int column = 0; column < linebytes; column++ )
623 {
624 uint8 reverse = 0;
fe9308c6
VZ
625 for ( int bp = 0; bp < 8; bp++ )
626 {
627 if ( ptr[column*24 + bp*3] > 0 )
628 {
629 // check only red as this is sufficient
38d4b1e4 630 reverse = (uint8)(reverse | 128 >> bp);
fe9308c6 631 }
fe9308c6
VZ
632 }
633
3ba9ea72 634 buf[column] = reverse;
fe9308c6
VZ
635 }
636 }
637 }
38755449 638
fe9308c6 639 if ( TIFFWriteScanline(tif, buf ? buf : ptr, (uint32)row, 0) < 0 )
f6bcfd97 640 {
19193a2c 641 if (verbose)
af588446 642 {
19193a2c 643 wxLogError( _("TIFF: Error writing image.") );
af588446 644 }
38755449 645
f6bcfd97
BP
646 TIFFClose( tif );
647 if (buf)
648 _TIFFfree(buf);
38755449 649
7beb59f3 650 return false;
f6bcfd97 651 }
fe9308c6 652
f6bcfd97
BP
653 ptr += image->GetWidth()*3;
654 }
655
656 (void) TIFFClose(tif);
657
658 if (buf)
fe9308c6 659 _TIFFfree(buf);
f6bcfd97 660
7beb59f3 661 return true;
257bcf28
RR
662}
663
664bool wxTIFFHandler::DoCanRead( wxInputStream& stream )
665{
0b72db08 666 unsigned char hdr[2];
257bcf28 667
8faef7cc 668 if ( !stream.Read(&hdr[0], WXSIZEOF(hdr)) ) // it's ok to modify the stream position here
7beb59f3 669 return false;
79fa2374 670
79fa2374
VZ
671 return (hdr[0] == 'I' && hdr[1] == 'I') ||
672 (hdr[0] == 'M' && hdr[1] == 'M');
257bcf28
RR
673}
674
e30285ab 675#endif // wxUSE_STREAMS
257bcf28 676
ccec9093
VZ
677/*static*/ wxVersionInfo wxTIFFHandler::GetLibraryVersionInfo()
678{
679 int major,
680 minor,
681 micro;
682
683 const wxString ver(::TIFFGetVersion());
9c1f960f 684 if ( wxSscanf(ver, "LIBTIFF, Version %d.%d.%d", &major, &minor, &micro) != 3 )
ccec9093
VZ
685 {
686 wxLogDebug("Unrecognized libtiff version string \"%s\"", ver);
687
688 major =
689 minor =
690 micro = 0;
691 }
692
693 wxString copyright;
694 const wxString desc = ver.BeforeFirst('\n', &copyright);
695 copyright.Replace("\n", "");
696
697 return wxVersionInfo("libtiff", major, minor, micro, desc, copyright);
698}
699
e30285ab 700#endif // wxUSE_LIBTIFF