home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / BC_502 / OWLSRC.PAK / DIB.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  31.0 KB  |  1,204 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // Copyright (c) 1992, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   10.14  $
  6. //
  7. // Implementation of TDib class, an encapsulation of Device Independent Bitmaps
  8. // on disk and in memory.
  9. //----------------------------------------------------------------------------
  10. #pragma hdrignore SECTION
  11. #include <owl/pch.h>
  12. #if !defined(OWL_GDIOBJEC_H)
  13. # include <owl/gdiobjec.h>
  14. #endif
  15. #if !defined(OWL_METAFILE_H)
  16. # include <owl/metafile.h>
  17. #endif
  18. #if !defined(OWL_CLIPBOAR_H)
  19. # include <owl/clipboar.h>
  20. #endif
  21. #if !defined(OWL_EXCEPT_H)
  22. # include <owl/except.h>
  23. #endif
  24. #if !defined(CLASSLIB_FILE_H)
  25. # include <classlib/file.h>
  26. #endif
  27.  
  28. OWL_DIAGINFO;
  29. DIAG_DECLARE_GROUP(OwlGDI);        // General GDI diagnostic group
  30.  
  31. #if defined(BI_NAMESPACE)
  32. namespace OWL {
  33. #endif
  34.  
  35. //
  36. // Direct dib surface manipulation functions
  37. //
  38. extern "C"
  39. {
  40.   void WINAPI
  41.   DibCopyBlt8(uint8 huge* dstBits, uint32 width, uint32 height, uint32 dstPitch,
  42.               uint8 huge* srcBits, uint32 srcPitch);
  43.  
  44.   void WINAPI
  45.   DibSpriteBlt8(uint8 huge* dstBits, uint32 width, uint32 height, uint32 dstPitch,
  46.                uint8 huge* srcBits, uint32 srcPitch, uint8 transparent);
  47. }
  48.  
  49. //
  50. // Internal DIB file Read/Write functions talk to this IO implementation
  51. //
  52. class TFileIO : public TDib::IFileIn, public TDib::IFileOut {
  53.   public:
  54.     TFileIO(TFile& file) : File(file) {}
  55.  
  56.     virtual bool Read(void huge* buffer, long size)
  57.                  {
  58.                    return File.Read(buffer, size) == size;
  59.                  }
  60.     virtual void Skip(long size)
  61.                  {
  62.                    File.Seek(size, TFile::cur);
  63.                  }
  64.     virtual bool Write(void huge* buffer, long size)
  65.                  {
  66.                    return File.Write(buffer, size) == size;
  67.                  }
  68.  
  69.   private:
  70.     TFile& File;
  71. };
  72.  
  73. #if defined(BI_NAMESPACE)
  74. } // namespace OWL
  75. #endif
  76.  
  77. #if !defined(SECTION) || SECTION == 1  // Main ctors, dtor & helpers
  78.  
  79. //
  80. // Given a BITMAPINFOHEADER, allocate a global buffer for Handle & init Info
  81. //
  82. void
  83. TDib::InfoFromHeader(const BITMAPINFOHEADER& infoHeader)
  84. {
  85.   // Allocate & lock down the actual single memory block used by this DIB
  86.   //
  87.   int maskAlloc = infoHeader.biCompression==BI_BITFIELDS ? 3*sizeof(uint32) : 0;
  88.   int colorAlloc = int(infoHeader.biClrUsed * sizeof(RGBQUAD));   // Color table size in mem
  89.   IsResHandle = false;
  90.   uint32 size = sizeof(BITMAPINFOHEADER) + maskAlloc + colorAlloc +
  91.                 infoHeader.biSizeImage;
  92.   Handle = ::GlobalAlloc(GMEM_MOVEABLE, size);
  93.   if (!Handle)
  94.     TXOutOfMemory::Raise();
  95.  
  96.   // Setup Info ptr & copy over working infoHeader. Finish by using
  97.   // InfoFromHandle to update all members from Info.
  98.   //
  99.   Info = (LPBITMAPINFO)::GlobalLock(Handle);
  100.   Info->bmiHeader = infoHeader;
  101.  
  102.   InfoFromHandle();
  103. }
  104.  
  105. //
  106. // Lock the global/res handle if needed & extract the pointers and cached info
  107. // maintained as member variables from Info.
  108. //
  109. // Needs only Info setup, or if Info is 0 then Handle & IsResHandle setup
  110. //
  111. void
  112. TDib::InfoFromHandle()
  113. {
  114.   // Get the BITMAPINFO Info from the handle if needed
  115.   //
  116.   if (!Info) {
  117.     if (IsResHandle)
  118.       Info = (LPBITMAPINFO)::LockResource(Handle);
  119.     else
  120.       Info = (LPBITMAPINFO)::GlobalLock(Handle);
  121.   }
  122.   // Fail if the header does not look OK
  123.   //
  124.   if (Info->bmiHeader.biSize != sizeof(BITMAPINFOHEADER)) {
  125.     ::GlobalUnlock(Handle);
  126.     TXGdi::Raise(IDS_INVALIDDIBHANDLE);
  127.   }
  128.  
  129.   // Determine if there is a bit mask (used by 16 & 32 bpp bmps) and where
  130.   // the color table starts
  131.   //
  132.   if (Info->bmiHeader.biCompression == BI_BITFIELDS) {
  133.     Mask = (uint32 far*)Info->bmiColors;
  134.     Colors = (TRgbQuad far*)((char far*)Info->bmiColors + 3 * sizeof(uint32));
  135.   }
  136.   else {
  137.     Mask = 0;
  138.     Colors = (TRgbQuad far*)Info->bmiColors;
  139.   }
  140.  
  141.   // Figure out the number of colors in the color table using biClrsUsed &
  142.   // biBitCount.
  143.   //
  144.   NumClrs = Info->bmiHeader.biClrUsed
  145.               ? Info->bmiHeader.biClrUsed
  146.               : NColors(Info->bmiHeader.biBitCount);
  147.  
  148.   Bits = (char HUGE*)(char far*)Colors + (int)NumClrs * sizeof(RGBQUAD);
  149.  
  150.   // Zero out Colors if there is no color table.
  151.   //
  152.   if (!NumClrs)
  153.     Colors = 0;
  154.  
  155.   Mode = DIB_RGB_COLORS;
  156. }
  157.  
  158. //
  159. // Under Win32, resources are read-only. So, to allow for modification of the
  160. // Dib, a copy must be made.
  161. //
  162. #if defined(BI_PLAT_WIN32)
  163. void
  164. TDib::ResToMemHandle()
  165. {
  166.   long size = ((char huge*)Bits + Info->bmiHeader.biSizeImage) -
  167.                 (char huge*)Info;
  168. //  long size = ::SizeofResource(instance, resHandle);
  169.   HANDLE tempHandle = ::GlobalAlloc(GMEM_MOVEABLE, size);
  170.   if (!tempHandle)
  171.     TXOutOfMemory::Raise();
  172.  
  173.   void* tempInfo = ::GlobalLock(tempHandle);
  174.   hmemcpy(tempInfo, Info, size);
  175.  
  176.   // Handle will now be a memory handle, & no longer a res handle
  177.   // Update Bits pointer & other members that may have moved.
  178.   //
  179.   Handle = tempHandle;
  180.   Info = (LPBITMAPINFO)tempInfo;
  181.   IsResHandle = false;
  182.   InfoFromHandle();
  183. }
  184. #endif
  185.  
  186. //
  187. // Construct a TDib from a borrowed handle
  188. //
  189. TDib::TDib(HGLOBAL handle, TAutoDelete autoDelete)
  190. :
  191.   TGdiBase(handle, autoDelete),
  192.   Info(0), IsResHandle(false)
  193. {
  194.   InfoFromHandle();
  195. }
  196.  
  197. //
  198. // Construct a TDib borrowed from a clipboard handle
  199. //
  200. TDib::TDib(const TClipboard& clipboard)
  201. :
  202.   TGdiBase(clipboard.GetClipboardData(CF_DIB)),
  203.   Info(0), IsResHandle(false)
  204. {
  205.   InfoFromHandle();
  206. }
  207.  
  208. //
  209. // Construct a TDib that is a copy of an existing one
  210. //
  211. TDib::TDib(const TDib& src)
  212. :
  213.   IsResHandle(false)
  214. {
  215.   PRECONDITION(src.Info != 0);
  216.  
  217. //  long size = ::GlobalSize(src.Handle);  
  218.   uint32 size = src.SizeDib();
  219.   Handle = ::GlobalAlloc(GMEM_MOVEABLE, size);
  220.   if (!Handle)
  221.     TXOutOfMemory::Raise();
  222.  
  223.   Info = (LPBITMAPINFO)::GlobalLock(Handle);
  224.   hmemcpy(Info, src.Info, size);
  225.  
  226.   Mask = (uint32 far*)(src.Mask ?
  227.            (char HUGE*)Info + ((char HUGE*)src.Mask - (char HUGE*)src.Info) : 0);
  228.   Colors = (TRgbQuad far*)((char HUGE*)Info + ((char HUGE*)src.Colors - (char HUGE*)src.Info));
  229.   Bits = (char HUGE*)Info + ((char HUGE*)src.Bits - (char HUGE*)src.Info);
  230.  
  231.   NumClrs = src.NumClrs;
  232.   Mode = src.Mode;
  233. }
  234.  
  235. //
  236. // Destruct a TDib by unlocking & freeing its global memory handle as required
  237. //
  238. TDib::~TDib()
  239. {
  240.   if (Handle)
  241.     if (IsResHandle) {
  242. #if defined(BI_PLAT_WIN16)
  243.       ::UnlockResource(Handle);
  244.       if (ShouldDelete)
  245.         ::FreeResource(Handle);
  246. #endif
  247.     }
  248.     else {
  249.       ::GlobalUnlock(Handle);
  250.       if (ShouldDelete)
  251.         ::GlobalFree(Handle);
  252.     }
  253. }
  254.  
  255. //
  256. // Convert an absolute RGB color table to a palette relative color table
  257. // Makes sure that color table is RGB
  258. //
  259. bool
  260. TDib::ChangeModeToPal(const TPalette& pal)
  261. {
  262.   if (Mode != DIB_RGB_COLORS)
  263.     return false;
  264.  
  265.   uint16 nEntries = pal.GetNumEntries();
  266.  
  267.   for (int c = 0; c < NumClrs; c++) {
  268.     uint16 index = uint16(c);
  269.     for (uint16 i = 0; i < nEntries; i++) {
  270.       PALETTEENTRY pe; //getting all entries one time up front would be faster
  271.       pal.GetPaletteEntry(i, pe);
  272.       if (pe.peRed == Colors[c].rgbRed &&
  273.           pe.peGreen == Colors[c].rgbGreen &&
  274.           pe.peBlue == Colors[c].rgbBlue) {
  275.         index = i;
  276.         break;
  277.       }
  278.     }
  279.     ((uint16*)Colors)[c] = index;
  280.   }
  281.   Mode = DIB_PAL_COLORS;
  282.   return true;
  283. }
  284.  
  285. //
  286. // Convert a palette relative color table to an absolute RGB color table
  287. // Makes sure that color table is pal relative & that there is enough space
  288. //
  289. bool
  290. TDib::ChangeModeToRGB(const TPalette& pal)
  291. {
  292.   if (Mode != DIB_PAL_COLORS ||
  293.       (uint)((char*)Bits - (char*)Info) < NumClrs*sizeof(RGBQUAD))
  294.     return false;
  295.  
  296.   uint16 nEntries = pal.GetNumEntries();
  297.  
  298.   for (int c = (int)NumClrs-1; c >= 0; c--) {
  299.     uint16 i = ((uint16*)Colors)[c];
  300.     if (i >= nEntries)
  301.       i = 0;
  302.     PALETTEENTRY pe;
  303.     pal.GetPaletteEntry(i, pe);
  304.     Colors[c].rgbRed = pe.peRed;
  305.     Colors[c].rgbGreen = pe.peGreen;
  306.     Colors[c].rgbBlue = pe.peBlue;
  307.   }
  308.   Mode = DIB_RGB_COLORS;
  309.   return true;
  310. }
  311.  
  312. //
  313. // Get, set, find and map the color table entries as colors (RGBQUADs)
  314. //
  315. TColor
  316. TDib::GetColor(int entry) const
  317. {
  318.   if (entry >= 0 && entry < NumClrs)
  319.     if (Mode == DIB_RGB_COLORS)
  320.       return GetColors()[entry];
  321.  
  322.   return 0;
  323. }
  324.  
  325. //
  326. // Set the color table entry to a specified color.
  327. //
  328. void
  329. TDib::SetColor(int entry, const TColor& color)
  330. {
  331.   if (entry >= 0 && entry < NumClrs)
  332.     if (Mode == DIB_RGB_COLORS)
  333.       GetColors()[entry] = color;
  334. }
  335.  
  336. //
  337. // Return the entry in the table that matches this color.
  338. //
  339. int
  340. TDib::FindColor(const TColor& color)
  341. {
  342.   for (int entry = 0; entry < NumClrs; entry++)
  343.     if (color == GetColors()[entry])  // Small data model requires this order
  344.       return entry;
  345.   return -1;
  346. }
  347.  
  348. //
  349. // Map first or all occurances of a given palette color to a new color
  350. //
  351. int
  352. TDib::MapColor(const TColor& fromColor, const TColor& toColor, bool mapAll)
  353. {
  354.   int count = 0;
  355.   for (int entry = 0; entry < NumClrs; entry++)
  356.     if (fromColor == GetColors()[entry]) {  // Small data model requires this order
  357.       GetColors()[entry] = toColor;
  358.       count++;
  359.       if (!mapAll)
  360.         break;
  361.     }
  362.   return count;
  363. }
  364.  
  365. //
  366. // Get, set, find and map the color table entries as palette indices
  367. //
  368. uint16
  369. TDib::GetIndex(int entry) const
  370. {
  371.   if (entry >= 0 && entry < NumClrs)
  372.     if (Mode == DIB_PAL_COLORS)
  373.       return ((uint16*)GetColors())[entry];
  374.  
  375.   return 0;
  376. }
  377.  
  378. //
  379. // Set the entry in the table to the palette index.
  380. //
  381. void
  382. TDib::SetIndex(int entry, uint16 index)
  383. {
  384.   if (entry >= 0 && entry < NumClrs)
  385.     if (Mode == DIB_PAL_COLORS)
  386.       ((uint16*)GetColors())[entry] = index;
  387. }
  388.  
  389. //
  390. // Find the table entry that matches this palette index.
  391. //
  392. int
  393. TDib::FindIndex(uint16 index)
  394. {
  395.   for (int entry = 0; entry < NumClrs; entry++)
  396.     if (GetIndices()[entry] == index)
  397.       return entry;
  398.   return -1;
  399. }
  400.  
  401. //
  402. // Map first or all occurances of a given palette index to a new index
  403. //
  404. int
  405. TDib::MapIndex(uint16 fromIndex, uint16 toIndex, bool doAll)
  406. {
  407.   int count = 0;
  408.   for (int entry = 0; entry < NumClrs; entry++)
  409.     if (GetIndices()[entry] == fromIndex) {
  410.       GetIndices()[entry] = toIndex;
  411.       count++;
  412.       if (!doAll)
  413.         break;
  414.     }
  415.   return count;
  416. }
  417.  
  418. //
  419. // Use MapColor to map selected standard UI colors in this DIB to their
  420. // current system values. Also can map a background color. Used to update a
  421. // UI DIB to current colors before rendering.
  422. //
  423. //   LtGray   -> 3d Face
  424. //   Black    -> Button Text
  425. //   Gray     -> 3d Shadow
  426. //   White    -> 3d Hilight
  427. //   Magenta  -> Window Frame
  428. //   LtYellow -> bkColor
  429. //
  430. void
  431. TDib::MapUIColors(uint mapColors, const TColor* bkColor)
  432. {
  433.   if (mapColors & TDib::MapFace)
  434.     MapColor(TColor::LtGray, TColor::Sys3dFace);
  435.   if (mapColors & TDib::MapText)
  436.     MapColor(TColor::Black, TColor::SysBtnText);
  437.   if (mapColors & TDib::MapShadow)
  438.     MapColor(TColor::Gray, TColor::Sys3dShadow);
  439.   if (mapColors & TDib::MapHighlight)
  440.     MapColor(TColor::White, TColor::Sys3dHilight);
  441.   if (mapColors & TDib::MapFrame)
  442.     MapColor(TColor::LtMagenta, TColor::SysWindowFrame);
  443.   if (bkColor)
  444.     MapColor(TColor::LtYellow, *bkColor);
  445. }
  446.  
  447. //
  448. // Move this dib to the clipboard. Ownership of the DIB handle is passed to the
  449. // clipboard.
  450. //
  451. void
  452. TDib::ToClipboard(TClipboard& clipboard)
  453. {
  454.   if (Handle) {
  455.     if (IsResHandle) {
  456. #if defined(BI_PLAT_WIN16)
  457.       ::UnlockResource(Handle);
  458. #endif
  459.     }
  460.     else {
  461.       ::GlobalUnlock(Handle);
  462.     }
  463.     clipboard.SetClipboardData(CF_DIB, Handle);
  464.     ShouldDelete = false;
  465.     Info = 0;
  466.     Bits = 0;
  467.     Handle = 0;
  468.   }
  469. }
  470.  
  471. #endif
  472. #if !defined(SECTION) || SECTION == 2  // Constructing & reading .BMP files
  473.  
  474. //
  475. // Construct a TDib given a .BMP file name
  476. //
  477. TDib::TDib(const char* name)
  478. {
  479.   if (!ReadFile(name))
  480.     TXGdi::Raise(IDS_GDIFILEREADFAIL);
  481. }
  482.  
  483. //
  484. // Create a dib from the file.
  485. //
  486. TDib::TDib(TFile& file, bool readFileHeader)
  487. {
  488.   if (!Read(file, readFileHeader))
  489.     TXGdi::Raise(IDS_GDIFILEREADFAIL);
  490. }
  491.  
  492. #if !defined(BI_DATA_NEAR)
  493. //
  494. // Create a dib from the file stream.
  495. //
  496. TDib::TDib(istream& is, bool readFileHeader)
  497. {
  498.   if (!Read(is, readFileHeader))
  499.     TXGdi::Raise(IDS_GDIFILEREADFAIL);
  500. }
  501. #endif
  502.  
  503. //
  504. // Construct an empty Dib for use by derived classes
  505. //
  506. TDib::TDib()
  507. :
  508.   Info(0), Mask(0), Colors(0), Bits(0),
  509.   NumClrs(0),
  510.   IsResHandle(false)
  511. {
  512.   // Handle must be set by derived class
  513.   // InfoFromHandle() or equivalent must then be called
  514. }
  515.  
  516. //
  517. // Test if the passed file is a Windows 3.x (or PM 1.x) DIB and if so read it.
  518. // Return true iff Dib was read OK
  519. //
  520. bool
  521. TDib::ReadFile(const char* name)
  522. {
  523.   TFile file(name, TFile::ReadOnly);
  524.   if (!file.IsOpen()) {
  525.     TRACEX(OwlGDI, 0, "Cannot open bitmap file '" << name << "' to read");
  526.     return false;
  527.   }
  528.  
  529.   // Read the bitmap in, file header & all
  530.   //
  531.   bool ok = Read(file, true);
  532.  
  533.   file.Close();
  534.   return ok;
  535. }
  536.  
  537. //
  538. // Read a Windows 3.x or PM 1.x device independent bitmap from a TFile
  539. // Return true iff Dib was read OK
  540. //
  541. bool
  542. TDib::Read(TFile& file, bool readFileHeader)
  543. {
  544.   TFileIO in(file);
  545.   return Read(in, readFileHeader);
  546. }
  547.  
  548. //
  549. // The ios version of the DIB read requires large data model since the buffers
  550. // are quite large.
  551. //
  552. #if !defined(BI_DATA_NEAR)
  553.  
  554. #if defined(BI_PLAT_WIN16)
  555. //
  556. // Huge (more than 64k) buffer read helper for 16 bit
  557. //
  558. static bool
  559. hugeRead(istream& is, char huge* p, long len)
  560. {
  561.   const int PtrIncSize = 0x4000;
  562.  
  563.   long bytesLeft = len;
  564.   int  passBytes = 0;
  565.  
  566.   // Bring pointer offset to right multiple
  567.   //
  568.   if (OFFSETOF(p) != 0  && bytesLeft > 0) {
  569.     passBytes = (int)min(long(PtrIncSize - (OFFSETOF(p) % PtrIncSize)),
  570.                          bytesLeft);
  571.     if (!is.read((char far*)p, passBytes))
  572.       return false;
  573.     p += passBytes;
  574.     bytesLeft -= passBytes;
  575.   }
  576.  
  577.   // Cycle through a chunk at a time
  578.   //
  579.   while (bytesLeft >  0) {
  580.     passBytes = (int)min(long(PtrIncSize), bytesLeft);
  581.     if (!is.read((char far*)p, passBytes))
  582.       return false;
  583.     p += passBytes;
  584.     bytesLeft -= passBytes;
  585.   }
  586.   return true;
  587. }
  588. #endif  // BI_PLAT_WIN16
  589.  
  590. //
  591. //
  592. //
  593. class TStreamIn : public TDib::IFileIn {
  594.   public:
  595.     TStreamIn(istream& is) : Is(is) {}
  596.  
  597. #if defined(BI_PLAT_WIN16)
  598.     virtual bool Read(void huge* buffer, long size)
  599.                  {
  600.                    return hugeRead(Is, (char huge*)buffer, size);
  601.                  }
  602. #else
  603.     virtual bool Read(void huge* buffer, long size)
  604.                  {
  605.                    return Is.read((char*)buffer, size).good();
  606.                  }
  607. #endif
  608.     virtual void Skip(long size)
  609.                  {
  610.                    Is.seekg(size, ios::cur);
  611.                  }
  612.  
  613.   private:
  614.     istream& Is;
  615. };
  616.  
  617. //
  618. //
  619. // Read a Windows 3.0 or PM 1.X device independent bitmap from an istream
  620. // Return true iff DIB was read OK
  621. //
  622. // Read a Windows 3.0 or PM 1.X device independent bitmap. (.BMP)
  623. //  Check header, read Info, palette and bitmap.  PM DIBs can be converted to
  624. //  Win 3.x DIBs on the fly.
  625. // Return true iff DIB was read OK
  626. //
  627. bool
  628. TDib::Read(istream& is, bool readFileHeader)
  629. {
  630.   TStreamIn in(is);
  631.   return Read(in, readFileHeader);
  632. }
  633. #endif  // if !defined(BI_DATA_NEAR)
  634.  
  635. //
  636. // Read a Windows 3.0 or PM 1.X device independent bitmap. (.BMP) from an
  637. // implementor of TDib's IFileIn interface
  638. //
  639. // Check header, read Info, palette and bitmap.  PM Dibs are converted to
  640. // Windows 3.x Dibs on the fly.
  641. //
  642. // Return true iff Dib was read OK
  643. //
  644. bool
  645. TDib::Read(IFileIn& in, bool readFileHeader)
  646. {
  647.   long offBits = 0;
  648.  
  649.   // Read file header and verify the signature. Grab bfOffBits if it is != 0
  650.   // We ignore all other information in the file header since some applications
  651.   // do not put correct information in the fields...
  652.   //
  653.   if (readFileHeader) {
  654.     BITMAPFILEHEADER bmf;
  655.     if (!in.Read(&bmf, sizeof bmf) || bmf.bfType != 'BM') {
  656.       TRACEX(OwlGDI, 0, "Not a Windows 3.x or PM 1.x bitmap file");
  657.       return false;
  658.     }
  659.     if (bmf.bfOffBits)
  660.       offBits = bmf.bfOffBits - sizeof(BITMAPFILEHEADER);
  661.   }
  662.  
  663.   // Read bitmap header size & check it. It must be one of the two known header
  664.   // sizes.
  665.   // Will add BITMAPV4HEADER support when available
  666.   //
  667.   uint32 headerSize;
  668.   if (!in.Read(&headerSize, sizeof headerSize)
  669.       || headerSize != sizeof(BITMAPCOREHEADER)
  670.       && headerSize != sizeof(BITMAPINFOHEADER)
  671.      ) {
  672.     TRACEX(OwlGDI, 0, "Not a Windows 3.x or PM 1.x bitmap file");
  673.     return false;
  674.   }
  675.  
  676.   // Prepare to build or read a header that is an Info (Windows) type
  677.   //
  678.   BITMAPINFOHEADER infoHeader;
  679.   infoHeader.biSize = sizeof(BITMAPINFOHEADER);
  680.  
  681.   // If this is a PM 1.x DIB, read the core header & copy over to the Info header
  682.   //
  683.   bool   isCore = headerSize == sizeof(BITMAPCOREHEADER);
  684.   if (isCore) {
  685.     // Read in the rest of the core header, aborting if it is truncated
  686.     //
  687.     BITMAPCOREHEADER coreHeader;
  688.     if (!in.Read(&coreHeader.bcWidth, (int)headerSize-sizeof(uint32))) {
  689.       TRACEX(OwlGDI, 0, "Invalid PM 1.x DIB Header");
  690.       return false;
  691.     }
  692.  
  693.     // Copy core fields over to info fields, filling in the missing pieces
  694.     //
  695.     infoHeader.biWidth = coreHeader.bcWidth;
  696.     infoHeader.biHeight = coreHeader.bcHeight;
  697.     infoHeader.biPlanes = coreHeader.bcPlanes;
  698.     infoHeader.biBitCount = coreHeader.bcBitCount;
  699.     infoHeader.biCompression = BI_RGB;  // No compression
  700.     infoHeader.biSizeImage = 0;         // Calculate this below
  701.     infoHeader.biXPelsPerMeter = 0;     // Zero is OK
  702.     infoHeader.biYPelsPerMeter = 0;     // Zero is OK
  703.     infoHeader.biClrUsed = 0;           // Calculate this below
  704.     infoHeader.biClrImportant = 0;      // Zero is OK
  705.   }
  706.   // This is a Win 3.x DIB, read the info header
  707.   //
  708.   else {
  709.     // Read in the rest of the info header, aborting if it is truncated
  710.     //
  711.     if (!in.Read(&infoHeader.biWidth, (int)headerSize-sizeof(uint32))) {
  712.       TRACEX(OwlGDI, 0, "Invalid Win 3.x DIB Header");
  713.       return false;
  714.     }
  715.   }
  716.  
  717.   // Check number of planes. Windows supports only 1 plane DIBs
  718.   //
  719.   if (infoHeader.biPlanes != 1) {
  720.     TRACEX(OwlGDI, 0, "Invalid number of planes in DIB");
  721.     return false;
  722.   }
  723.  
  724.   // Fill in the default value for biClrsUsed, if not supplied, using the
  725.   // bit count. Will remain 0 for 16bpp or greater.
  726.   //
  727.   if (!infoHeader.biClrUsed)
  728.     infoHeader.biClrUsed = NColors(infoHeader.biBitCount);
  729.  
  730.   // Some applications do not fill in the biSizeImage field in the header.
  731.   // (Actually the truth is more likely that some drivers do not fill the
  732.   // field in and the apps do not compensate for these buggy drivers.)
  733.   //
  734.   // Therefore, if compression was not used, we (re)compute the size,
  735.   // but if compression is used, we have no choice but to trust the size.
  736.   //
  737.   if (infoHeader.biCompression == BI_RGB ||
  738.       infoHeader.biCompression == BI_BITFIELDS)
  739.     infoHeader.biSizeImage =
  740.         ScanBytes(infoHeader.biWidth,
  741.                   infoHeader.biBitCount) * infoHeader.biHeight;
  742.  
  743.   // Setup all members based on InfoHeader
  744.   //
  745.   InfoFromHeader(infoHeader);
  746.  
  747.   // Read color mask directly into allocated memory
  748.   //
  749.   if (Mask) {
  750.     if (!in.Read((char far*)Mask, 3*sizeof(uint32))) {
  751.       TRACEX(OwlGDI, 0, "Could not read DIB color mask");
  752.       ::GlobalUnlock(Handle);
  753.       return false;
  754.     }
  755.   }
  756.  
  757.   // Read color table directly into allocated memory
  758.   // Walk backwards & expand to RGBQUADs if it is a PM Core DIB
  759.   //
  760.   int colorRead = isCore ?          // Color table size on disk
  761.         (int)NumClrs * sizeof(RGBTRIPLE) :
  762.         (int)NumClrs * sizeof(RGBQUAD);
  763.   if (Colors) {
  764.     if (!in.Read((char far*)Colors, colorRead)) {
  765.       TRACEX(OwlGDI, 0, "Could not read DIB color table");
  766.       ::GlobalUnlock(Handle);
  767.       return false;
  768.     }
  769.     if (isCore) {
  770.       for (int i = int(NumClrs-1); i >= 0; i--) {
  771.         Colors[i].rgbRed = ((RGBTRIPLE*)Colors)[i].rgbtRed;
  772.         Colors[i].rgbGreen = ((RGBTRIPLE*)Colors)[i].rgbtGreen;
  773.         Colors[i].rgbBlue = ((RGBTRIPLE*)Colors)[i].rgbtBlue;
  774.         Colors[i].rgbReserved = 0;
  775.       }
  776.     }
  777.   }
  778.  
  779.   // Locate & Read Bits, skipping Pad if any.
  780.   // Ignore offBits if it is zero, or if less than the current position--it's
  781.   // probably bad
  782.   //
  783.   if (offBits && offBits - (long)(headerSize+colorRead) > 0)
  784.     in.Skip(offBits - (headerSize+colorRead));
  785.   if (!in.Read(Bits, infoHeader.biSizeImage)) {
  786.     TRACEX(OwlGDI, 0, "Could not read DIB bits");
  787.     return false;
  788.   }
  789.  
  790.   return true;
  791. }
  792.  
  793. #endif
  794. #if !defined(SECTION) || SECTION == 3 // constructing & reading DIB resources
  795.  
  796. //
  797. // Construct a TDib given a module instance and a resource name or int Id
  798. //
  799. TDib::TDib(HINSTANCE instance, TResId resId)
  800. :
  801.   Info(0), Mask(0), Colors(0), Bits(0),
  802.   NumClrs(0),
  803.   IsResHandle(false)
  804. {
  805.   if (!LoadResource(instance, resId))
  806.     TXGdi::Raise(IDS_GDIRESLOADFAIL);
  807. }
  808.  
  809. //
  810. // Load a dib resource into an empty dib.
  811. //
  812. bool
  813. TDib::LoadResource(HINSTANCE instance, TResId resId)
  814. {
  815.   PRECONDITION(!Handle);
  816.  
  817.   // First, load the resource into a global memory block.
  818.   //
  819.   HRSRC  resHandle = ::FindResource(instance, resId, RT_BITMAP);
  820.   Handle = resHandle ? ::LoadResource(instance, resHandle) : 0;
  821.   if (!Handle) {
  822.     TRACEX(OwlGDI, 0, "Cannot access bitmap resource");
  823.     return false;
  824.   }
  825.   IsResHandle = true;
  826.  
  827.   // Then update our pointers & other info.
  828.   //
  829.   InfoFromHandle();
  830.  
  831.   // Under Win32, resources are read-only. So, to allow for later modification
  832.   // of the Dib, a copy must be made.
  833.   //
  834.   // Could postpone this until dib needed to be written on...
  835.   //
  836. #if defined(BI_PLAT_WIN32)
  837.   ResToMemHandle();
  838. #endif
  839.  
  840.   return true;
  841. }
  842.  
  843. #endif
  844. #if !defined(SECTION) || SECTION == 4  // Writing .BMP files
  845.  
  846. //
  847. // Write the DIB into an external file.
  848. //
  849. bool
  850. TDib::WriteFile(const char* name)
  851. {
  852.   TFile file(name, TFile::WriteOnly|TFile::Create|TFile::DenyRdWr, TFile::PermRdWr);
  853.  
  854.   if (!file.IsOpen()) {
  855.     TRACEX(OwlGDI, 0, "Cannot open bitmap file '" << name << "' to write");
  856.     return false;
  857.   }
  858.  
  859.   bool ok = Write(file, true);
  860.  
  861.   file.Close();
  862.   if (!ok) {
  863.     TRACEX(OwlGDI, 0, "Disk error writing file '" << name << "'");
  864.     return false;
  865.   }
  866.   return true;
  867. }
  868.  
  869. //
  870. // Write the DIB into a file.
  871. //
  872. bool
  873. TDib::Write(TFile& file, bool writeFileHeader)
  874. {
  875.   TFileIO out(file);
  876.   return Write(out, writeFileHeader);
  877. }
  878.  
  879. //
  880. // The ios version of the DIB read requires large data model since the buffers
  881. // are quite large.
  882. //
  883. #if !defined(BI_DATA_NEAR)
  884.  
  885. #if defined(BI_PLAT_WIN16)
  886. //
  887. // Huge (more than 64k) buffer write helper for 16 bit
  888. //
  889. static bool
  890. hugeWrite(ostream& os, char huge* p, long len)
  891. {
  892.   const int PtrIncSize = 0x4000;
  893.  
  894.   long bytesLeft = len;
  895.   int  passBytes = 0;
  896.  
  897.   // Bring pointer offset to proper multiple
  898.   //
  899.   if (OFFSETOF(p) != 0  && bytesLeft > 0) {
  900.     passBytes = (int)min(long(PtrIncSize - (OFFSETOF(p) % PtrIncSize)),
  901.                          bytesLeft);
  902.     if (!os.write((char far*)p, passBytes))
  903.       return false;
  904.     p += passBytes;
  905.     bytesLeft -= passBytes;
  906.   }
  907.  
  908.   // Cycle through a chunk at a time
  909.   //
  910.   while (bytesLeft >  0) {
  911.     passBytes = (int)min(long(PtrIncSize), bytesLeft);
  912.     if (!os.write((char far*)p, passBytes))
  913.       return false;
  914.     p += passBytes;
  915.     bytesLeft -= passBytes;
  916.   }
  917.   return true;
  918. }
  919. #endif  //  BI_PLAT_WIN16
  920.  
  921. //
  922. //
  923. //
  924. class TStreamOut : public TDib::IFileOut {
  925.   public:
  926.     TStreamOut(ostream& os) : Os(os) {}
  927.  
  928. #if defined(BI_PLAT_WIN16)
  929.     virtual bool Write(void huge* buffer, long size)
  930.                  {
  931.                    return hugeWrite(Os, (char huge*)buffer, size);
  932.                  }
  933. #else
  934.     virtual bool Write(void huge* buffer, long size)
  935.                  {
  936.                    return Os.write((char*)buffer, size).good();
  937.                  }
  938. #endif
  939.   private:
  940.     ostream& Os;
  941. };
  942.  
  943. //
  944. // Write the DIB into a file stream.
  945. //
  946. bool
  947. TDib::Write(ostream& os, bool writeFileHeader)
  948. {
  949.   TStreamOut out(os);
  950.   return Write(out, writeFileHeader);
  951. }
  952. #endif  // !defined(BI_DATA_NEAR)
  953.  
  954. //
  955. // Write the DIB into a file stream.
  956. //
  957. bool
  958. TDib::Write(IFileOut& out, bool writeFileHeader)
  959. {
  960.   long size = ::GlobalSize(Handle);
  961.  
  962.   // Write file header
  963.   //
  964.   if (writeFileHeader) {
  965.     BITMAPFILEHEADER bmf;
  966.     bmf.bfType = 'BM';
  967.     bmf.bfSize = sizeof(bmf) + size;
  968.     bmf.bfReserved1 = 0;
  969.     bmf.bfReserved2 = 0;
  970.     bmf.bfOffBits = sizeof bmf + (char far*)Bits - (char far*)Info;
  971.     if (!out.Write(&bmf, sizeof bmf))
  972.       return false;
  973.   }
  974.  
  975.   // Write rest of dib, including dib header, color table & bits
  976.   //
  977.   if (!out.Write(Info, size)) //(void huge*)Info
  978.     return false;
  979.  
  980.   return true;
  981. }
  982.  
  983. #endif
  984. #if !defined(SECTION) || SECTION == 5
  985.  
  986. //
  987. // Construct a Dib given dimensions and color depth
  988. //
  989. TDib::TDib(int width, int height, uint32 nColors, uint16 mode)
  990. {
  991.   PRECONDITION(width && height && nColors);
  992.  
  993.   BITMAPINFOHEADER      infoHeader;
  994.   infoHeader.biSize       = sizeof(BITMAPINFOHEADER);
  995.   infoHeader.biWidth      = width;
  996.   infoHeader.biHeight     = height;
  997.   infoHeader.biPlanes     = 1;
  998.   infoHeader.biBitCount   = NBits(nColors);
  999.   infoHeader.biCompression   = BI_RGB;
  1000.   uint32 bytes = ScanBytes(width, infoHeader.biBitCount);
  1001.   infoHeader.biSizeImage = bytes * height;
  1002.   infoHeader.biXPelsPerMeter = 0;
  1003.   infoHeader.biYPelsPerMeter = 0;
  1004.   infoHeader.biClrUsed       = nColors;
  1005.   infoHeader.biClrImportant  = 0;
  1006.  
  1007.   // Setup all members based on infoHeader
  1008.   //
  1009.   InfoFromHeader(infoHeader);
  1010.  
  1011.   // Initialize the color table--either Palette or RGB
  1012.   //
  1013.   Mode = mode;
  1014.   if (Mode == DIB_PAL_COLORS) {
  1015.     // Generate a 1:1 palette relative color table- it can later be translated
  1016.     // to RGB given a palette.
  1017.     //
  1018.     for (uint16 i = 0; i < nColors; i++)
  1019.       ((uint16*)Colors)[i] = i;
  1020.   }
  1021.   else {
  1022.     // Get the system palette and convert to RGB quad format.
  1023.     //
  1024.     TScreenDC dc;
  1025.     ::GetSystemPaletteEntries(dc, 0, nColors, (LPPALETTEENTRY)Colors);
  1026.     for (uint32 i = 0; i < nColors; i++) {
  1027.       Swap(Colors[i].rgbRed, Colors[i].rgbBlue);
  1028.       Colors[i].rgbReserved = 0;
  1029.     }
  1030.   }
  1031. }
  1032.  
  1033. #endif
  1034. #if !defined(SECTION) || SECTION == 6
  1035.  
  1036. //
  1037. // Construct a TDib given a TBitmap and a TPalette
  1038. // If no palette is give, uses the one in the focus window.
  1039. //
  1040. TDib::TDib(const TBitmap& bitmap, const TPalette* palette)
  1041. {
  1042.   BITMAP  bm;
  1043.   bitmap.GetObject(bm);
  1044.  
  1045.   BITMAPINFOHEADER  infoHeader;
  1046.   infoHeader.biSize       = sizeof(BITMAPINFOHEADER);
  1047.   infoHeader.biWidth      = bm.bmWidth;
  1048.   infoHeader.biHeight     = bm.bmHeight;
  1049.   infoHeader.biPlanes     = 1;
  1050.   uint16 nColors;
  1051.   if (palette) {
  1052.     palette->GetObject(nColors);
  1053.     infoHeader.biBitCount = NBits(nColors);
  1054.   }
  1055.   else {
  1056.     infoHeader.biBitCount = uint16(bm.bmBitsPixel*bm.bmPlanes);
  1057.     nColors = (uint16)NColors(infoHeader.biBitCount);
  1058.   }
  1059.   infoHeader.biCompression   = BI_RGB;
  1060.   infoHeader.biSizeImage     = ScanBytes(infoHeader.biWidth,
  1061.                                          infoHeader.biBitCount) * infoHeader.biHeight;
  1062.   infoHeader.biXPelsPerMeter = 0;
  1063.   infoHeader.biYPelsPerMeter = 0;
  1064.   infoHeader.biClrUsed       = nColors;
  1065.   infoHeader.biClrImportant  = 0;
  1066.  
  1067.   // Setup all members based on infoHeader
  1068.   //
  1069.   InfoFromHeader(infoHeader);
  1070.  
  1071.   // Copy pixels from given bitmap into our new empty DIB, selecting palette
  1072.   // if provided
  1073.   //
  1074.   TScreenDC dc;
  1075.   if (palette)
  1076.     dc.SelectObject(*palette, false);
  1077.   dc.GetDIBits(bitmap, StartScan(), NumScans(), Bits, *Info, Usage());
  1078. }
  1079.  
  1080. #endif
  1081. #if !defined(SECTION) || SECTION == 7
  1082.  
  1083. //
  1084. // Blast the image from a dib onto this bitmap.
  1085. //
  1086. void
  1087. TDib::MultiBlt(int type, int dstX, int dstY, TDib& srcDib,
  1088.                int srcWidth, int srcHeight, uint8 transparentColor)
  1089. {
  1090.   // this == dst
  1091.   //
  1092.   if (!srcWidth)
  1093.     srcWidth = srcDib.Width();
  1094.   if (!srcHeight)
  1095.     srcHeight = srcDib.Height();
  1096.  
  1097.   int orientation = 1;
  1098.   long dstHeight = Height();
  1099.  
  1100.   if (dstHeight < 0) {   // check for top-down DIB
  1101.     orientation = -1;
  1102.     dstHeight = -dstHeight;
  1103.   }
  1104.  
  1105.   TRect dstRect(0, 0, Width(), int(dstHeight));
  1106.   TRect srcRect(dstX, dstY, dstX + srcWidth, dstY + srcHeight);
  1107.   TRect clipped = srcRect & dstRect;
  1108.  
  1109.   // Intersect the dst rectangle with the dst DIB
  1110.   //
  1111.   if (!clipped.IsEmpty()) {
  1112.     // default delta scan to width in bytes
  1113.     //
  1114.     long dstPitch = Pitch();
  1115.  
  1116.     long dstXOrigin = clipped.left;
  1117.     long dstYOrigin = clipped.top;
  1118.  
  1119.     long dstDeltaX = dstXOrigin - dstX;
  1120.     long dstDeltaY = dstYOrigin - dstY;
  1121.  
  1122.     int width = clipped.Width();
  1123.     int height = clipped.Height();
  1124.  
  1125.     long srcXOrigin = dstDeltaX;
  1126.     long srcYOrigin = dstDeltaY;
  1127.  
  1128.     uint8 HUGE* srcSurface = (uint8 HUGE*)srcDib.GetBits();
  1129.     srcSurface += long(srcHeight - (srcYOrigin + uint32(height))) * srcDib.Pitch();
  1130.     srcSurface += long(srcXOrigin);
  1131.  
  1132.     // Now we'll calculate the starting dst pointer taking into account we may
  1133.     // have a top-down dst
  1134.     //
  1135.     uint8 HUGE* dstSurface;
  1136.     if (orientation < 0) {
  1137.       // Dst is top-down
  1138.       //
  1139.       dstPitch = -dstPitch;
  1140.       dstSurface  = (uint8 HUGE*)GetBits();
  1141.       dstSurface += long(dstYOrigin + uint32(height) - 1) * Pitch();
  1142.       dstSurface += long(dstXOrigin);
  1143. //      dstSurface = (uint8 HUGE*)GetBits()
  1144. //                   + long(dstYOrigin + uint32(height) - 1) * Pitch()
  1145. //                   + dstXOrigin;
  1146.     }
  1147.     else {
  1148.       // Dst is bottom-up
  1149.       //
  1150.       dstSurface  = (uint8 HUGE*)GetBits();
  1151.       dstSurface += long(dstHeight - (dstYOrigin + uint32(height))) * Pitch();
  1152.       dstSurface += long(dstXOrigin);
  1153.  
  1154. //      dstSurface = (uint8 HUGE*)GetBits()
  1155. //                   + long(dstHeight - (dstYOrigin + uint32(height))) * Pitch()
  1156. //                   + dstXOrigin;
  1157.     }
  1158.     if (type == 0)
  1159.       ::DibCopyBlt8(dstSurface, width, height, dstPitch,
  1160.                     srcSurface, srcDib.Pitch());
  1161.     else
  1162.       ::DibSpriteBlt8(dstSurface, width, height, dstPitch,
  1163.                       srcSurface, srcDib.Pitch(), transparentColor);
  1164.   }
  1165. }
  1166.  
  1167. //
  1168. // Modify this dib so that the pixels & color table coincide with a given
  1169. // palette
  1170. //
  1171. void
  1172. TDib::MapToPalette(const TPalette& pal)
  1173. {
  1174.   // Create a mapping from our current color table to the target palette
  1175.   //
  1176.   uint8 map[256];
  1177.   for (int i = 0; i < 256; i++)
  1178.     map[i] = (uint8)pal.GetNearestPaletteIndex(GetColor(i));
  1179.  
  1180.   // Use the map to translate all of the pixels into indexes in the target
  1181.   // palette
  1182.   //
  1183.   uint8 huge* bits = (uint8 huge*)GetBits();
  1184.   long size = Pitch() * Height();
  1185.   while (size--) {
  1186.     *bits = map[*bits];
  1187.     bits++;
  1188.   }
  1189.  
  1190.   // Now copy the target palette into our color table
  1191.   //
  1192.   PALETTEENTRY pe[256];
  1193.   pal.GetPaletteEntries(0, 256, pe);
  1194.   TRgbQuad far* colorTab = GetColors();
  1195.   for (int j = 0; j < 256; j++) {
  1196.     colorTab->rgbRed = pe[j].peRed;
  1197.     colorTab->rgbGreen = pe[j].peGreen;
  1198.     colorTab->rgbBlue = pe[j].peBlue;
  1199.     colorTab++;
  1200.   }
  1201. }
  1202.  
  1203. #endif
  1204.