home *** CD-ROM | disk | FTP | other *** search
/ C Programming Starter Kit 2.0 / SamsPublishing-CProgrammingStarterKit-v2.0-Win31.iso / bc45 / owlsrc.pak / DIB.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-07-24  |  29.5 KB  |  1,080 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // (C) Copyright 1992, 1994 by Borland International, All Rights Reserved
  4. //
  5. //   Implementation of TDib class
  6. //----------------------------------------------------------------------------
  7. #pragma hdrignore SECTION
  8. #include <owl/owlpch.h>
  9. #include <owl/gdiobjec.h>
  10. #include <owl/metafile.h>
  11. #include <owl/clipboar.h>
  12. #include <owl/except.h>
  13. #include <classlib/file.h>
  14.  
  15. //
  16. // size of scan in bytes =
  17. //   Pixel Width * bits per pixel rounded up to a uint32 boundary
  18. //
  19. inline long ScanBytes(int pixWidth, int bitsPixel) {
  20.   return (((long)pixWidth*bitsPixel+31) / 32) * 4;
  21. }
  22.  
  23. DIAG_DECLARE_GROUP(OwlGDI);        // General GDI diagnostic group
  24.  
  25.  
  26. #if !defined(SECTION) || SECTION == 1
  27.  
  28. // defining this will cause old core BMs to be converted to 3.0 format
  29. // undefine this to leave old core bms as is, or not worry about them at all
  30. //
  31. //#define CVT_CORE_TO_INFO
  32.  
  33.  
  34. //
  35. // Lock the global/res handle if needed & extract the pointers and cached info
  36. // maintained as member variables.
  37. //
  38. void
  39. TDib::InfoFromHandle()
  40. {
  41.   if (!Info)
  42.     if (IsResHandle)
  43.       Info = (LPBITMAPINFO)::LockResource(Handle);
  44.     else
  45.       Info = (LPBITMAPINFO)::GlobalLock(Handle);
  46.   if (Info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
  47.     IsCore = true;
  48.   else if (Info->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
  49.     IsCore = false;
  50.   else {
  51.     ::GlobalUnlock(Handle);
  52.     THROW( TXGdi(IDS_INVALIDDIBHANDLE) );
  53.   }
  54.   int colorAlloc;
  55.   if (IsCore) {
  56.     NumClrs = NColors(((LPBITMAPCOREINFO)Info)->bmciHeader.bcBitCount);
  57.     colorAlloc = (int)NumClrs * sizeof(RGBTRIPLE);
  58.     W = ((LPBITMAPCOREINFO)Info)->bmciHeader.bcWidth;
  59.     H = ((LPBITMAPCOREINFO)Info)->bmciHeader.bcHeight;
  60.   }
  61.   else {
  62.     NumClrs = NColors(Info->bmiHeader.biBitCount);
  63.     colorAlloc = (int)NumClrs * sizeof(RGBQUAD);
  64.     W = (int)Info->bmiHeader.biWidth;
  65.     H = (int)Info->bmiHeader.biHeight;
  66.   }
  67.   Bits = (char far*)Info + ((int)Info->bmiHeader.biSize + colorAlloc);
  68.   Mode = DIB_RGB_COLORS;
  69. }
  70.  
  71. //
  72. // Construct a TDib from a borrowed handle
  73. //
  74. TDib::TDib(HGLOBAL handle, TAutoDelete autoDelete)
  75. :
  76.   TGdiBase(handle, autoDelete),
  77.   Info(0), Bits(0), NumClrs(0),
  78.   W(0), H(0),
  79.   IsCore(false), IsResHandle(false)
  80. {
  81.   InfoFromHandle();
  82. }
  83.  
  84. //
  85. // Construct a TDib borrowed from a clipboard handle
  86. //
  87. TDib::TDib(const TClipboard& clipboard)
  88. :
  89.   TGdiBase(clipboard.GetClipboardData(CF_DIB)),
  90.   Info(0), Bits(0), NumClrs(0),
  91.   W(0), H(0),
  92.   IsCore(false), IsResHandle(false)
  93. {
  94.   InfoFromHandle();
  95. }
  96.  
  97. //
  98. // Construct a TDib that is a copy of an existing one
  99. //
  100. TDib::TDib(const TDib& dib)
  101. :
  102.   Info(0), Bits(0), NumClrs(0),
  103.   W(0), H(0),
  104.   IsCore(false), IsResHandle(false)
  105. {
  106.   PRECONDITION(dib.IsOK());
  107.  
  108.   long size = ::GlobalSize(dib.Handle);
  109.   Handle = ::GlobalAlloc(GMEM_MOVEABLE, size);
  110.   if (!Handle)
  111.     THROW( TXOutOfMemory() );
  112.  
  113.   Info = (LPBITMAPINFO)::GlobalLock(Handle);
  114.   hmemcpy(Info, dib.Info, size);
  115.   IsCore = dib.IsCore;
  116.   NumClrs = dib.NumClrs;
  117.   W = dib.W;
  118.   H = dib.H;
  119.   Mode = dib.Mode;
  120.   int colorAlloc = (int)NumClrs *
  121.                    (IsCore ? sizeof(RGBTRIPLE) : sizeof(RGBQUAD));
  122.   Bits = (char far*)Info + ((int)Info->bmiHeader.biSize + colorAlloc);
  123. }
  124.  
  125. //
  126. // Destruct a dib by unlocking & freeing its global memory handle as required
  127. //
  128. TDib::~TDib()
  129. {
  130.   if (Handle)
  131.     if (IsResHandle) {
  132. #if defined(BI_PLAT_WIN16)
  133.       ::UnlockResource(Handle);
  134.       if (ShouldDelete)
  135.         ::FreeResource(Handle);
  136. #endif
  137.     }
  138.     else {
  139.       ::GlobalUnlock(Handle);
  140.       if (ShouldDelete)
  141.         ::GlobalFree(Handle);
  142.     }
  143. }
  144.  
  145. //
  146. // Convert an absolute RGB color table to a palette relative color table
  147. // Makes sure that color table is RGB
  148. //
  149. bool
  150. TDib::ChangeModeToPal(const TPalette& pal)
  151. {
  152.   if (Mode != DIB_RGB_COLORS)
  153.     return false;
  154.  
  155.   uint16 nEntries = pal.GetNumEntries();
  156.   
  157.   for (int c = 0; c < NumClrs; c++) {
  158.     uint16 index = uint16(c);
  159.     for (uint16 i = 0; i < nEntries; i++) {
  160.       PALETTEENTRY pe; //getting all entries one time up front would be faster
  161.       pal.GetPaletteEntry(i, pe);
  162.       if (pe.peRed == Info->bmiColors[c].rgbRed &&
  163.           pe.peGreen == Info->bmiColors[c].rgbGreen &&
  164.           pe.peBlue == Info->bmiColors[c].rgbBlue) {
  165.         index = i;
  166.         break;
  167.       }
  168.     }
  169.     ((uint16*)Info->bmiColors)[c] = index;
  170.   }
  171.   Mode = DIB_PAL_COLORS;
  172.   return true;
  173. }
  174.  
  175. //
  176. // Convert a palette relative color table to an absolute RGB color table
  177. // Makes sure that color table is pal relative & that there is enough space
  178. //
  179. bool
  180. TDib::ChangeModeToRGB(const TPalette& pal)
  181. {
  182.   if (Mode != DIB_PAL_COLORS ||
  183.       (int)((char*)Bits - (char*)Info) < NumClrs*sizeof(RGBQUAD))
  184.     return false;
  185.   
  186.   uint16 nEntries = pal.GetNumEntries();
  187.  
  188.   for (int c = (int)NumClrs-1; c >= 0; c--) {
  189.     uint16 i = ((uint16*)Info->bmiColors)[c];
  190.     if (i >= nEntries)
  191.       i = 0;
  192.     PALETTEENTRY pe;
  193.     pal.GetPaletteEntry(i, pe);
  194.     Info->bmiColors[c].rgbRed = pe.peRed;
  195.     Info->bmiColors[c].rgbGreen = pe.peGreen;
  196.     Info->bmiColors[c].rgbBlue = pe.peBlue;
  197.   }
  198.   Mode = DIB_RGB_COLORS;
  199.   return true;
  200. }
  201.  
  202. //
  203. // Get, set, find and map the color table entries as colors(RGBQUADs)
  204. //
  205. TColor
  206. TDib::GetColor(int entry) const
  207. {
  208.   if (entry >= 0 && entry < NumClrs)
  209.     if (Mode == DIB_RGB_COLORS)
  210.       return GetColors()[entry];
  211.  
  212.   return 0;
  213. }
  214.  
  215. void
  216. TDib::SetColor(int entry, TColor color)
  217. {
  218.   if (entry >= 0 && entry < NumClrs)
  219.     if (Mode == DIB_RGB_COLORS)
  220.       GetColors()[entry] = color;
  221. }
  222.  
  223. int
  224. TDib::FindColor(TColor color)
  225. {
  226.   for (int entry = 0; entry < NumClrs; entry++)
  227.     if (color == GetColors()[entry])
  228.       return entry;
  229.   return -1;
  230. }
  231.  
  232. int
  233. TDib::MapColor(TColor fromColor, TColor toColor, bool doAll)
  234. {
  235.   for (int entry = 0, count = 0; entry < NumClrs; entry++)
  236.     if (fromColor == GetColors()[entry]) {
  237.       GetColors()[entry] = toColor;
  238.       count++;
  239.       if (!doAll)
  240.         break;
  241.     }
  242.   return count;
  243. }
  244.  
  245. //
  246. // Get, set, find and map the color table entries as palette indices
  247. //
  248. uint16
  249. TDib::GetIndex(int entry) const
  250. {
  251.   if (entry >= 0 && entry < NumClrs)
  252.     if (Mode == DIB_PAL_COLORS)
  253.       return ((uint16*)GetColors())[entry];
  254.  
  255.   return 0;
  256. }
  257.  
  258. void
  259. TDib::SetIndex(int entry, uint16 index)
  260. {
  261.   if (entry >= 0 && entry < NumClrs)
  262.     if (Mode == DIB_PAL_COLORS)
  263.       ((uint16*)GetColors())[entry] = index;
  264. }
  265.  
  266. int
  267. TDib::FindIndex(uint16 index)
  268. {
  269.   for (int entry = 0; entry < NumClrs; entry++)
  270.     if (GetIndices()[entry] == index)
  271.       return entry;
  272.   return -1;
  273. }
  274.  
  275. int
  276. TDib::MapIndex(uint16 fromIndex, uint16 toIndex, bool doAll)
  277. {
  278.   for (int entry = 0, count = 0; entry < NumClrs; entry++)
  279.     if (GetIndices()[entry] == fromIndex) {
  280.       GetIndices()[entry] = toIndex;
  281.       count++;
  282.       if (!doAll)
  283.         break;
  284.     }
  285.   return count;
  286. }
  287.  
  288. void
  289. TDib::MapUIColors(uint mapColors, TColor* bkColor)
  290. {
  291.   if (mapColors & TDib::MapFace)
  292.     MapColor(TColor::LtGray, ::GetSysColor(COLOR_BTNFACE));
  293.   if (mapColors & TDib::MapText)
  294.     MapColor(TColor::Black, ::GetSysColor(COLOR_BTNTEXT));
  295.   if (mapColors & TDib::MapShadow)
  296.     MapColor(TColor::Gray, ::GetSysColor(COLOR_BTNSHADOW));
  297.   if (mapColors & TDib::MapHighlight)
  298.     MapColor(TColor::White, ::GetSysColor(COLOR_BTNHIGHLIGHT));
  299.   if (mapColors & TDib::MapFrame)
  300.     MapColor(TColor::LtMagenta, ::GetSysColor(COLOR_WINDOWFRAME));
  301.   if (bkColor)
  302.     MapColor(TColor::LtYellow, *bkColor);
  303. }
  304.  
  305. //
  306. // Move this dib to the clipboard. Ownership of the DIB is passed to the
  307. // clipboard.
  308. //
  309. void
  310. TDib::ToClipboard(TClipboard& clipboard)
  311. {
  312.   if (Handle) {
  313.     if (IsResHandle) {
  314. #if defined(BI_PLAT_WIN16)
  315.       ::UnlockResource(Handle);
  316. #endif
  317.     }
  318.     else {
  319.       ::GlobalUnlock(Handle);
  320.     }
  321.     clipboard.SetClipboardData(CF_DIB, Handle);
  322.     ShouldDelete = false;
  323.     Info = 0;
  324.     Bits = 0;
  325.     Handle = 0;
  326.   }
  327. }
  328.  
  329. #endif
  330. #if !defined(SECTION) || SECTION == 2  // Constructing & reading .BMP files
  331.  
  332. //
  333. // Construct a Dib given a .BMP file name
  334. //
  335. TDib::TDib(const char* name)
  336. :
  337.   Info(0), Bits(0), NumClrs(0),
  338.   W(0), H(0),
  339.   IsCore(false), IsResHandle(false)
  340. {
  341.   if (!ReadFile(name))
  342.     THROW( TXGdi(IDS_GDIFILEREADFAIL) );
  343. }
  344.  
  345. #if !defined(BI_DATA_NEAR)
  346.  
  347. TDib::TDib(istream& is, bool readFileHeader)
  348. :
  349.   Info(0), Bits(0), NumClrs(0),
  350.   W(0), H(0),
  351.   IsCore(false), IsResHandle(false)
  352. {
  353.   if (!Read(is, readFileHeader))
  354.     THROW( TXGdi(IDS_GDIFILEREADFAIL) );
  355. }
  356. #endif
  357.   
  358. //
  359. // Construct an empty Dib for use by derived classes
  360. //
  361. TDib::TDib()
  362. :
  363.   Info(0), Bits(0), NumClrs(0),
  364.   W(0), H(0),
  365.   IsCore(false), IsResHandle(false)
  366. {
  367.   // Handle must be set by derived class
  368.   // InfoFromHandle() or equivalent must then be called
  369. }
  370.  
  371. //
  372. // Test if the passed file is a Windows 3.0 (or PM 1.x) DI bitmap and if so
  373. // read it. Return false if unable to do so.
  374. //
  375. bool
  376. TDib::ReadFile(const char* name)
  377. {
  378.   TFile file(name, TFile::ReadOnly);
  379.   if (!file.IsOpen()) {
  380.     TRACEX(OwlGDI, 0, "Cannot open bitmap file '" << name << "' to read");
  381.     return false;
  382.   }
  383.  
  384.   // Read the bitmap in, file header & all
  385.   //
  386.   bool ok = Read(file, true);
  387.  
  388.   file.Close();
  389.   return ok;
  390. }
  391.  
  392. //
  393. // Read a Windows 3.0 or PM 1.X device independent bitmap. (.BMP)
  394. //  Check header, read Info, palette and bitmap.  PM Dibs can be converted to
  395. //  Win 3.0 Dibs on the fly.
  396. // Return true iff Dib was read OK
  397. //
  398. bool
  399. TDib::Read(TFile& file, bool readFileHeader)
  400. {
  401.   long offBits = 0;
  402.  
  403.   // Read file header and verify the signature. Grab bfOffBits if it is != 0
  404.   // We ignore all other information in the file header since some applications
  405.   // do not put correct information in the fields...
  406.   //
  407.   if (readFileHeader) {
  408.     BITMAPFILEHEADER bmf;
  409.     if (file.Read(&bmf, sizeof(bmf)) != sizeof(bmf) || bmf.bfType != 'BM') {
  410.       TRACEX(OwlGDI, 0, "Not a Windows 3.x or PM 1.x bitmap file");
  411.       return false;
  412.     }
  413.     if (bmf.bfOffBits)
  414.       offBits = bmf.bfOffBits - sizeof(BITMAPFILEHEADER);
  415.   }
  416.  
  417.   // Read bitmap header & check size
  418.   //
  419.   uint32 headerSize;
  420.   if (file.Read(&headerSize, sizeof(headerSize)) != sizeof(headerSize)
  421.       || headerSize != sizeof(BITMAPCOREHEADER)
  422.       && headerSize != sizeof(BITMAPINFOHEADER)) {
  423.     TRACEX(OwlGDI, 0, "Not a Windows 3.x or PM 1.x bitmap file");
  424.     return false;
  425.   }
  426.  
  427.   // Prepare to accept a header that is either Core(PM) or Info(Win) type
  428.   // Note thet the biSize and the bcSize fields are the same(the only ones).
  429.   //
  430.   union {
  431.     BITMAPINFOHEADER infoHeader;
  432.     BITMAPCOREHEADER coreHeader;
  433.   };
  434.   #if defined(CVT_CORE_TO_INFO)
  435.     infoHeader.biSize = sizeof(BITMAPINFOHEADER);
  436.   #else
  437.     infoHeader.biSize = headerSize;
  438.   #endif
  439.   if (file.Read(&infoHeader.biWidth, (int)headerSize-sizeof(uint32)) !=
  440.       (int)headerSize-sizeof(uint32)) {
  441.     TRACEX(OwlGDI, 0, "Invalid DIB Header");
  442.     return false;
  443.   }
  444.  
  445.   // Type dependent fields kept independently
  446.   //
  447.   uint16 bitCount;
  448.   int    colorAlloc;
  449.   int    colorRead;
  450.   uint32 bitsAlloc;
  451.  
  452.   // If this is a PM 1.X Dib, expand header and fill out reamining fields
  453.   // for win3 dib info
  454.   // Calculate size of color table in memory using RGBQUADs if converting.
  455.   // For PM Dibs, this is NOT the size on disk.
  456.   //
  457.   if (headerSize == sizeof(BITMAPCOREHEADER)) {
  458.     // check number of planes. Windows 3.x supports only 1 plane DIBs
  459.     if (coreHeader.bcPlanes != 1) {
  460.       TRACEX(OwlGDI, 0, "Invalid number of planes in PM 1.X bitmap");
  461.       return false;
  462.     }
  463.     bitCount = coreHeader.bcBitCount;
  464.     NumClrs = NColors(bitCount);
  465.     colorRead = (int)NumClrs * sizeof(RGBTRIPLE); // Color tables on disk
  466.     W = coreHeader.bcWidth;
  467.     H = coreHeader.bcHeight;
  468.     #if defined(CVT_CORE_TO_INFO)
  469.       IsCore = false;
  470.       // Note reverse field order for copying in place
  471.       infoHeader.biBitCount = coreHeader.bcBitCount;
  472.       infoHeader.biPlanes = 1;
  473.       infoHeader.biWidth = W;
  474.       infoHeader.biHeight = H;
  475.       infoHeader.biCompression = BI_RGB;
  476.       infoHeader.biSizeImage = 0; // calculate this below
  477.       infoHeader.biXPelsPerMeter = 0;
  478.       infoHeader.biYPelsPerMeter = 0;
  479.       infoHeader.biClrUsed = NumClrs;
  480.       infoHeader.biClrImportant = 0;
  481.       colorAlloc = NumClrs * sizeof(RGBQUAD); // size of color tables in mem
  482.     #else
  483.       IsCore = true;
  484.       colorAlloc = colorRead;
  485.     #endif
  486.     bitsAlloc = 0;      // Calculate below
  487.   }
  488.   else {
  489.     // check number of planes. Windows 3.x supports only 1 plane DIBs
  490.     if (infoHeader.biPlanes != 1) {
  491.       TRACEX(OwlGDI, 0, "Invalid number of planes in Win 3.X bitmap");
  492.       return false;
  493.     }
  494.     IsCore = false;
  495.     bitCount = infoHeader.biBitCount;
  496.     if (!infoHeader.biClrUsed)
  497.       infoHeader.biClrUsed = NColors(bitCount);
  498.     NumClrs = (int)infoHeader.biClrUsed;
  499.     colorAlloc = (int)NumClrs * sizeof(RGBQUAD); // size of color tables
  500.     colorRead = colorAlloc;
  501.     W = (int)infoHeader.biWidth;
  502.     H = (int)infoHeader.biHeight;
  503.     bitsAlloc = infoHeader.biSizeImage;
  504.   }
  505.  
  506.   // Some applications do not fill in the SizeImage field in the header.
  507.   // (Actually the truth is more likely that some drivers do not fill the
  508.   // field in and the apps do not compensate for these buggy drivers.)
  509.   // Or it is a PM 1.X Dib.
  510.   // Therefore, if compression was not used, we will(re)compute the size,
  511.   // but if compression is used, we have no choice but to trust the size.
  512.   //
  513.   if (IsCore || infoHeader.biCompression == BI_RGB) {
  514.     bitsAlloc = ScanBytes(W, bitCount) * H;
  515.     if (!IsCore)
  516.       infoHeader.biSizeImage = bitsAlloc;
  517.   }
  518.  
  519.   Handle = ::GlobalAlloc(GMEM_MOVEABLE, infoHeader.biSize + colorAlloc + bitsAlloc);
  520.   if (!Handle)
  521.     THROW( TXOutOfMemory() );
  522.  
  523.   Info = (LPBITMAPINFO)::GlobalLock(Handle);
  524.   Info->bmiHeader = infoHeader;
  525.  
  526.   // Read color table.  Expand to RGBQUADs if it is a PM Dib & we are converting
  527.   //
  528.   if (colorAlloc) {
  529.     if (file.Read((char far*)Info+(int)infoHeader.biSize, colorRead) != colorRead) {
  530.       TRACEX(OwlGDI, 0, "Could not read color table");
  531.       ::GlobalUnlock(Handle);
  532.       return false;
  533.     }
  534.     #if defined(CVT_CORE_TO_INFO)
  535.     if (IsCore) {
  536.       for (int i = NumClrs-1; i >= 0; i--) {
  537.         Info->bmiColors[i].rgbRed = ((RGBTRIPLE*)Info->bmiColors)[i].rgbtRed;
  538.         Info->bmiColors[i].rgbGreen = ((RGBTRIPLE*)Info->bmiColors)[i].rgbtGreen;
  539.         Info->bmiColors[i].rgbBlue = ((RGBTRIPLE*)Info->bmiColors)[i].rgbtBlue;
  540.         Info->bmiColors[i].rgbReserved = 0;
  541.       }
  542.     }
  543.     #endif
  544.   }
  545.   Mode = DIB_RGB_COLORS;
  546.  
  547.   // Locate & Read Bits, skipping Pad if any. Ignore offBits if it is zero.
  548.   // Ignore offBits if less than the current position (it's probably bad)
  549.   //
  550.   Bits = (char far*)Info + ((int)infoHeader.biSize + colorAlloc);
  551.   if (offBits && offBits - (long)(headerSize+colorRead) > 0)
  552.     file.Seek(offBits - (headerSize+colorRead), TFile::cur);
  553.   if (file.Read(Bits, bitsAlloc) != bitsAlloc) {
  554.     TRACEX(OwlGDI, 0, "Could not read DIB bits");
  555.     return false;
  556.   }
  557.   return true;
  558. }
  559.  
  560.  
  561. #if !defined(BI_DATA_NEAR)
  562.  
  563. #if defined(BI_PLAT_WIN16)  
  564.  
  565. static bool
  566. bigRead(istream& is, char HUGE* p, long len)
  567. {
  568.   const int PtrIncSize = 0x4000;
  569.  
  570.   long bytesLeft = len;
  571.   int  passBytes = 0;
  572.  
  573.   // Bring pointer offset to right multiple
  574.   //
  575.   if (OFFSETOF(p) != 0  && bytesLeft > 0) {
  576.     passBytes = (int)min(long(PtrIncSize - (OFFSETOF(p) % PtrIncSize)), 
  577.                          bytesLeft);
  578.     if (!is.read((char*)p, passBytes)) 
  579.       return false;
  580.     p += passBytes;
  581.     bytesLeft -= passBytes;
  582.   } 
  583.  
  584.   // Cycle through a chunk at a time
  585.   //
  586.   while (bytesLeft >  0) {
  587.     passBytes = (int)min(long(PtrIncSize), bytesLeft);
  588.     if (!is.read((char*)p, passBytes))
  589.       return false;
  590.     p += passBytes;
  591.     bytesLeft -= passBytes;
  592.   }
  593.   return true;
  594. }
  595.  
  596. #endif  //  BI_PLAT_WIN16   
  597.  
  598.  
  599. //
  600. // Read a Windows 3.0 or PM 1.X device independent bitmap. (.BMP)
  601. //  Check header, read Info, palette and bitmap.  PM Dibs can be converted to
  602. //  Win 3.0 Dibs on the fly.
  603. // Return true iff Dib was read OK
  604. //
  605. bool
  606. TDib::Read(istream& is, bool readFileHeader)
  607. {
  608.   long offBits = 0;
  609.  
  610.   // Read file header and verify the signature. Grab bfOffBits if it is != 0
  611.   // We ignore all other information in the file header since some applications
  612.   // do not put correct information in the fields...
  613.   //
  614.   if (readFileHeader) {
  615.     BITMAPFILEHEADER bmf;
  616.     if (!is.read((char*)&bmf, sizeof(bmf)) || bmf.bfType != 'BM') {
  617.       TRACEX(OwlGDI, 0, "Not a Windows 3.x or PM 1.x bitmap file");
  618.       return false;
  619.     }
  620.     if (bmf.bfOffBits)
  621.       offBits = bmf.bfOffBits - sizeof(BITMAPFILEHEADER);
  622.   }
  623.  
  624.   uint32 headerSize;
  625.   if (!is.read((char*)&headerSize, sizeof(headerSize))
  626.       || headerSize != sizeof(BITMAPCOREHEADER)
  627.       && headerSize != sizeof(BITMAPINFOHEADER)) {
  628.     TRACEX(OwlGDI, 0, "Not a Windows 3.x or PM 1.x bitmap file");
  629.     return false;
  630.   }
  631.  
  632.   // Prepare to accept a header that is either Core(PM) or Info(Win) type
  633.   // Note thet the biSize and the bcSize fields are the same(the only ones).
  634.   //
  635.   union {
  636.     BITMAPINFOHEADER infoHeader;
  637.     BITMAPCOREHEADER coreHeader;
  638.   };
  639.   #if defined(CVT_CORE_TO_INFO)
  640.     infoHeader.biSize = sizeof(BITMAPINFOHEADER);
  641.   #else
  642.     infoHeader.biSize = headerSize;
  643.   #endif
  644.   if (!is.read((char*)&infoHeader.biWidth, (int)headerSize-sizeof(uint32))) {
  645.     TRACEX(OwlGDI, 0, "Invalid DIB Header");
  646.     return false;
  647.   }
  648.  
  649.   // Type dependent fields kept independently
  650.   //
  651.   uint16 bitCount;
  652.   int    colorAlloc;
  653.   int    colorRead;
  654.   uint32 bitsAlloc;
  655.  
  656.   // If this is a PM 1.X Dib, expand header and fill out reamining fields
  657.   // for win3 dib info
  658.   // Calculate size of color table in memory using RGBQUADs if converting.
  659.   // For PM Dibs, this is NOT the size on disk.
  660.   //
  661.   if (headerSize == sizeof(BITMAPCOREHEADER)) {
  662.     // check number of planes. Windows 3.x supports only 1 plane DIBs
  663.     if (coreHeader.bcPlanes != 1) {
  664.       TRACEX(OwlGDI, 0, "Invalid number of planes in PM 1.X bitmap");
  665.       return false;
  666.     }
  667.     bitCount = coreHeader.bcBitCount;
  668.     NumClrs = NColors(bitCount);
  669.     colorRead = (int)NumClrs * sizeof(RGBTRIPLE); // Color tables on disk
  670.     W = coreHeader.bcWidth;
  671.     H = coreHeader.bcHeight;
  672.     #if defined(CVT_CORE_TO_INFO)
  673.       IsCore = false;
  674.       // Note reverse field order for copying in place
  675.       infoHeader.biBitCount = coreHeader.bcBitCount;
  676.       infoHeader.biPlanes = 1;
  677.       infoHeader.biWidth = W;
  678.       infoHeader.biHeight = H;
  679.       infoHeader.biCompression = BI_RGB;
  680.       infoHeader.biSizeImage = 0; // calculate this below
  681.       infoHeader.biXPelsPerMeter = 0;
  682.       infoHeader.biYPelsPerMeter = 0;
  683.       infoHeader.biClrUsed = NumClrs;
  684.       infoHeader.biClrImportant = 0;
  685.       colorAlloc = NumClrs * sizeof(RGBQUAD); // size of color tables in mem
  686.     #else
  687.       IsCore = true;
  688.       colorAlloc = colorRead;
  689.     #endif
  690.     bitsAlloc = 0;      // Calculate below
  691.   }
  692.   else {
  693.     // check number of planes. Windows 3.x supports only 1 plane DIBs
  694.     if (infoHeader.biPlanes != 1) {
  695.       TRACEX(OwlGDI, 0, "Invalid number of planes in Win 3.X bitmap");
  696.       return false;
  697.     }
  698.     IsCore = false;
  699.     bitCount = infoHeader.biBitCount;
  700.     if (!infoHeader.biClrUsed)
  701.       infoHeader.biClrUsed = NColors(bitCount);
  702.     NumClrs = (int)infoHeader.biClrUsed;
  703.     colorAlloc = (int)NumClrs * sizeof(RGBQUAD); // size of color tables
  704.     colorRead = colorAlloc;
  705.     W = (int)infoHeader.biWidth;
  706.     H = (int)infoHeader.biHeight;
  707.     bitsAlloc = infoHeader.biSizeImage;
  708.   }
  709.  
  710.   // Some applications do not fill in the SizeImage field in the header.
  711.   // (Actually the truth is more likely that some drivers do not fill the
  712.   // field in and the apps do not compensate for these buggy drivers.)
  713.   // Or it is a PM 1.X Dib.
  714.   // Therefore, if compression was not used, we will(re)compute the size,
  715.   // but if compression is used, we have no choice but to trust the size.
  716.   //
  717.   if (IsCore || infoHeader.biCompression == BI_RGB) {
  718.     bitsAlloc = ScanBytes(W, bitCount) * H;
  719.     if (!IsCore)
  720.       infoHeader.biSizeImage = bitsAlloc;
  721.   }
  722.  
  723.   Handle = ::GlobalAlloc(GMEM_MOVEABLE, infoHeader.biSize + colorAlloc + bitsAlloc);
  724.   if (!Handle)
  725.     THROW( TXOutOfMemory() );
  726.  
  727.   Info = (LPBITMAPINFO)::GlobalLock(Handle);
  728.   Info->bmiHeader = infoHeader;
  729.  
  730.   // Read color table.  Expand to RGBQUADs if it is a PM Dib & we are converting
  731.   //
  732.   if (colorAlloc) {
  733.     if (!is.read((char*)Info+(int)infoHeader.biSize, colorRead)) {
  734.       TRACEX(OwlGDI, 0, "Could not read color table");
  735.       ::GlobalUnlock(Handle);
  736.       return false;
  737.     }
  738.     #if defined(CVT_CORE_TO_INFO)
  739.     if (IsCore) {
  740.       for (int i = NumClrs-1; i >= 0; i--) {
  741.         Info->bmiColors[i].rgbRed = ((RGBTRIPLE*)Info->bmiColors)[i].rgbtRed;
  742.         Info->bmiColors[i].rgbGreen = ((RGBTRIPLE*)Info->bmiColors)[i].rgbtGreen;
  743.         Info->bmiColors[i].rgbBlue = ((RGBTRIPLE*)Info->bmiColors)[i].rgbtBlue;
  744.         Info->bmiColors[i].rgbReserved = 0;
  745.       }
  746.     }
  747.     #endif
  748.   }
  749.   Mode = DIB_RGB_COLORS;
  750.  
  751.   // Locate & Read Bits, skipping Pad if any. Ignore offBits if it is zero.
  752.   // Ignore offBits if less than the current position (it's probably bad)
  753.   //
  754.   Bits = (char far*)Info + ((int)infoHeader.biSize + colorAlloc);
  755.   if (offBits && offBits - (long)(headerSize+colorRead) > 0)
  756.     is.seekg(offBits - (headerSize+colorRead), ios::cur);
  757.  
  758. #if defined(BI_PLAT_WIN16)
  759.   if (!bigRead(is, (char*)Bits, bitsAlloc)) {
  760.     TRACEX(OwlGDI, 0, "Could not read DIB bits");
  761.     return false;
  762.   }
  763. #else
  764.   if (!is.read((char*)Bits, bitsAlloc)) {
  765.     TRACEX(OwlGDI, 0, "Could not read DIB bits");
  766.     return false;
  767.   }
  768. #endif  
  769.   return true;
  770. }
  771. #endif  // !defined(BI_DATA_NEAR)
  772.  
  773. #endif
  774. #if !defined(SECTION) || SECTION == 3 // constructing & reading DIB resources
  775.  
  776. //
  777. // Construct a Dib given a module instance and a resource name or int Id
  778. //
  779. TDib::TDib(HINSTANCE instance, TResId resId)
  780. :
  781.   Info(0), Bits(0), NumClrs(0),
  782.   W(0), H(0),
  783.   IsCore(false), IsResHandle(false)
  784. {
  785.   if (!LoadResource(instance, resId))
  786.     THROW( TXGdi(IDS_GDIRESLOADFAIL) );
  787. }
  788.  
  789. //
  790. // Load a dib resource into an empty dib.
  791. //
  792. bool
  793. TDib::LoadResource(HINSTANCE instance, TResId resId)
  794. {
  795.   // First, load the resource into a global memory block.
  796.   //
  797.   HRSRC  resHandle = ::FindResource(instance, resId, RT_BITMAP);
  798.   if (resHandle)
  799.     Handle = ::LoadResource(instance, resHandle);
  800.   else
  801.     Handle = 0;
  802.   if (!Handle) {
  803.     TRACEX(OwlGDI, 0, "Cannot access bitmap resource");
  804.     return false;
  805.   }
  806.   IsResHandle = true;
  807.  
  808.   // Then update our pointers & other info.
  809.   //
  810.   InfoFromHandle();
  811.  
  812.   // Under Win32, resources are read-only. So, to allow for later modification
  813.   // of the Dib, a copy must be made. Could postpone this until dib needed
  814.   // to be written on...
  815.   //
  816. #if defined(BI_PLAT_WIN32)
  817.   long size = ::SizeofResource(instance, resHandle);
  818.   HANDLE tempHandle = ::GlobalAlloc(GMEM_MOVEABLE, size);
  819.   if (!tempHandle)
  820.     THROW( TXOutOfMemory() );
  821.  
  822.   void* tempInfo = ::GlobalLock(tempHandle);
  823.   hmemcpy(tempInfo, Info, size);
  824.  
  825.   // Handle will now be a memory handle, & no longer a res handle
  826.   // Update Bits pointer & other members that may have moved.
  827.   //
  828.   Handle = tempHandle;
  829.   Info = (LPBITMAPINFO)tempInfo;
  830.   IsResHandle = false;
  831.   InfoFromHandle();
  832. #endif
  833.  
  834.   return true;
  835. }
  836.  
  837. #endif
  838. #if !defined(SECTION) || SECTION == 4  // Writing BMP files
  839.  
  840. //
  841. // 
  842. //
  843. bool
  844. TDib::WriteFile(const char* name)
  845. {
  846.   TFile file(name, TFile::WriteOnly|TFile::Create|TFile::DenyRdWr, TFile::PermRdWr);
  847.  
  848.   if (!file.IsOpen()) {
  849.     TRACEX(OwlGDI, 0, "Cannot open bitmap file '" << name << "' to write");
  850.     return false;
  851.   }
  852.  
  853.   bool ok = Write(file, true);
  854.  
  855.   file.Close();
  856.   if (!ok) {
  857.     TRACEX(OwlGDI, 0, "Disk error writing file '" << name << "'");
  858.     return false;
  859.   }
  860.   return true;
  861. }
  862.  
  863. //
  864. // 
  865. //
  866. bool
  867. TDib::Write(TFile& file, bool writeFileHeader)
  868. {
  869.   long size = ::GlobalSize(Handle);
  870.  
  871.   // write file header
  872.   //
  873.   if (writeFileHeader) {
  874.     BITMAPFILEHEADER bmf;
  875.     bmf.bfType = 'BM';
  876.     bmf.bfSize = sizeof(bmf) + size;
  877.     bmf.bfReserved1 = 0;
  878.     bmf.bfReserved2 = 0;
  879.     bmf.bfOffBits = sizeof(bmf) + (char far*)Bits - (char far*)Info;
  880.     if (file.Write(&bmf, sizeof(bmf)) != sizeof(bmf))
  881.       return false;
  882.   }
  883.  
  884.   // Write rest of dib, including dib header, color table & bits
  885.   //
  886.   if (file.Write((void HUGE*)Info, size) != size)
  887.     return false;
  888.  
  889.   return true;
  890. }
  891.  
  892. #if !defined(BI_DATA_NEAR)
  893.  
  894. #if defined(BI_PLAT_WIN16)
  895.  
  896. static bool
  897. bigWrite(ostream& os, char HUGE* p, long len)
  898. {
  899.   const int PtrIncSize = 0x4000;
  900.  
  901.   long bytesLeft = len;
  902.   int  passBytes = 0;
  903.  
  904.   // Bring pointer offset to proper multiple
  905.   //
  906.   if (OFFSETOF(p) != 0  && bytesLeft > 0) {
  907.     passBytes = (int)min(long(PtrIncSize - (OFFSETOF(p) % PtrIncSize)), 
  908.                          bytesLeft);
  909.     if (!os.write((char*)p, passBytes)) 
  910.       return false;
  911.     p += passBytes;
  912.     bytesLeft -= passBytes;
  913.   } 
  914.  
  915.   // Cycle through a chunk at a time
  916.   //
  917.   while (bytesLeft >  0) {
  918.     passBytes = (int)min(long(PtrIncSize), bytesLeft);
  919.     if (!os.write((char*)p, passBytes))
  920.       return false;
  921.     p += passBytes;
  922.     bytesLeft -= passBytes;
  923.   }
  924.   return true;
  925. }
  926.  
  927. #endif  //  BI_PLAT_WIN16
  928.  
  929.  
  930. //
  931. // 
  932. //
  933. bool
  934. TDib::Write(ostream& os, bool writeFileHeader)
  935. {
  936.   long size = ::GlobalSize(Handle);
  937.  
  938.   // write file header
  939.   //
  940.   if (writeFileHeader) {
  941.     BITMAPFILEHEADER bmf;
  942.     bmf.bfType = 'BM';
  943.     bmf.bfSize = sizeof(bmf) + size;
  944.     bmf.bfReserved1 = 0;
  945.     bmf.bfReserved2 = 0;
  946.     bmf.bfOffBits = sizeof(bmf) + (char far*)Bits - (char far*)Info;
  947.     if (!os.write((char*)&bmf, sizeof(bmf)))
  948.       return false;
  949.   }
  950.  
  951.   // Write rest of dib, including dib header, color table & bits
  952.   //
  953. #if defined(BI_PLAT_WIN16)
  954.   if (!bigWrite(os, (char*)Info, size))
  955.     return false;
  956. #else
  957.   if (!os.write((char*)Info, size))
  958.     return false;
  959. #endif
  960.  
  961.   return true;
  962. }
  963. #endif  // !defined(BI_DATA_NEAR)
  964.  
  965. #endif
  966. #if !defined(SECTION) || SECTION == 5
  967.  
  968. //
  969. // Construct a Dib given dimensions and color depth
  970. //
  971. TDib::TDib(int width, int height, int nColors, uint16 mode)
  972. :
  973.   Info(0), Bits(0), NumClrs(0),
  974.   W(0), H(0),
  975.   IsCore(false), IsResHandle(false)
  976. {
  977.   PRECONDITION(width && height && nColors);
  978.  
  979.   BITMAPINFOHEADER      InfoHeader;
  980.   InfoHeader.biSize       = sizeof(BITMAPINFOHEADER);
  981.   InfoHeader.biWidth      = width;
  982.   InfoHeader.biHeight     = height;
  983.   InfoHeader.biBitCount   = NBits(nColors);
  984.   InfoHeader.biPlanes     = 1;
  985.   InfoHeader.biXPelsPerMeter = 0;
  986.   InfoHeader.biYPelsPerMeter = 0;
  987.   InfoHeader.biClrUsed       = nColors;
  988.   InfoHeader.biClrImportant  = 0;   // nColors ?;
  989.   InfoHeader.biCompression   = BI_RGB;
  990.   InfoHeader.biSizeImage = ScanBytes(width, InfoHeader.biBitCount) * height;
  991.  
  992.   int  colorAlloc = nColors * sizeof(RGBQUAD); // size of color tables
  993.   long bitsAlloc = InfoHeader.biSize + colorAlloc + InfoHeader.biSizeImage;
  994.  
  995.   Handle = ::GlobalAlloc(GMEM_MOVEABLE, bitsAlloc);
  996.   if (!Handle)
  997.     THROW( TXOutOfMemory() );
  998.  
  999.   Info = (LPBITMAPINFO)::GlobalLock(Handle);
  1000.   Info->bmiHeader = InfoHeader;
  1001.   InfoFromHandle();
  1002.  
  1003.   Mode = mode;
  1004.   if (Mode == DIB_PAL_COLORS) {
  1005.     // Generate a 1:1 palette relative color table- it can later be translated
  1006.     // to RGB given a palette.
  1007.     //
  1008.     for (uint16 i = 0; i < nColors; i++)
  1009.       ((uint16*)Info->bmiColors)[i] = i;
  1010.   }
  1011.   else {
  1012.     // Get the system palette and convert to RGB quad format.
  1013.     //
  1014.     TScreenDC dc;
  1015.     ::GetSystemPaletteEntries(dc, 0, nColors, (LPPALETTEENTRY)Info->bmiColors);
  1016.     for (int i = 0; i < nColors; i++) {
  1017.       Swap(Info->bmiColors[i].rgbRed, Info->bmiColors[i].rgbBlue);
  1018.       Info->bmiColors[i].rgbReserved = 0;
  1019.     }
  1020.   }
  1021. }
  1022.  
  1023. #endif
  1024. #if !defined(SECTION) || SECTION == 6
  1025.  
  1026. //
  1027. // Construct a TDib given a TBitmap and a TPalette
  1028. // If no palette is give, uses the one in the focus window.
  1029. //
  1030. TDib::TDib(const TBitmap& bitmap, const TPalette* palette)
  1031. :
  1032.   Info(0), Bits(0), NumClrs(0),
  1033.   W(0), H(0),
  1034.   IsCore(false), IsResHandle(false)
  1035. {
  1036.   BITMAP  bm;
  1037.   bitmap.GetObject(bm);
  1038.  
  1039.   uint16            bitCount;
  1040.   BITMAPINFOHEADER  infoHeader;
  1041.  
  1042.   IsCore = false;
  1043.   infoHeader.biSize       = sizeof(BITMAPINFOHEADER);
  1044.   infoHeader.biWidth      = W = bm.bmWidth;
  1045.   infoHeader.biHeight     = H = bm.bmHeight;
  1046.   if (palette) {
  1047.     uint16 nColors;
  1048.     palette->GetObject(nColors);
  1049.     infoHeader.biBitCount    = bitCount = NBits(nColors);
  1050.   }
  1051.   else
  1052.     infoHeader.biBitCount    = bitCount = uint16(bm.bmBitsPixel*bm.bmPlanes);
  1053.   infoHeader.biPlanes        = 1;
  1054.   infoHeader.biXPelsPerMeter = 0;
  1055.   infoHeader.biYPelsPerMeter = 0;
  1056.   infoHeader.biClrUsed       = NumClrs = NColors(bitCount);
  1057.   infoHeader.biClrImportant  = 0;
  1058.   infoHeader.biCompression   = BI_RGB;
  1059.   infoHeader.biSizeImage     = ScanBytes(W, bitCount) * H;
  1060.  
  1061.   int  colorAlloc = (int)NumClrs * sizeof(RGBQUAD); // size of color tables
  1062.   long bitsAlloc = infoHeader.biSize + colorAlloc + infoHeader.biSizeImage;
  1063.  
  1064.   Handle = ::GlobalAlloc(GMEM_MOVEABLE, bitsAlloc);
  1065.   if (!Handle)
  1066.     THROW( TXOutOfMemory() );
  1067.  
  1068.   Info = (LPBITMAPINFO)::GlobalLock(Handle);
  1069.   Info->bmiHeader = infoHeader;
  1070.  
  1071.   TScreenDC dc;
  1072.   if (palette)
  1073.     dc.SelectObject(*palette, false);
  1074.   Bits = (char far*)Info + ((int)infoHeader.biSize + colorAlloc);
  1075.   Mode = DIB_RGB_COLORS;
  1076.   dc.GetDIBits(bitmap, StartScan(), NumScans(), Bits, *Info, Usage());
  1077. }
  1078.  
  1079. #endif
  1080.