Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

pltiffdec.cpp

Go to the documentation of this file.
00001 /*
00002 /--------------------------------------------------------------------
00003 |
00004 |      $Id: pltiffdec.cpp,v 1.1 2004/05/21 21:02:53 maxx Exp $
00005 |      TIFF Decoder Class
00006 |
00007 |      TIFF file decoder. Uses LIBTIFF to do the actual conversion.
00008 |
00009 |      Copyright (c) 1996-2002 Ulrich von Zadow
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 //  helper class to setup libtiff callbacks
00027 
00028 class _tiff_helper
00029 {
00030 public:
00031   _tiff_helper()
00032   {
00033     // Set up function pointers to error handling routines.
00034     TIFFSetErrorHandler (PLTIFFDecoder::Win32ErrorHandler);
00035     TIFFSetWarningHandler (PLTIFFDecoder::Win32WarningHandler);
00036   }
00037 
00038   // We could restore the internal (default) libtiff handlers,
00039   // but that is not generally useful
00040   ~_tiff_helper()
00041 {}
00042 
00043 };
00044 
00045 static _tiff_helper _the_tiff_helper_singleton;
00046 
00047 // Helper stuff to make sure photoshop alpha gets decoded too.
00048 // Copied from tif_getimage.c. If anyone knows how to do this in
00049 // an easier way, please tell me.
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  * 8-bit packed samples => RGBA w/ associated alpha
00081  * (known to have Map == NULL)
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 // Class functions
00107 
00108 PLTIFFDecoder::PLTIFFDecoder ()
00109   : PLPicDecoder()
00110 // Creates a decoder
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   // get tagged image parameters
00127   TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &BitsPerSample);
00128   TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &SamplePerPixel);
00129 
00130   // For the time being, paintlib bitmaps only actually support 8
00131   // or 32bpp; so the following mapping should cover all cases ...
00132   if ((SamplePerPixel == 1 || SamplePerPixel == 2) && BitsPerSample <= 8
00133       &&  !TIFFIsTiled(tif))
00134     doLoColor(tif, pBmp);
00135   else
00136     // complicated decoding; use higher-level API
00137     // it will promote all images to 32bpp, though
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   {  // Centimeters...
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   // Hack for photoshop alpha channel support
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   // Correct the byte ordering
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   // Clean up.
00249   delete [] pBits;
00250   TIFFRGBAImageEnd(&img);
00251 }
00252 
00253 /*
00254  * TIFF decoding for 1, 4 and 8 bit(s) per pixel
00255  * bdelmee; 10/98
00256  */
00257 
00258 /* check if color map holds old-style 8-bit values */
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); //Number of bytes in one line
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   // phase one: build color map
00319 
00320   if /* monochrome (=bitonal) or grayscale */
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     // warning: the following ignores possible halftone hints
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   //PhotometricInterpretation = 2 image is RGB
00342   //PhotometricInterpretation = 3 image has a color palette
00343   else if (PhotometricInterpretation == PHOTOMETRIC_PALETTE)
00344   {
00345     uint16* red;
00346     uint16* green;
00347     uint16* blue;
00348     int16 i, Palette16Bits;
00349 
00350     // we get pointers to libtiff-owned colormaps
00351     i = TIFFGetField(tif, TIFFTAG_COLORMAP, &red, &green, &blue);
00352 
00353     //Is the palette 16 or 8 bits ?
00354     Palette16Bits = checkcmap(1<<BitsPerSample, red, green, blue) == 16;
00355 
00356     //load the palette in the DIB
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   // phase two: read image itself
00370 
00371   //generally, TIFF images are ordered from upper-left to bottom-right
00372   // we implicitly assume PLANARCONFIG_CONTIG
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         // we should maybe free the BMP memory as well...
00386         raiseError (PL_ERRINTERNAL, m_szLastErr);
00387       }
00388       /*
00389       if (BitsPerSample == 1)  // go ahead, waste space ;-)
00390         for (x=0; x < imageWidth; ++x)
00391           pLineArray[row][x] = pBits[x / 8] & (128 >> (x & 7)) ? 1 : 0;
00392       else */
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         // odd number of pixels
00401         if (imageWidth & 1)
00402           pLineArray[row][imageWidth-1] = (pBits[x] & 0xf0) >> 4;
00403       }
00404       else //if (BitsPerSample == 8 || BitsPerSample == 1)
00405         if (SamplePerPixel == 1)
00406           memcpy( pLineArray[row], pBits, LineSize );
00407         else
00408         {
00409           // We've got an 8 bit image with an alpha channel.
00410           // Ignore the alpha channel.
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   // propagate colormap
00419   pBmp->SetPalette (pPal);
00420   // clean up
00421   delete [] pBits;
00422 }
00423 
00425 // Static functions used as Callbacks from the TIFF library
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   //raiseError (PL_ERRINTERNAL, m_szLastErr);
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 |      $Log: pltiffdec.cpp,v $
00459 |      Revision 1.1  2004/05/21 21:02:53  maxx
00460 |      Initial Version of vuVolume, moderatly changed to make it compile on my windows and linux machine.
00461 |
00462 |      Revision 1.1  2002/11/13 01:58:22  mspindle
00463 |      *** empty log message ***
00464 |
00465 |      Revision 1.7  2002/03/03 11:59:43  uzadow
00466 |      Updated to work with cygwin.
00467 |
00468 |      Revision 1.6  2002/02/11 16:45:36  uzadow
00469 |      Fixed bug decoding 16 bit per channel tiffs.
00470 |
00471 |      Revision 1.5  2001/10/21 17:12:40  uzadow
00472 |      Added PSD decoder beta, removed BPPWanted from all decoders, added PLFilterPixel.
00473 |
00474 |      Revision 1.4  2001/10/17 13:19:47  uzadow
00475 |      Added support for photoshop tiff alpha channels.
00476 |
00477 |      Revision 1.3  2001/10/16 17:12:26  uzadow
00478 |      Added support for resolution information (Luca Piergentili)
00479 |
00480 |      Revision 1.2  2001/10/06 22:03:26  uzadow
00481 |      Added PL prefix to basic data types.
00482 |
00483 |      Revision 1.1  2001/09/16 19:03:22  uzadow
00484 |      Added global name prefix PL, changed most filenames.
00485 |
00486 |      Revision 1.13  2001/09/15 14:37:34  uzadow
00487 |      Fixed palette handling for tiff < 4 bpp.
00488 |
00489 |      Revision 1.12  2001/02/04 14:31:52  uzadow
00490 |      Member initialization list cleanup (Erik Hoffmann).
00491 |
00492 |      Revision 1.11  2001/01/21 14:28:21  uzadow
00493 |      Changed array cleanup from delete to delete[].
00494 |
00495 |      Revision 1.10  2000/12/18 22:42:52  uzadow
00496 |      Replaced RGBAPIXEL with PLPixel32.
00497 |
00498 |      Revision 1.9  2000/08/13 12:11:43  Administrator
00499 |      Added experimental DirectDraw-Support
00500 |
00501 |      Revision 1.8  2000/03/16 13:56:37  Ulrich von Zadow
00502 |      Added pgm decoder by Jose Miguel Buenaposada Biencinto
00503 |
00504 |      Revision 1.7  2000/01/16 20:43:14  anonymous
00505 |      Removed MFC dependencies
00506 |
00507 |      Revision 1.6  2000/01/10 23:53:00  Ulrich von Zadow
00508 |      Changed formatting & removed tabs.
00509 |
00510 |      Revision 1.5  2000/01/09 22:24:10  Ulrich von Zadow
00511 |      Corrected tiff callback bug.
00512 |
00513 |      Revision 1.4  1999/10/03 18:50:52  Ulrich von Zadow
00514 |      Added automatic logging of changes.
00515 |
00516 |
00517 \--------------------------------------------------------------------
00518 */

Generated on Wed Dec 15 21:20:30 2004 for vuVolume by  doxygen 1.3.9.1