00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "plstdpch.h"
00015 #include "pltiffdec.h"
00016 #include "plexcept.h"
00017
00018 extern "C"
00019 {
00020 #include "tif_msrc.h"
00021 }
00022
00023 char PLTIFFDecoder::m_szLastErr[256];
00024
00026
00027
00028 class _tiff_helper
00029 {
00030 public:
00031 _tiff_helper()
00032 {
00033
00034 TIFFSetErrorHandler (PLTIFFDecoder::Win32ErrorHandler);
00035 TIFFSetWarningHandler (PLTIFFDecoder::Win32WarningHandler);
00036 }
00037
00038
00039
00040 ~_tiff_helper()
00041 {}
00042
00043 };
00044
00045 static _tiff_helper _the_tiff_helper_singleton;
00046
00047
00048
00049
00050
00051 typedef unsigned char u_char;
00052
00053 #define REPEAT8(op) REPEAT4(op); REPEAT4(op)
00054 #define REPEAT4(op) REPEAT2(op); REPEAT2(op)
00055 #define REPEAT2(op) op; op
00056 #define CASE8(x,op) \
00057 switch (x) { \
00058 case 7: op; case 6: op; case 5: op; \
00059 case 4: op; case 3: op; case 2: op; \
00060 case 1: op; \
00061 }
00062 #define NOP
00063
00064 #define UNROLL8(w, op1, op2) { \
00065 uint32 _x; \
00066 for (_x = w; _x >= 8; _x -= 8) { \
00067 op1; \
00068 REPEAT8(op2); \
00069 } \
00070 if (_x > 0) { \
00071 op1; \
00072 CASE8(_x,op2); \
00073 } \
00074 }
00075
00076 #define PACK4(r,g,b,a) \
00077 ((uint32)(r)|((uint32)(g)<<8)|((uint32)(b)<<16)|((uint32)(a)<<24))
00078
00079
00080
00081
00082
00083 static void putRGBAAcontig8bittile(
00084 TIFFRGBAImage* img,
00085 uint32* cp,
00086 uint32 x, uint32 y,
00087 uint32 w, uint32 h,
00088 int32 fromskew, int32 toskew,
00089 u_char* pp
00090 )
00091 {
00092 int samplesperpixel = img->samplesperpixel;
00093
00094 (void) x; (void) y;
00095 fromskew *= samplesperpixel;
00096 while (h-- > 0) {
00097 UNROLL8(w, NOP,
00098 *cp++ = PACK4(pp[0], pp[1], pp[2], pp[3]);
00099 pp += samplesperpixel);
00100 cp += toskew;
00101 pp += fromskew;
00102 }
00103 }
00104
00106
00107
00108 PLTIFFDecoder::PLTIFFDecoder ()
00109 : PLPicDecoder()
00110
00111 {
00112 }
00113
00114
00115 PLTIFFDecoder::~PLTIFFDecoder ()
00116 {
00117 }
00118
00119
00120 void PLTIFFDecoder::DoTiffDecode (PLBmp * pBmp,
00121 PLDataSource * pDataSrc, TIFF* tif)
00122 {
00123 uint16 BitsPerSample;
00124 uint16 SamplePerPixel;
00125
00126
00127 TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &BitsPerSample);
00128 TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &SamplePerPixel);
00129
00130
00131
00132 if ((SamplePerPixel == 1 || SamplePerPixel == 2) && BitsPerSample <= 8
00133 && !TIFFIsTiled(tif))
00134 doLoColor(tif, pBmp);
00135 else
00136
00137
00138 doHiColor(tif, pBmp, SamplePerPixel);
00139 }
00140
00141
00142 void PLTIFFDecoder::DoDecode (PLBmp * pBmp,
00143 PLDataSource * pDataSrc)
00144 {
00145 TIFF* tif = TIFFOpenMem (pDataSrc->ReadEverything(),
00146 pDataSrc->GetFileSize(),
00147 NULL);
00148 if (!tif)
00149 raiseError (PL_ERRWRONG_SIGNATURE, m_szLastErr);
00150
00151 int DestBPP = 0;
00152 DoTiffDecode( pBmp, pDataSrc, tif );
00153
00154 pBmp->SetResolution(getResolution (tif));
00155
00156 TIFFClose(tif);
00157 }
00158
00159 const PLPoint PLTIFFDecoder::getResolution (TIFF* tif)
00160 {
00161 float nResX;
00162 nResX = 0.0;
00163 TIFFGetField(tif,TIFFTAG_XRESOLUTION,&nResX);
00164 if(nResX <= 1.0)
00165 nResX = 0.0;
00166
00167 float nResY;
00168 nResY = 0.0;
00169 TIFFGetField(tif,TIFFTAG_YRESOLUTION,&nResY);
00170 if(nResY <= 1.0)
00171 nResY = 0.0;
00172 uint16 resunit;
00173 if (!TIFFGetField (tif, TIFFTAG_RESOLUTIONUNIT, &resunit))
00174 resunit = RESUNIT_INCH;
00175
00176 if (resunit != RESUNIT_INCH)
00177 {
00178 nResX /= 39.37f;
00179 nResY /= 39.37f;
00180 }
00181
00182 return PLPoint (int (nResX+0.5), int (nResY+0.5));
00183 }
00184
00185 void PLTIFFDecoder::doHiColor (TIFF * tif, PLBmp * pBmp, uint16 SamplePerPixel)
00186 {
00187 int ok;
00188 PLULONG x, y;
00189
00190 TIFFRGBAImage img;
00191 char emsg[1024];
00192 PLBYTE * pBits;
00193
00194 ok = TIFFRGBAImageBegin(&img, tif, 0, emsg);
00195
00196 if (ok == 0)
00197 {
00198 TIFFClose (tif);
00199 raiseError (PL_ERRWRONG_SIGNATURE, m_szLastErr);
00200 }
00201
00202 bool bHasAlpha;
00203 bHasAlpha = (img.alpha != 0 || SamplePerPixel == 4);
00204 try
00205 {
00206 pBmp->Create (img.width, img.height, 32, bHasAlpha);
00207 pBits = new PLBYTE [img.width*img.height*4];
00208 if (pBits == NULL)
00209 raiseError (PL_ERRNO_MEMORY, "Out of memory allocating TIFF buffer.");
00210 }
00211 catch (PLTextException)
00212 {
00213 TIFFClose (tif);
00214 throw;
00215 }
00216
00217
00218 if (SamplePerPixel == 4 && img.bitspersample == 8)
00219 {
00220 img.put.contig = putRGBAAcontig8bittile;
00221 }
00222
00223 ok = TIFFRGBAImageGet(&img, (uint32 *) pBits, img.width, img.height);
00224 if (!ok)
00225 {
00226 TIFFRGBAImageEnd(&img);
00227 TIFFClose(tif);
00228 raiseError (PL_ERRWRONG_SIGNATURE, m_szLastErr);
00229 }
00230
00231 pBmp->Lock(false, true);
00232 PLPixel32 ** pLineArray = pBmp->GetLineArray32();
00233
00234
00235 for (y=0; y<img.height; y++)
00236 {
00237 PLBYTE * pSrc = pBits+(img.height-y-1)*img.width*4;
00238 PLPixel32 * pPixel = pLineArray[y];
00239 for (x=0; x<img.width; x++)
00240 {
00241 pPixel->Set (*pSrc, *(pSrc+1), *(pSrc+2), *(pSrc+3));
00242 pPixel++;
00243 pSrc += 4;
00244 }
00245 }
00246 pBmp->Unlock();
00247
00248
00249 delete [] pBits;
00250 TIFFRGBAImageEnd(&img);
00251 }
00252
00253
00254
00255
00256
00257
00258
00259 static int checkcmap(int n, uint16* r, uint16* g, uint16* b)
00260 {
00261 while (n-- > 0)
00262 if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256)
00263 return (16);
00264
00265 return (8);
00266 }
00267
00268 #define CVT(x) (((x) * 255L) / ((1L<<16)-1))
00269
00270 void PLTIFFDecoder::doLoColor (TIFF * tif, PLBmp * pBmp)
00271 {
00272 uint32 imageLength;
00273 uint32 imageWidth;
00274 uint16 BitsPerSample;
00275 uint16 SamplePerPixel;
00276 int32 LineSize;
00277 int16 PhotometricInterpretation;
00278 uint32 row;
00279 PLBYTE *pBits;
00280
00281 TIFFGetFieldDefaulted(tif, TIFFTAG_IMAGEWIDTH, &imageWidth);
00282 TIFFGetFieldDefaulted(tif, TIFFTAG_IMAGELENGTH, &imageLength);
00283 TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &BitsPerSample);
00284 TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &SamplePerPixel);
00285 TIFFGetFieldDefaulted(tif, TIFFTAG_PHOTOMETRIC, &PhotometricInterpretation);
00286
00287 if (PhotometricInterpretation!=PHOTOMETRIC_MINISWHITE &&
00288 PhotometricInterpretation!=PHOTOMETRIC_MINISBLACK &&
00289 PhotometricInterpretation!=PHOTOMETRIC_PALETTE)
00290 {
00291 PhotometricInterpretation = PHOTOMETRIC_MINISWHITE;
00292 Trace(2,"unexpected PhotometricInterpretation, default to PHOTOMETRIC_MINISWHITE");
00293 }
00294
00295 LineSize = TIFFScanlineSize(tif);
00296
00297 int nBPP;
00298 if (SamplePerPixel == 1 && BitsPerSample ==1)
00299 nBPP = 1;
00300 else
00301 nBPP = 8;
00302
00303 PLPixel32 pPal[256];
00304 try
00305 {
00306 pBmp->Create (imageWidth, imageLength, nBPP, 0);
00307 pBits = new PLBYTE [LineSize];
00308 if (pBits == NULL)
00309 raiseError (PL_ERRNO_MEMORY, "Out of memory allocating TIFF buffer.");
00310 }
00311 catch (PLTextException)
00312 {
00313 TIFFClose (tif);
00314 throw;
00315 }
00316
00317
00318
00319
00320 if
00321 (PhotometricInterpretation == PHOTOMETRIC_MINISWHITE ||
00322 PhotometricInterpretation == PHOTOMETRIC_MINISBLACK)
00323 {
00324 int numColors = 1 << BitsPerSample;
00325 PLBYTE step = 255 / (numColors-1);
00326 PLBYTE *pb = (PLBYTE *) (pPal);
00327 int offset = sizeof(PLPixel32);
00328 if (PhotometricInterpretation == PHOTOMETRIC_MINISWHITE)
00329 {
00330 pb += (numColors-1) * sizeof(PLPixel32);
00331 offset = -offset;
00332 }
00333
00334 for (int i = 0; i < numColors; ++i, pb += offset)
00335 {
00336 pb[PL_RGBA_RED] = pb[PL_RGBA_GREEN] = pb[PL_RGBA_BLUE] = i * step;
00337 pb[PL_RGBA_ALPHA] = 255;
00338 }
00339
00340 }
00341
00342
00343 else if (PhotometricInterpretation == PHOTOMETRIC_PALETTE)
00344 {
00345 uint16* red;
00346 uint16* green;
00347 uint16* blue;
00348 int16 i, Palette16Bits;
00349
00350
00351 i = TIFFGetField(tif, TIFFTAG_COLORMAP, &red, &green, &blue);
00352
00353
00354 Palette16Bits = checkcmap(1<<BitsPerSample, red, green, blue) == 16;
00355
00356
00357 for (i = 0; i < 1<<BitsPerSample; ++i)
00358 {
00359 PLBYTE *pb = (PLBYTE *) ((pPal)+i);
00360 pb[PL_RGBA_RED ] = (PLBYTE) (Palette16Bits ? CVT( red[i]) : red[i]);
00361 pb[PL_RGBA_GREEN] = (PLBYTE) (Palette16Bits ? CVT(green[i]) : green[i]);
00362 pb[PL_RGBA_BLUE ] = (PLBYTE) (Palette16Bits ? CVT( blue[i]) : blue[i]);
00363 pb[PL_RGBA_ALPHA] = 255;
00364 }
00365 }
00366 else
00367 Trace( 2, "unexpected PhotometricInterpretation in PLTIFFDecoder::DoLoColor()" );
00368
00369
00370
00371
00372
00373 pBmp->Lock(false, true);
00374 PLBYTE **pLineArray = pBmp->GetLineArray();
00375
00376 if (BitsPerSample > 8)
00377 Trace( 2, "unexpected bit-depth in PLTIFFDecoder::DoLoColor()" );
00378 else for ( row = 0; row < imageLength; ++row )
00379 {
00380 uint16 x;
00381 int status = TIFFReadScanline( tif, pBits, row, 0 );
00382 if (status == -1 && row < imageLength / 3)
00383 {
00384 delete [] pBits;
00385
00386 raiseError (PL_ERRINTERNAL, m_szLastErr);
00387 }
00388
00389
00390
00391
00392
00393 if (BitsPerSample == 4)
00394 {
00395 for (x=0; x < imageWidth / 2; ++x)
00396 {
00397 pLineArray[row][2*x ] = (pBits[x] & 0xf0) >> 4;
00398 pLineArray[row][2*x+1] = (pBits[x] & 0x0f);
00399 }
00400
00401 if (imageWidth & 1)
00402 pLineArray[row][imageWidth-1] = (pBits[x] & 0xf0) >> 4;
00403 }
00404 else
00405 if (SamplePerPixel == 1)
00406 memcpy( pLineArray[row], pBits, LineSize );
00407 else
00408 {
00409
00410
00411 PLASSERT (BitsPerSample == 8);
00412 for (x=0; x < imageWidth; ++x)
00413 pLineArray[row][x] = pBits[x*2];
00414 }
00415 }
00416 pBmp->Unlock();
00417
00418
00419 pBmp->SetPalette (pPal);
00420
00421 delete [] pBits;
00422 }
00423
00425
00426
00427 void PLTIFFDecoder::Win32ErrorHandler (const char* module, const char* fmt, va_list ap)
00428 {
00429 int k = vsprintf(m_szLastErr, fmt, ap);
00430 if (k >= 0) strcat( m_szLastErr + k, "\n" );
00431
00432 Trace (0, m_szLastErr);
00433
00434
00435 return;
00436 }
00437
00438 void PLTIFFDecoder::Win32WarningHandler (const char* module, const char* fmt, va_list ap)
00439 {
00440 char szTemp[256];
00441 char szMessage[256];
00442
00443 int k = vsprintf(szMessage, fmt, ap);
00444 if (k >= 0) strcat( szMessage + k, "\n" );
00445
00446 if (module != NULL)
00447 sprintf (szTemp, "Warning in LIBTIFF(%s): %s\n", module, szMessage);
00448 else
00449 sprintf (szTemp, "Warning in LIBTIFF: %s\n", szMessage);
00450
00451 Trace (2, szTemp);
00452
00453 return;
00454 }
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518