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

plpictdec.cpp

Go to the documentation of this file.
00001 /*
00002 /--------------------------------------------------------------------
00003 |
00004 |      $Id: plpictdec.cpp,v 1.1 2004/05/21 21:02:53 maxx Exp $
00005 |      Macintosh pict Decoder Class
00006 |
00007 |      This class decodes macintosh PICT files with 1,2,4,8,16 and 32
00008 |      bits per pixel as well as PICT/JPEG. If an alpha channel is
00009 |      present in a 32-bit-PICT, it is decoded as well.
00010 |      The PICT format is a general picture file format and can
00011 |      contain a lot of other elements besides bitmaps. These elements
00012 |      are ignored.
00013 |
00014 |      Copyright (c) 1996-1998 Ulrich von Zadow
00015 |
00016 \--------------------------------------------------------------------
00017 */
00018 
00019 #include "plstdpch.h"
00020 #include "config.h"
00021 #include "plpictdec.h"
00022 #ifdef PL_SUPPORT_JPEG
00023 #include "pljpegdec.h"
00024 #endif
00025 #include "ploptable.h"
00026 #include "plexcept.h"
00027 
00028 #include <stdio.h>
00029 
00030 PLPictDecoder::PLPictDecoder
00031     ( PLJPEGDecoder * pJPEGDecoder
00032     )
00033     : PLPicDecoder(),
00034       m_pJPEGDecoder (pJPEGDecoder),
00035       m_Resolution(0,0)
00036     // Creates a decoder
00037 {
00038 }
00039 
00040 
00041 PLPictDecoder::~PLPictDecoder
00042     ()
00043 {
00044 }
00045 
00046 
00047 void PLPictDecoder::DoDecode
00048     ( PLBmp * pBmp,
00049       PLDataSource * pDataSrc
00050     )
00051     // Called by MakeDIB to do the actual decoding.
00052 {
00053   int Version;
00054 
00055   Trace (2, "Decoding mac pict.\n");
00056 
00057   // Skip empty 512 byte header.
00058   pDataSrc->Skip (512);
00059 
00060   // Read PICT header
00061   readHeader (pDataSrc, Version);
00062 
00063   interpretOpcodes (pBmp, pDataSrc, Version);
00064   pBmp->SetResolution (m_Resolution);
00065 }
00066 
00067 void PLPictDecoder::readHeader
00068     ( PLDataSource * pDataSrc,
00069       int& Version
00070     )
00071     // Decodes header and version information.
00072     // Performs checks to make sure the data is really a pict file.
00073 {
00074   PLBYTE ch;
00075   PLWORD PicSize;  // Version 1 picture size. Ignored in version 2.
00076   char sz[256];
00077   MacRect Frame;
00078 
00079   PicSize = ReadMWord (pDataSrc);
00080 
00081   readRect (&Frame, pDataSrc);
00082 
00083   while ((ch = ReadByte(pDataSrc)) == 0);
00084   if (ch != 0x11)
00085                 raiseError (PL_ERRWRONG_SIGNATURE,
00086                 "Error decoding pict: Version number missing.");
00087 
00088   switch (ReadByte(pDataSrc))
00089   {
00090     case 1:
00091       Version = 1;
00092       break;
00093     case 2:
00094       if (ReadByte(pDataSrc) != 0xff)
00095         raiseError (PL_ERRWRONG_SIGNATURE,
00096                     "Illegal version number.");
00097       Version = 2;
00098       break;
00099     default:
00100       raiseError (PL_ERRWRONG_SIGNATURE,
00101                   "Illegal version number.");
00102   }
00103 
00104   sprintf (sz, "PICT version %d found.\n", Version);
00105   Trace (2, sz);
00106 }
00107 
00108 
00109 void PLPictDecoder::interpretOpcodes
00110     ( PLBmp * pBmp,
00111       PLDataSource * pDataSrc,
00112       int& Version
00113     )
00114     // This is the main decoder loop. The functions reads opcodes,
00115     // skips some, and hands the rest to opcode-specific functions.
00116     // It stops decoding after the first opcode containing bitmapped
00117     // data.
00118 {
00119   PLWORD   Opcode;
00120   char   sz[256];
00121 
00122   bool   bDone = false;
00123 
00124   while (!bDone)
00125   {
00126     Opcode = readOpcode(Version, pDataSrc);
00127 
00128     if (Opcode == 0xFF || Opcode == 0xFFFF)
00129     {
00130       bDone = true;
00131       Trace (2, "Opcode: End of pict.\n");
00132       raiseError (PL_ERRFORMAT_NOT_SUPPORTED,
00133                   "PICT contained only vector data!\n");
00134     }
00135     else if (Opcode < 0xa2)
00136     {
00137       if (!strcmp(optable[Opcode].name, "reserved"))
00138         sprintf (sz, "Opcode: reserved=0x%x\n", Opcode);
00139       else
00140         sprintf (sz, "Opcode: %s\n", optable[Opcode].name);
00141       Trace (2, sz);
00142 
00143       switch (Opcode)
00144       {
00145         case 0x01: // Clip
00146           clip (pDataSrc);
00147           break;
00148         case 0x12:
00149         case 0x13:
00150         case 0x14:
00151           pixPat (pDataSrc);
00152           break;
00153         case 0x70:
00154         case 0x71:
00155         case 0x72:
00156         case 0x73:
00157         case 0x74:
00158         case 0x75:
00159         case 0x76:
00160         case 0x77:
00161           skipPolyOrRegion (pDataSrc);
00162           break;
00163         case 0x90:
00164         case 0x98:
00165           bitsRect (pDataSrc, pBmp);
00166           bDone = true;
00167           break;
00168         case 0x91:
00169         case 0x99:
00170           bitsRegion (pDataSrc, pBmp);
00171           bDone = true;
00172           break;
00173         case 0x9a:
00174           opcode9a (pDataSrc, pBmp);
00175           bDone = true;
00176           break;
00177         case 0xa1:
00178           longComment (pDataSrc);
00179           break;
00180         default:
00181           // No function => skip to next Opcode
00182           if (optable[Opcode].len == WORD_LEN)
00183             pDataSrc->Skip(ReadMWord(pDataSrc));
00184            else
00185             pDataSrc->Skip(optable[Opcode].len);
00186       }
00187     }
00188     else if (Opcode == 0xc00)
00189     {
00190       Trace (2, "Opcode: Header.\n");
00191       headerOp (pDataSrc, pBmp);
00192     }
00193     else if (Opcode == 0x8200)
00194     {
00195       Trace (2, "Opcode: JPEG.\n");
00196       jpegOp (pDataSrc, pBmp);
00197       bDone = true;
00198     }
00199     else if (Opcode >= 0xa2 && Opcode <= 0xaf)
00200     {
00201       sprintf (sz, "Opcode: reserved 0x%x.\n", Opcode);
00202       Trace (2, sz);
00203       pDataSrc->Skip(ReadMWord(pDataSrc));
00204     }
00205     else if ((Opcode >= 0xb0 && Opcode <= 0xcf) ||
00206              (Opcode >= 0x8000 && Opcode <= 0x80ff))
00207     {
00208       // just a reserved Opcode, no data
00209       sprintf (sz, "Opcode: reserved 0x%x.\n", Opcode);
00210       Trace (2, sz);
00211     }
00212     else if ((Opcode >= 0xd0 && Opcode <= 0xfe) ||
00213              (Opcode >= 8100 && Opcode <= 0xffff))
00214     {
00215       sprintf (sz, "Opcode: reserved 0x%x.\n", Opcode);
00216       Trace (2, sz);
00217       pDataSrc->Skip(ReadMLong(pDataSrc));
00218     }
00219     else if (Opcode >= 0x100 && Opcode <= 0x7fff)
00220     {
00221       sprintf (sz, "Opcode: reserved 0x%x.\n", Opcode);
00222       Trace (2, sz);
00223       pDataSrc->Skip((Opcode >> 7) & 255);
00224     }
00225     else
00226     {
00227       char sz[256];
00228       sprintf (sz, "Can't handle Opcode %x.\n", Opcode);
00229       raiseError (PL_ERRFORMAT_UNKNOWN, sz);
00230     }
00231   }
00232 }
00233 
00234 
00235 PLWORD PLPictDecoder::readOpcode
00236     ( int Version,
00237       PLDataSource * pDataSrc
00238     )
00239     // moves to an even byte position in the file and returns the
00240     // opcode found.
00241 {
00242   if (Version == 2)
00243     pDataSrc->AlignToWord();
00244 
00245   if (Version == 1)
00246     return ReadByte (pDataSrc);
00247    else
00248     return ReadMWord (pDataSrc);
00249 }
00250 
00251 
00253 // Opcode functions
00254 
00255 void PLPictDecoder::clip
00256     ( PLDataSource * pDataSrc
00257     )
00258     // skips clipping rectangle or region.
00259 {
00260   MacRect ClipRect;
00261 
00262   PLWORD len = ReadMWord(pDataSrc);
00263 
00264   if (len == 0x000a)
00265     { /* null rgn */
00266       readRect(&ClipRect, pDataSrc);
00267     }
00268    else
00269     pDataSrc->Skip(len - 2);
00270 }
00271 
00272 void PLPictDecoder::pixPat
00273     ( PLDataSource * pDataSrc
00274     )
00275     // skips pattern definition.
00276 {
00277   PLWORD       PatType;
00278   PLWORD       rowBytes;
00279   MacpixMap  p;
00280   PLWORD       NumColors;
00281 
00282   PatType = ReadMWord(pDataSrc);
00283 
00284   switch (PatType)
00285     {
00286       case 2:
00287         pDataSrc->Skip(8);
00288         pDataSrc->Skip(5);
00289         break;
00290       case 1:
00291         {
00292           pDataSrc->Skip(8);
00293           rowBytes = ReadMWord(pDataSrc);
00294           readRect(&p.Bounds, pDataSrc);
00295           readPixmap(&p, pDataSrc);
00296 
00297           PLPixel32 CT[256];
00298           readColourTable(&NumColors, pDataSrc, CT);
00299           skipBits(&p.Bounds, rowBytes, p.pixelSize, pDataSrc);
00300         }
00301         break;
00302       default:
00303         raiseError (PL_ERRFORMAT_UNKNOWN,
00304                     "Unknown pattern type in pixPat.");
00305     }
00306 }
00307 
00308 void PLPictDecoder::skipPolyOrRegion
00309     ( PLDataSource * pDataSrc
00310     )
00311 {
00312   Trace (3, "Skipping polygon or region.\n");
00313   pDataSrc->Skip (ReadMWord (pDataSrc) - 2);
00314 }
00315 
00316 void PLPictDecoder::bitsRect
00317     ( PLDataSource * pDataSrc,
00318       PLBmp * pBmp
00319     )
00320     // Bitmap/pixmap data clipped by a rectangle.
00321 {
00322   PLWORD rowBytes;
00323 
00324   rowBytes = ReadMWord(pDataSrc);    // Bytes per row in source when
00325                                      // uncompressed.
00326   if (rowBytes & 0x8000)
00327     doPixmap(rowBytes, false, pBmp, pDataSrc);
00328    else
00329     doBitmap(rowBytes, false, pBmp, pDataSrc);
00330 }
00331 
00332 void PLPictDecoder::bitsRegion
00333     ( PLDataSource * pDataSrc,
00334       PLBmp * pBmp
00335     )
00336     // Bitmap/pixmap data clipped by a region.
00337 {
00338   PLWORD rowBytes;
00339 
00340   rowBytes = ReadMWord(pDataSrc);    // Bytes per row in source when
00341                                      // uncompressed.
00342   if (rowBytes & 0x8000)
00343     doPixmap(rowBytes, true, pBmp, pDataSrc);
00344    else
00345     doBitmap(rowBytes, true, pBmp, pDataSrc);
00346 }
00347 
00348 void PLPictDecoder::opcode9a
00349     ( PLDataSource * pDataSrc,
00350       PLBmp * pBmp
00351     )
00352     // DirectBitsRect.
00353 {
00354   MacpixMap PixMap;
00355 
00356   pDataSrc->Skip(4);           // Skip fake len and fake EOF.
00357   ReadMWord(pDataSrc);         // bogus row bytes.
00358 
00359   // Read in the PixMap fields.
00360   readRect(&PixMap.Bounds, pDataSrc);
00361   readPixmap (&PixMap, pDataSrc);
00362 
00363   // Ignore source & destination rectangle as well as transfer mode.
00364   MacRect TempRect;
00365   readRect (&TempRect, pDataSrc);
00366   readRect (&TempRect, pDataSrc);
00367   PLWORD mode = ReadMWord(pDataSrc);
00368 
00369   // Create empty DIB
00370   createOutputBmp (PixMap, pBmp);
00371   pBmp->Lock(false, true);
00372 
00373   // Do the actual unpacking.
00374   switch (PixMap.pixelSize)
00375   {
00376     case 32:
00377       unpack32bits (&PixMap.Bounds, 0, PixMap.cmpCount, pBmp, pDataSrc);
00378       break;
00379     case 8:
00380       unpack8bits (&PixMap.Bounds, 0, pBmp, pDataSrc);
00381       break;
00382     default:
00383       unpackbits (&PixMap.Bounds, 0, PixMap.pixelSize, pBmp, pDataSrc);
00384   }
00385   pBmp->Unlock();
00386 }
00387 
00388 void PLPictDecoder::longComment
00389     ( PLDataSource * pDataSrc
00390     )
00391 {
00392   PLWORD type;
00393   PLWORD len;
00394 
00395   type = ReadMWord(pDataSrc);
00396   len = ReadMWord(pDataSrc);
00397   if (len > 0)
00398     pDataSrc->Skip (len);
00399 }
00400 
00401 void PLPictDecoder::headerOp 
00402     ( PLDataSource * pDataSrc,
00403       PLBmp * pBmp
00404     )
00405 {
00406   int Version = ReadMWord (pDataSrc);
00407   m_Resolution.x = ReadMLong(pDataSrc);
00408   m_Resolution.y = ReadMLong(pDataSrc);
00409   MacRect Dummy;
00410   readRect (&Dummy, pDataSrc);
00411   ReadMWord (pDataSrc);
00412 }
00413 
00414 void PLPictDecoder::jpegOp
00415     ( PLDataSource * pDataSrc,
00416       PLBmp * pBmp
00417     )
00418     // Invoke the JPEG decoder for this PICT.
00419 {
00420   long OpLen = ReadMLong(pDataSrc);
00421   bool bFound = false;
00422   int i = 0;
00423 
00424   // skip to JPEG header.
00425   while (!bFound && i < OpLen)
00426   {
00427     PLBYTE * pData = pDataSrc->GetBufferPtr (3);
00428     if (pData[0] == 0xFF && pData[1] == 0xD8 && pData[2] == 0xFF)
00429       bFound = true;
00430     else
00431     {
00432       ReadByte(pDataSrc);
00433       i++;
00434     }
00435   }
00436   if (bFound)
00437     // Pass the data to the JPEG decoder.
00438     if (m_pJPEGDecoder)
00439 #ifdef PL_SUPPORT_JPEG
00440       m_pJPEGDecoder->MakeBmp (pDataSrc, pBmp);
00441 #else
00442       raiseError (PL_ERRFORMAT_NOT_SUPPORTED,
00443                   "Library not compiled for PICT/JPEG.");
00444 #endif
00445      else
00446       raiseError (PL_ERRFORMAT_NOT_SUPPORTED,
00447                   "Library not compiled for PICT/JPEG.");
00448    else
00449     raiseError (PL_ERRFORMAT_NOT_SUPPORTED,
00450                 "PICT file contains unrecognized quicktime data.\n");
00451 }
00452 
00454 // Bitmap & Pixmap functions
00455 
00456 void PLPictDecoder::createOutputBmp
00457     ( MacpixMap PixMap,
00458       PLBmp * pBmp
00459     )
00460 {
00461   int DestBPP;
00462   if (PixMap.pixelSize > 8)
00463     DestBPP = 32;
00464   else
00465     DestBPP = 8;
00466 
00467   bool bAlpha = false;
00468   // Create empty DIB
00469   if (DestBPP == 32 && PixMap.cmpCount == 4)
00470     bAlpha = true;
00471   pBmp->Create (PixMap.Bounds.right - PixMap.Bounds.left,
00472                 PixMap.Bounds.bottom - PixMap.Bounds.top,
00473                 DestBPP, bAlpha);
00474 }
00475 
00476 
00477 void PLPictDecoder::doBitmap
00478     ( int rowBytes,
00479       bool bIsRegion,
00480       PLBmp * pBmp,
00481       PLDataSource * pDataSrc
00482     )
00483     // Decode version 1 bitmap: 1 bpp.
00484 {
00485   MacRect Bounds;
00486   MacRect SrcRect;
00487   MacRect DstRect;
00488   PLWORD    mode;
00489   PLWORD    width;        // Width in pixels
00490   PLWORD    height;       // Height in pixels
00491 
00492   Trace (2, "Reading version 1 bitmap.\n");
00493 
00494   readRect(&Bounds, pDataSrc);
00495   dumpRect ("  Bounds", &Bounds);
00496   readRect(&SrcRect, pDataSrc);
00497   readRect(&DstRect, pDataSrc);
00498 
00499   width = Bounds.right - Bounds.left;
00500   height = Bounds.bottom - Bounds.top;
00501 
00502   // Create empty DIB without resolution info.
00503   pBmp->Create (width, height, 8, false);
00504 
00505   mode = ReadMWord(pDataSrc);
00506 
00507   if (bIsRegion)
00508     skipPolyOrRegion (pDataSrc);
00509 
00510   pBmp->Lock(false, true);
00511   pBmp->SetPaletteEntry (0, 0, 0, 0, 255);
00512   pBmp->SetPaletteEntry (1, 255, 255, 255, 255);
00513   unpackbits (&Bounds, rowBytes, 1, pBmp, pDataSrc);
00514 
00515   pBmp->Unlock();
00516 }
00517 
00518 void PLPictDecoder::doPixmap
00519     ( int rowBytes,
00520       bool bIsRegion,
00521       PLBmp * pBmp,
00522       PLDataSource * pDataSrc
00523     )
00524     // Decode version 2 pixmap
00525 {
00526   MacpixMap   PixMap;
00527   PLWORD      NumColors;    // Palette size.
00528 
00529   readRect(&PixMap.Bounds, pDataSrc);
00530   readPixmap(&PixMap, pDataSrc);
00531 
00532   createOutputBmp (PixMap, pBmp);
00533 
00534   // Read mac colour table into windows palette.
00535   PLPixel32 Pal[256];
00536   readColourTable (&NumColors, pDataSrc, Pal);
00537   if (pBmp->GetBitsPerPixel() == 8)
00538     pBmp->SetPalette (Pal);
00539 
00540   // Ignore source & destination rectangle as well as transfer mode.
00541   MacRect TempRect;
00542   readRect (&TempRect, pDataSrc);
00543   readRect (&TempRect, pDataSrc);
00544   PLWORD mode = ReadMWord(pDataSrc);
00545 
00546   if (bIsRegion)
00547     skipPolyOrRegion (pDataSrc);
00548 
00549   pBmp->Lock(false, true);
00550   switch (PixMap.pixelSize)
00551   {
00552     case 32:
00553       unpack32bits (&PixMap.Bounds, rowBytes, PixMap.cmpCount, pBmp, pDataSrc);
00554       break;
00555     case 8:
00556       unpack8bits (&PixMap.Bounds, rowBytes, pBmp, pDataSrc);
00557       break;
00558     default:
00559       unpackbits (&PixMap.Bounds, rowBytes, PixMap.pixelSize,
00560                   pBmp, pDataSrc);
00561   }
00562   pBmp->Unlock();
00563 }
00564 
00565 void PLPictDecoder::unpack32bits
00566     ( MacRect* pBounds,
00567       PLWORD rowBytes,
00568       int NumBitPlanes,    // 3 if RGB, 4 if RGBA
00569       PLBmp * pBmp,
00570       PLDataSource * pDataSrc
00571     )
00572     // This routine decompresses BitsRects with a packType of 4 (and
00573     // 32 bits per pixel). In this format, each line is separated
00574     // into 8-bit-bitplanes and then compressed via RLE. To decode,
00575     // the routine decompresses each line & then juggles the bytes
00576     // around to get pixel-oriented data.
00577 {
00578   int    i,j;
00579   PLWORD   BytesPerRow;        // bytes per row when uncompressed.
00580   PLPixel32 * pDestLine;
00581 
00582   PLBYTE * pLinebuf;           // Temporary buffer for line data. In
00583                              // this buffer, pixels are uncompressed
00584                              // but still plane-oriented.
00585   PLPixel32 ** pLineArray = pBmp->GetLineArray32();
00586 
00587 
00588   int Height = pBounds->bottom - pBounds->top;
00589   int Width = pBounds->right - pBounds->left;
00590 
00591   BytesPerRow = Width*NumBitPlanes;
00592 
00593   if (rowBytes == 0)
00594     rowBytes = Width*4;
00595 
00596   // Allocate temporary line buffer.
00597   pLinebuf = new PLBYTE [BytesPerRow];
00598 
00599   try
00600   {
00601     for (i = 0; i < Height; i++)
00602     { // for each line do...
00603       int linelen;            // length of source line in bytes.
00604       if (rowBytes > 250)
00605         linelen = ReadMWord(pDataSrc);
00606        else
00607         linelen = ReadByte(pDataSrc);
00608 
00609       PLBYTE * pBuf = unpackPictRow (pLinebuf, pDataSrc, Width, rowBytes, linelen);
00610 
00611       // Convert plane-oriented data into pixel-oriented data &
00612       // copy into destination bitmap.
00613       pDestLine = pLineArray[i];
00614 
00615       if (NumBitPlanes == 3)
00616         for (j = 0; j < Width; j++)
00617         { // For each pixel in line...
00618           pDestLine->SetB (*(pBuf+Width*2));     // Blue
00619           pDestLine->SetG (*(pBuf+Width));       // Green
00620           pDestLine->SetR (*pBuf);             // Red
00621           pDestLine->SetA (0xFF);        
00622           pDestLine++;
00623           pBuf++;
00624         }
00625       else
00626         for (j = 0; j < Width; j++)
00627         { // For each pixel in line...
00628           pDestLine->SetB (*(pBuf+Width*3));     // Blue
00629           pDestLine->SetG (*(pBuf+Width*2));     // Green
00630           pDestLine->SetR (*(pBuf+Width));       // Red
00631           pDestLine->SetA (*pBuf);        
00632           pDestLine++;
00633           pBuf++;
00634         }
00635     }
00636   }
00637   catch (PLTextException)
00638   {
00639     delete [] pLinebuf;
00640     throw;
00641   }
00642   catch(...)
00643   {
00644     delete [] pLinebuf;
00645     throw;
00646   }
00647   delete [] pLinebuf;
00648 }
00649 
00650 
00651 void PLPictDecoder::unpack8bits
00652     ( MacRect* pBounds,
00653       PLWORD rowBytes,
00654       PLBmp * pBmp,
00655       PLDataSource * pDataSrc
00656     )
00657     // Decompression routine for 8 bpp. rowBytes is the number of
00658     // bytes each source row would take if it were uncompressed.
00659     // This _isn't_ equal to the number of pixels in the row - it
00660     // seems apple pads the data to a word boundary and then
00661     // compresses it. Of course, we have to decompress the excess
00662     // data and then throw it away.
00663 {
00664   int     i;
00665   PLBYTE ** pLineArray = pBmp->GetLineArray();
00666 
00667   int Height = pBounds->bottom - pBounds->top;
00668   int Width = pBounds->right - pBounds->left;
00669 
00670   // High bit of rowBytes is flag.
00671   rowBytes &= 0x7fff;
00672 
00673   if (rowBytes == 0)
00674     rowBytes = Width;
00675 
00676   PLBYTE * pLineBuf = new PLBYTE [rowBytes];
00677 
00678   try
00679   {
00680     for (i = 0; i < Height; i++)
00681     {
00682       int linelen;            // length of source line in bytes.
00683       if (rowBytes > 250)
00684         linelen = ReadMWord(pDataSrc);
00685        else
00686         linelen = ReadByte(pDataSrc);
00687       PLBYTE * pRawLine = unpackPictRow (pLineBuf, pDataSrc, Width, rowBytes, linelen);
00688       memcpy (pLineArray[i], pRawLine, Width);
00689     }
00690   }
00691   catch (PLTextException)
00692   {
00693     delete [] pLineBuf;
00694     throw;
00695   }
00696   delete [] pLineBuf;
00697 }
00698 
00699 
00700 void PLPictDecoder::unpackbits
00701     ( MacRect* pBounds,
00702       PLWORD rowBytes,
00703       int pixelSize,         // Source bits per pixel.
00704       PLBmp * pBmp,
00705       PLDataSource * pDataSrc
00706     )
00707     // Decompression routine for everything but 8 & 32 bpp. This
00708     // routine is slower than the two routines above since it has to
00709     // deal with a lot of special cases :-(.
00710     // It's also a bit chaotic because of these special cases...
00711     // unpack8bits is basically a dumber version of unpackbits.
00712 {
00713   PLBYTE * pSrcLine;           // Pointer to source line in file.
00714   int    i,j,k;
00715   PLWORD   pixwidth;           // bytes per row when uncompressed.
00716   int    linelen;            // length of source line in bytes.
00717   int    pkpixsize;
00718   PLBYTE * pDestLine;
00719   PLBYTE   FlagCounter;
00720   int    len;
00721   int    PixelPerRLEUnit=0;
00722   PLBYTE * pLineBuf=NULL;
00723   PLBYTE * pBuf;
00724   PLBYTE ** pLineArray = pBmp->GetLineArray();
00725 
00726   int Height = pBounds->bottom - pBounds->top;
00727   int Width = pBounds->right - pBounds->left;
00728 
00729   // High bit of rowBytes is flag.
00730   if (pixelSize <= 8)
00731     rowBytes &= 0x7fff;
00732 
00733   pixwidth = Width;
00734   pkpixsize = 1;          // RLE unit: one byte for everything...
00735   if (pixelSize == 16)    // ...except 16 bpp.
00736   {
00737     pkpixsize = 2;
00738     pixwidth *= 2;
00739   }
00740 
00741   if (rowBytes == 0)
00742     rowBytes = pixwidth;
00743 
00744   try
00745   {
00746     // I allocate the temporary line buffer here. I allocate too
00747     // much memory to compensate for sloppy (& hence fast)
00748     // decompression.
00749     switch (pixelSize)
00750     {
00751       case 1:
00752         PixelPerRLEUnit = 8;
00753         pLineBuf = new PLBYTE [(rowBytes+1) * 32];
00754         break;
00755       case 2:
00756         PixelPerRLEUnit = 4;
00757         pLineBuf = new PLBYTE [(rowBytes+1) * 16];
00758         break;
00759       case 4:
00760         PixelPerRLEUnit = 2;
00761         pLineBuf = new PLBYTE [(rowBytes+1) * 8];
00762         break;
00763       case 8:
00764         PixelPerRLEUnit = 1;
00765         pLineBuf = new PLBYTE [rowBytes * 4];
00766         break;
00767       case 16:
00768         PixelPerRLEUnit = 1;
00769         pLineBuf = new PLBYTE [rowBytes * 2 + 4];
00770         break;
00771       default:
00772         char sz[256];
00773         sprintf (sz,
00774                  "Illegal bpp value in unpackbits: %d\n",
00775                  pixelSize);
00776         raiseError (PL_ERRFORMAT_UNKNOWN, sz);
00777     }
00778 
00779     if (rowBytes < 8)
00780     { // ah-ha!  The bits aren't actually packed.  This will be easy.
00781       for (i = 0; i < Height; i++)
00782       {
00783         pDestLine = pLineArray[i];
00784         pSrcLine = pDataSrc->ReadNBytes (rowBytes);
00785         if (pixelSize == 16)
00786           expandBuf(pDestLine, pSrcLine, Width, pixelSize);
00787         else
00788           expandBuf8(pDestLine, pSrcLine, Width, pixelSize);
00789       }
00790     }
00791     else
00792     {
00793       for (i = 0; i < Height; i++)
00794       { // For each line do...
00795         if (rowBytes > 250)
00796           linelen = ReadMWord(pDataSrc);
00797          else
00798           linelen = ReadByte(pDataSrc);
00799 
00800         pSrcLine = pDataSrc->ReadNBytes(linelen);
00801         pBuf = pLineBuf;
00802 
00803         // Unpack RLE. The data is packed bytewise - except for
00804         // 16 bpp data, which is packed per pixel :-(.
00805         for (j = 0; j < linelen; )
00806         {
00807           FlagCounter = pSrcLine[j];
00808           if (FlagCounter & 0x80)
00809           {
00810             if (FlagCounter == 0x80)
00811               // Special case: repeat value of 0.
00812               // Apple sais ignore.
00813               j++;
00814             else
00815             { // Packed data.
00816               len = ((FlagCounter ^ 255) & 255) + 2;
00817 
00818               // This is slow for some formats...
00819               if (pixelSize == 16)
00820               {
00821                 expandBuf (pBuf, pSrcLine+j+1, 1, pixelSize);
00822                 for (k = 1; k < len; k++)
00823                 { // Repeat the pixel len times.
00824                   memcpy (pBuf+(k*4*PixelPerRLEUnit), pBuf,
00825                           4*PixelPerRLEUnit);
00826                 }
00827                 pBuf += len*4*PixelPerRLEUnit;
00828               }
00829               else
00830               {
00831                 expandBuf8 (pBuf, pSrcLine+j+1, 1, pixelSize);
00832                 for (k = 1; k < len; k++)
00833                 { // Repeat the expanded byte len times.
00834                   memcpy (pBuf+(k*PixelPerRLEUnit), pBuf,
00835                           PixelPerRLEUnit);
00836                 }
00837                 pBuf += len*PixelPerRLEUnit;
00838               }
00839               j += 1 + pkpixsize;
00840             }
00841           }
00842           else
00843           { // Unpacked data
00844             len = (FlagCounter & 255) + 1;
00845             if (pixelSize == 16)
00846             {
00847               expandBuf (pBuf, pSrcLine+j+1, len, pixelSize);
00848               pBuf += len*4*PixelPerRLEUnit;
00849             }
00850             else
00851             {
00852               expandBuf8 (pBuf, pSrcLine+j+1, len, pixelSize);
00853               pBuf += len*PixelPerRLEUnit;
00854             }
00855             j += len * pkpixsize + 1;
00856           }
00857         }
00858         pDestLine = pLineArray[i];
00859         if (pixelSize == 16)
00860           memcpy (pDestLine, pLineBuf, 4*Width);
00861         else
00862           memcpy (pDestLine, pLineBuf, Width);
00863       }
00864     }
00865   }
00866   catch (PLTextException)
00867   {
00868     delete [] pLineBuf;
00869     throw;
00870   }
00871 
00872   delete [] pLineBuf;
00873 }
00874 
00875 void PLPictDecoder::skipBits
00876     ( MacRect* pBounds,
00877       PLWORD rowBytes,
00878       int pixelSize,         // Source bits per pixel.
00879       PLDataSource * pDataSrc
00880     )
00881     // skips unneeded packbits.
00882 {
00883   int    i;
00884   PLWORD   pixwidth;           // bytes per row when uncompressed.
00885   int    linelen;            // length of source line in bytes.
00886 
00887   int Height = pBounds->bottom - pBounds->top;
00888   int Width = pBounds->right - pBounds->left;
00889 
00890   // High bit of rowBytes is flag.
00891   if (pixelSize <= 8)
00892     rowBytes &= 0x7fff;
00893 
00894   pixwidth = Width;
00895 
00896   if (pixelSize == 16)
00897     pixwidth *= 2;
00898 
00899   if (rowBytes == 0)
00900     rowBytes = pixwidth;
00901 
00902   if (rowBytes < 8)
00903   {
00904     pDataSrc->Skip (rowBytes*Height);
00905   }
00906   else
00907   {
00908     for (i = 0; i < Height; i++)
00909     {
00910       if (rowBytes > 250)
00911         linelen = ReadMWord(pDataSrc);
00912        else
00913         linelen = ReadByte(pDataSrc);
00914       pDataSrc->Skip (linelen);
00915     }
00916   }
00917 }
00918 
00919 
00920 void PLPictDecoder::expandBuf
00921     ( PLBYTE * pDestBuf,
00922       PLBYTE * pSrcBuf,
00923       int Width,       // Width in bytes for 8 bpp or less.
00924                        // Width in pixels for 16 bpp.
00925       int bpp          // bits per pixel
00926     )
00927     // Expands Width units to 32-bit pixel data.
00928 {
00929   PLBYTE * pSrc;
00930   PLBYTE * pDest;
00931   int i;
00932 
00933   pSrc = pSrcBuf;
00934   pDest = pDestBuf;
00935 
00936   switch (bpp)
00937   {
00938     case 16:
00939       for (i=0; i<Width; i++)
00940       {
00941         PLWORD Src = pSrcBuf[1]+(pSrcBuf[0]<<8);
00942         *(pDestBuf+PL_RGBA_BLUE) = ((Src) & 31)*8;          // Blue
00943         *(pDestBuf+PL_RGBA_GREEN) = ((Src >> 5) & 31)*8;    // Green
00944         *(pDestBuf+PL_RGBA_RED) = ((Src  >> 10) & 31)*8;    // Red
00945         *(pDestBuf+PL_RGBA_ALPHA) = 0xFF;                   // Alpha
00946         pSrcBuf += 2;
00947         pDestBuf += 4;
00948       }
00949       break;
00950     default:
00951       raiseError (PL_ERRFORMAT_UNKNOWN,
00952                   "Bad bits per pixel in expandBuf.");
00953   }
00954   return;
00955 }
00956 
00957 
00958 void PLPictDecoder::expandBuf8
00959     ( PLBYTE * pDestBuf,
00960       PLBYTE * pSrcBuf,
00961       int Width,       // Width in bytes.
00962       int bpp          // bits per pixel.
00963     )
00964     // Expands Width units to 8-bit pixel data.
00965     // Max. 8 bpp source format.
00966 {
00967   PLBYTE * pSrc;
00968   PLBYTE * pDest;
00969   int i;
00970 
00971   pSrc = pSrcBuf;
00972   pDest = pDestBuf;
00973 
00974   switch (bpp)
00975   {
00976     case 8:
00977       memcpy (pDestBuf, pSrcBuf, Width);
00978       break;
00979     case 4:
00980       for (i=0; i<Width; i++)
00981       {
00982         *pDest = (*pSrc >> 4) & 15;
00983         *(pDest+1) = (*pSrc & 15);
00984         pSrc++;
00985         pDest += 2;
00986       }
00987       if (Width & 1) // Odd Width?
00988       {
00989         *pDest = (*pSrc >> 4) & 15;
00990         pDest++;
00991       }
00992       break;
00993     case 2:
00994       for (i=0; i<Width; i++)
00995       {
00996         *pDest = (*pSrc >> 6) & 3;
00997         *(pDest+1) = (*pSrc >> 4) & 3;
00998         *(pDest+2) = (*pSrc >> 2) & 3;
00999         *(pDest+3) = (*pSrc & 3);
01000         pSrc++;
01001         pDest += 4;
01002       }
01003       if (Width & 3)  // Check for leftover pixels
01004         for (i=6; i>8-(Width & 3)*2; i-=2)
01005         {
01006           *pDest = (*pSrc >> i) & 3;
01007           pDest++;
01008         }
01009       break;
01010     case 1:
01011       for (i=0; i<Width; i++)
01012       {
01013         *pDest = (*pSrc >> 7) & 1;
01014         *(pDest+1) = (*pSrc >> 6) & 1;
01015         *(pDest+2) = (*pSrc >> 5) & 1;
01016         *(pDest+3) = (*pSrc >> 4) & 1;
01017         *(pDest+4) = (*pSrc >> 3) & 1;
01018         *(pDest+5) = (*pSrc >> 2) & 1;
01019         *(pDest+6) = (*pSrc >> 1) & 1;
01020         *(pDest+7) = (*pSrc  & 1);
01021         pSrc++;
01022         pDest += 8;
01023       }
01024       if (Width & 7)  // Check for leftover pixels
01025         for (i=7; i>(8-Width & 7); i--)
01026         {
01027           *pDest = (*pSrc >> i) & 1;
01028           pDest++;
01029         }
01030       break;
01031     default:
01032       raiseError (PL_ERRFORMAT_UNKNOWN,
01033                   "Bad bits per pixel in expandBuf8.");
01034   }
01035   return;
01036 }
01037 
01038 
01040 // Auxillary functions
01041 
01042 void PLPictDecoder::readPixmap
01043     ( MacpixMap * pPixMap,
01044       PLDataSource * pDataSrc
01045     )
01046 {
01047   pPixMap->version = ReadMWord(pDataSrc);
01048   pPixMap->packType = ReadMWord(pDataSrc);
01049   pPixMap->packSize = ReadMLong(pDataSrc);
01050   pPixMap->hRes = ReadMLong(pDataSrc);
01051   pPixMap->vRes = ReadMLong(pDataSrc);
01052   pPixMap->pixelType = ReadMWord(pDataSrc);
01053   pPixMap->pixelSize = ReadMWord(pDataSrc);
01054   pPixMap->cmpCount = ReadMWord(pDataSrc);
01055   pPixMap->cmpSize = ReadMWord(pDataSrc);
01056   pPixMap->planeBytes = ReadMLong(pDataSrc);
01057   pPixMap->pmTable = ReadMLong(pDataSrc);
01058   pPixMap->pmReserved = ReadMLong(pDataSrc);
01059 
01060   tracePixMapHeader (2, pPixMap);
01061 }
01062 
01063 void PLPictDecoder::readColourTable
01064     ( PLWORD * pNumColors,
01065       PLDataSource * pDataSrc,
01066       PLPixel32 * pPal
01067     )
01068     // Reads a mac colour table into a bitmap palette.
01069 {
01070   PLLONG        ctSeed;
01071   PLWORD        ctFlags;
01072   PLWORD        val;
01073   int         i;
01074 
01075   Trace (3, "Getting color table info.\n");
01076 
01077   ctSeed = ReadMLong(pDataSrc);
01078   ctFlags = ReadMWord(pDataSrc);
01079   *pNumColors = ReadMWord(pDataSrc)+1;
01080 
01081   char sz[256];
01082   sprintf (sz, "Palette Size:  %d\n", *pNumColors);
01083   Trace (2, sz);
01084   Trace (3, "Reading Palette.\n");
01085 
01086   for (i = 0; i < *pNumColors; i++)
01087   {
01088     val = ReadMWord(pDataSrc);
01089     if (ctFlags & 0x8000)
01090       // The indicies in a device colour table are bogus and
01091       // usually == 0, so I assume we allocate up the list of
01092       // colours in order.
01093       val = i;
01094     if (val >= *pNumColors)
01095     {
01096       raiseError (PL_ERRFORMAT_UNKNOWN,
01097                   "pixel value greater than colour table size.");
01098     }
01099     // Mac colour tables contain 16-bit values for R, G, and B...
01100     pPal[val].SetR ((PLBYTE) (((PLWORD) (ReadMWord(pDataSrc)) >> 8) & 0xFF));
01101     pPal[val].SetG ((PLBYTE) (((PLWORD) (ReadMWord(pDataSrc)) >> 8) & 0xFF));
01102     pPal[val].SetB ((PLBYTE) (((PLWORD) (ReadMWord(pDataSrc)) >> 8) & 0xFF));
01103   }
01104 
01105 }
01106 
01107 void PLPictDecoder::readRect
01108     ( MacRect * pr,
01109       PLDataSource * pDataSrc
01110     )
01111 {
01112   pr->top = ReadMWord(pDataSrc);
01113   pr->left = ReadMWord(pDataSrc);
01114   pr->bottom = ReadMWord(pDataSrc);
01115   pr->right = ReadMWord(pDataSrc);
01116 }
01117 
01118 
01119 void PLPictDecoder::dumpRect
01120     ( char * psz,
01121       MacRect * pr
01122     )
01123 {
01124   char sz[256];
01125   sprintf (sz, "%s (%d,%d) (%d,%d).\n",
01126            psz, pr->left, pr->top, pr->right, pr->bottom);
01127   Trace (2, sz);
01128 }
01129 
01130 
01131 void PLPictDecoder::tracePixMapHeader
01132     ( int Level,
01133       MacpixMap * pPixMap
01134     )
01135 {
01136   char sz[256];
01137   Trace (Level, "PixMap header info:\n");
01138   dumpRect ("  Bounds:", &(pPixMap->Bounds));
01139 
01140   sprintf (sz, "  version: 0x%x\n", pPixMap->version);
01141   Trace (Level, sz);
01142   sprintf (sz, "  packType: %d\n", pPixMap->packType);
01143   Trace (Level, sz);
01144   sprintf (sz, "  packSize: %ld\n", pPixMap->packSize);
01145   Trace (Level, sz);
01146   sprintf (sz, "  pixelSize: %d\n", pPixMap->pixelSize);
01147   Trace (Level, sz);
01148   sprintf (sz, "  cmpCount: %d\n", pPixMap->cmpCount);
01149   Trace (Level, sz);
01150   sprintf (sz, "  cmpSize: %d.\n", pPixMap->cmpSize);
01151   Trace (Level, sz);
01152   sprintf (sz, "  planeBytes: %ld.\n", pPixMap->planeBytes);
01153   Trace (Level, sz);
01154 }
01155 
01156 /*
01157 /--------------------------------------------------------------------
01158 |
01159 |      $Log: plpictdec.cpp,v $
01160 |      Revision 1.1  2004/05/21 21:02:53  maxx
01161 |      Initial Version of vuVolume, moderatly changed to make it compile on my windows and linux machine.
01162 |
01163 |      Revision 1.2  2003/01/07 16:14:58  sbergner
01164 |      *** empty log message ***
01165 |
01166 |      Revision 1.1  2002/11/13 01:58:21  mspindle
01167 |      *** empty log message ***
01168 |
01169 |      Revision 1.6  2001/10/21 17:12:40  uzadow
01170 |      Added PSD decoder beta, removed BPPWanted from all decoders, added PLFilterPixel.
01171 |
01172 |      Revision 1.5  2001/10/16 17:12:26  uzadow
01173 |      Added support for resolution information (Luca Piergentili)
01174 |
01175 |      Revision 1.4  2001/10/06 22:03:26  uzadow
01176 |      Added PL prefix to basic data types.
01177 |
01178 |      Revision 1.3  2001/10/06 15:32:22  uzadow
01179 |      Removed types LPBYTE, DWORD, UCHAR, VOID and INT from the code.
01180 |
01181 |      Revision 1.2  2001/09/16 20:57:17  uzadow
01182 |      Linux version name prefix changes
01183 |
01184 |      Revision 1.1  2001/09/16 19:03:22  uzadow
01185 |      Added global name prefix PL, changed most filenames.
01186 |
01187 |      Revision 1.12  2001/02/04 14:31:52  uzadow
01188 |      Member initialization list cleanup (Erik Hoffmann).
01189 |
01190 |      Revision 1.11  2001/01/21 14:28:21  uzadow
01191 |      Changed array cleanup from delete to delete[].
01192 |
01193 |      Revision 1.10  2000/12/18 22:42:52  uzadow
01194 |      Replaced RGBAPIXEL with PLPixel32.
01195 |
01196 |      Revision 1.9  2000/10/24 23:01:42  uzadow
01197 |      Fixed bug in ver.1 bitmap decoder
01198 |
01199 |      Revision 1.8  2000/08/13 12:11:43  Administrator
01200 |      Added experimental DirectDraw-Support
01201 |
01202 |      Revision 1.7  2000/05/27 16:28:28  Ulrich von Zadow
01203 |      Really fixed bug decoding pixmaps with < 8 bpp.
01204 |
01205 |      Revision 1.6  2000/03/15 17:23:20  Ulrich von Zadow
01206 |      Fixed bug decoding pixmaps with < 8 bpp.
01207 |
01208 |      Revision 1.5  2000/01/16 20:43:14  anonymous
01209 |      Removed MFC dependencies
01210 |
01211 |      Revision 1.4  1999/11/22 15:00:27  Ulrich von Zadow
01212 |      Fixed bug decoding small 24 bpp pict files.
01213 |
01214 |      Revision 1.3  1999/10/03 18:50:51  Ulrich von Zadow
01215 |      Added automatic logging of changes.
01216 |
01217 |
01218 \--------------------------------------------------------------------
01219 */

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