//---------------------------------------------------------------------------- // ObjectWindows // (C) Copyright 1992, 1994 by Borland International, All Rights Reserved // // Implementation of TDib class //---------------------------------------------------------------------------- #pragma hdrignore SECTION #include #include #include #include #include #include // // size of scan in bytes = // Pixel Width * bits per pixel rounded up to a uint32 boundary // inline long ScanBytes(int pixWidth, int bitsPixel) { return (((long)pixWidth*bitsPixel+31) / 32) * 4; } DIAG_DECLARE_GROUP(OwlGDI); // General GDI diagnostic group #if !defined(SECTION) || SECTION == 1 // defining this will cause old core BMs to be converted to 3.0 format // undefine this to leave old core bms as is, or not worry about them at all // //#define CVT_CORE_TO_INFO // // Lock the global/res handle if needed & extract the pointers and cached info // maintained as member variables. // void TDib::InfoFromHandle() { if (!Info) if (IsResHandle) Info = (LPBITMAPINFO)::LockResource(Handle); else Info = (LPBITMAPINFO)::GlobalLock(Handle); if (Info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) IsCore = true; else if (Info->bmiHeader.biSize == sizeof(BITMAPINFOHEADER)) IsCore = false; else { ::GlobalUnlock(Handle); THROW( TXGdi(IDS_INVALIDDIBHANDLE) ); } int colorAlloc; if (IsCore) { NumClrs = NColors(((LPBITMAPCOREINFO)Info)->bmciHeader.bcBitCount); colorAlloc = (int)NumClrs * sizeof(RGBTRIPLE); W = ((LPBITMAPCOREINFO)Info)->bmciHeader.bcWidth; H = ((LPBITMAPCOREINFO)Info)->bmciHeader.bcHeight; } else { NumClrs = NColors(Info->bmiHeader.biBitCount); colorAlloc = (int)NumClrs * sizeof(RGBQUAD); W = (int)Info->bmiHeader.biWidth; H = (int)Info->bmiHeader.biHeight; } Bits = (char far*)Info + ((int)Info->bmiHeader.biSize + colorAlloc); Mode = DIB_RGB_COLORS; } // // Construct a TDib from a borrowed handle // TDib::TDib(HGLOBAL handle, TAutoDelete autoDelete) : TGdiBase(handle, autoDelete), Info(0), Bits(0), NumClrs(0), W(0), H(0), IsCore(false), IsResHandle(false) { InfoFromHandle(); } // // Construct a TDib borrowed from a clipboard handle // TDib::TDib(const TClipboard& clipboard) : TGdiBase(clipboard.GetClipboardData(CF_DIB)), Info(0), Bits(0), NumClrs(0), W(0), H(0), IsCore(false), IsResHandle(false) { InfoFromHandle(); } // // Construct a TDib that is a copy of an existing one // TDib::TDib(const TDib& dib) : Info(0), Bits(0), NumClrs(0), W(0), H(0), IsCore(false), IsResHandle(false) { PRECONDITION(dib.IsOK()); long size = ::GlobalSize(dib.Handle); Handle = ::GlobalAlloc(GMEM_MOVEABLE, size); if (!Handle) THROW( TXOutOfMemory() ); Info = (LPBITMAPINFO)::GlobalLock(Handle); hmemcpy(Info, dib.Info, size); IsCore = dib.IsCore; NumClrs = dib.NumClrs; W = dib.W; H = dib.H; Mode = dib.Mode; int colorAlloc = (int)NumClrs * (IsCore ? sizeof(RGBTRIPLE) : sizeof(RGBQUAD)); Bits = (char far*)Info + ((int)Info->bmiHeader.biSize + colorAlloc); } // // Destruct a dib by unlocking & freeing its global memory handle as required // TDib::~TDib() { if (Handle) if (IsResHandle) { #if defined(BI_PLAT_WIN16) ::UnlockResource(Handle); if (ShouldDelete) ::FreeResource(Handle); #endif } else { ::GlobalUnlock(Handle); if (ShouldDelete) ::GlobalFree(Handle); } } // // Convert an absolute RGB color table to a palette relative color table // Makes sure that color table is RGB // bool TDib::ChangeModeToPal(const TPalette& pal) { if (Mode != DIB_RGB_COLORS) return false; uint16 nEntries = pal.GetNumEntries(); for (int c = 0; c < NumClrs; c++) { uint16 index = uint16(c); for (uint16 i = 0; i < nEntries; i++) { PALETTEENTRY pe; //getting all entries one time up front would be faster pal.GetPaletteEntry(i, pe); if (pe.peRed == Info->bmiColors[c].rgbRed && pe.peGreen == Info->bmiColors[c].rgbGreen && pe.peBlue == Info->bmiColors[c].rgbBlue) { index = i; break; } } ((uint16*)Info->bmiColors)[c] = index; } Mode = DIB_PAL_COLORS; return true; } // // Convert a palette relative color table to an absolute RGB color table // Makes sure that color table is pal relative & that there is enough space // bool TDib::ChangeModeToRGB(const TPalette& pal) { if (Mode != DIB_PAL_COLORS || (int)((char*)Bits - (char*)Info) < NumClrs*sizeof(RGBQUAD)) return false; uint16 nEntries = pal.GetNumEntries(); for (int c = (int)NumClrs-1; c >= 0; c--) { uint16 i = ((uint16*)Info->bmiColors)[c]; if (i >= nEntries) i = 0; PALETTEENTRY pe; pal.GetPaletteEntry(i, pe); Info->bmiColors[c].rgbRed = pe.peRed; Info->bmiColors[c].rgbGreen = pe.peGreen; Info->bmiColors[c].rgbBlue = pe.peBlue; } Mode = DIB_RGB_COLORS; return true; } // // Get, set, find and map the color table entries as colors(RGBQUADs) // TColor TDib::GetColor(int entry) const { if (entry >= 0 && entry < NumClrs) if (Mode == DIB_RGB_COLORS) return GetColors()[entry]; return 0; } void TDib::SetColor(int entry, TColor color) { if (entry >= 0 && entry < NumClrs) if (Mode == DIB_RGB_COLORS) GetColors()[entry] = color; } int TDib::FindColor(TColor color) { for (int entry = 0; entry < NumClrs; entry++) if (color == GetColors()[entry]) return entry; return -1; } int TDib::MapColor(TColor fromColor, TColor toColor, bool doAll) { for (int entry = 0, count = 0; entry < NumClrs; entry++) if (fromColor == GetColors()[entry]) { GetColors()[entry] = toColor; count++; if (!doAll) break; } return count; } // // Get, set, find and map the color table entries as palette indices // uint16 TDib::GetIndex(int entry) const { if (entry >= 0 && entry < NumClrs) if (Mode == DIB_PAL_COLORS) return ((uint16*)GetColors())[entry]; return 0; } void TDib::SetIndex(int entry, uint16 index) { if (entry >= 0 && entry < NumClrs) if (Mode == DIB_PAL_COLORS) ((uint16*)GetColors())[entry] = index; } int TDib::FindIndex(uint16 index) { for (int entry = 0; entry < NumClrs; entry++) if (GetIndices()[entry] == index) return entry; return -1; } int TDib::MapIndex(uint16 fromIndex, uint16 toIndex, bool doAll) { for (int entry = 0, count = 0; entry < NumClrs; entry++) if (GetIndices()[entry] == fromIndex) { GetIndices()[entry] = toIndex; count++; if (!doAll) break; } return count; } void TDib::MapUIColors(uint mapColors, TColor* bkColor) { if (mapColors & TDib::MapFace) MapColor(TColor::LtGray, ::GetSysColor(COLOR_BTNFACE)); if (mapColors & TDib::MapText) MapColor(TColor::Black, ::GetSysColor(COLOR_BTNTEXT)); if (mapColors & TDib::MapShadow) MapColor(TColor::Gray, ::GetSysColor(COLOR_BTNSHADOW)); if (mapColors & TDib::MapHighlight) MapColor(TColor::White, ::GetSysColor(COLOR_BTNHIGHLIGHT)); if (mapColors & TDib::MapFrame) MapColor(TColor::LtMagenta, ::GetSysColor(COLOR_WINDOWFRAME)); if (bkColor) MapColor(TColor::LtYellow, *bkColor); } // // Move this dib to the clipboard. Ownership of the DIB is passed to the // clipboard. // void TDib::ToClipboard(TClipboard& clipboard) { if (Handle) { if (IsResHandle) { #if defined(BI_PLAT_WIN16) ::UnlockResource(Handle); #endif } else { ::GlobalUnlock(Handle); } clipboard.SetClipboardData(CF_DIB, Handle); ShouldDelete = false; Info = 0; Bits = 0; Handle = 0; } } #endif #if !defined(SECTION) || SECTION == 2 // Constructing & reading .BMP files // // Construct a Dib given a .BMP file name // TDib::TDib(const char* name) : Info(0), Bits(0), NumClrs(0), W(0), H(0), IsCore(false), IsResHandle(false) { if (!ReadFile(name)) THROW( TXGdi(IDS_GDIFILEREADFAIL) ); } #if !defined(BI_DATA_NEAR) TDib::TDib(istream& is, bool readFileHeader) : Info(0), Bits(0), NumClrs(0), W(0), H(0), IsCore(false), IsResHandle(false) { if (!Read(is, readFileHeader)) THROW( TXGdi(IDS_GDIFILEREADFAIL) ); } #endif // // Construct an empty Dib for use by derived classes // TDib::TDib() : Info(0), Bits(0), NumClrs(0), W(0), H(0), IsCore(false), IsResHandle(false) { // Handle must be set by derived class // InfoFromHandle() or equivalent must then be called } // // Test if the passed file is a Windows 3.0 (or PM 1.x) DI bitmap and if so // read it. Return false if unable to do so. // bool TDib::ReadFile(const char* name) { TFile file(name, TFile::ReadOnly); if (!file.IsOpen()) { TRACEX(OwlGDI, 0, "Cannot open bitmap file '" << name << "' to read"); return false; } // Read the bitmap in, file header & all // bool ok = Read(file, true); file.Close(); return ok; } // // Read a Windows 3.0 or PM 1.X device independent bitmap. (.BMP) // Check header, read Info, palette and bitmap. PM Dibs can be converted to // Win 3.0 Dibs on the fly. // Return true iff Dib was read OK // bool TDib::Read(TFile& file, bool readFileHeader) { long offBits = 0; // Read file header and verify the signature. Grab bfOffBits if it is != 0 // We ignore all other information in the file header since some applications // do not put correct information in the fields... // if (readFileHeader) { BITMAPFILEHEADER bmf; if (file.Read(&bmf, sizeof(bmf)) != sizeof(bmf) || bmf.bfType != 'BM') { TRACEX(OwlGDI, 0, "Not a Windows 3.x or PM 1.x bitmap file"); return false; } if (bmf.bfOffBits) offBits = bmf.bfOffBits - sizeof(BITMAPFILEHEADER); } // Read bitmap header & check size // uint32 headerSize; if (file.Read(&headerSize, sizeof(headerSize)) != sizeof(headerSize) || headerSize != sizeof(BITMAPCOREHEADER) && headerSize != sizeof(BITMAPINFOHEADER)) { TRACEX(OwlGDI, 0, "Not a Windows 3.x or PM 1.x bitmap file"); return false; } // Prepare to accept a header that is either Core(PM) or Info(Win) type // Note thet the biSize and the bcSize fields are the same(the only ones). // union { BITMAPINFOHEADER infoHeader; BITMAPCOREHEADER coreHeader; }; #if defined(CVT_CORE_TO_INFO) infoHeader.biSize = sizeof(BITMAPINFOHEADER); #else infoHeader.biSize = headerSize; #endif if (file.Read(&infoHeader.biWidth, (int)headerSize-sizeof(uint32)) != (int)headerSize-sizeof(uint32)) { TRACEX(OwlGDI, 0, "Invalid DIB Header"); return false; } // Type dependent fields kept independently // uint16 bitCount; int colorAlloc; int colorRead; uint32 bitsAlloc; // If this is a PM 1.X Dib, expand header and fill out reamining fields // for win3 dib info // Calculate size of color table in memory using RGBQUADs if converting. // For PM Dibs, this is NOT the size on disk. // if (headerSize == sizeof(BITMAPCOREHEADER)) { // check number of planes. Windows 3.x supports only 1 plane DIBs if (coreHeader.bcPlanes != 1) { TRACEX(OwlGDI, 0, "Invalid number of planes in PM 1.X bitmap"); return false; } bitCount = coreHeader.bcBitCount; NumClrs = NColors(bitCount); colorRead = (int)NumClrs * sizeof(RGBTRIPLE); // Color tables on disk W = coreHeader.bcWidth; H = coreHeader.bcHeight; #if defined(CVT_CORE_TO_INFO) IsCore = false; // Note reverse field order for copying in place infoHeader.biBitCount = coreHeader.bcBitCount; infoHeader.biPlanes = 1; infoHeader.biWidth = W; infoHeader.biHeight = H; infoHeader.biCompression = BI_RGB; infoHeader.biSizeImage = 0; // calculate this below infoHeader.biXPelsPerMeter = 0; infoHeader.biYPelsPerMeter = 0; infoHeader.biClrUsed = NumClrs; infoHeader.biClrImportant = 0; colorAlloc = NumClrs * sizeof(RGBQUAD); // size of color tables in mem #else IsCore = true; colorAlloc = colorRead; #endif bitsAlloc = 0; // Calculate below } else { // check number of planes. Windows 3.x supports only 1 plane DIBs if (infoHeader.biPlanes != 1) { TRACEX(OwlGDI, 0, "Invalid number of planes in Win 3.X bitmap"); return false; } IsCore = false; bitCount = infoHeader.biBitCount; if (!infoHeader.biClrUsed) infoHeader.biClrUsed = NColors(bitCount); NumClrs = (int)infoHeader.biClrUsed; colorAlloc = (int)NumClrs * sizeof(RGBQUAD); // size of color tables colorRead = colorAlloc; W = (int)infoHeader.biWidth; H = (int)infoHeader.biHeight; bitsAlloc = infoHeader.biSizeImage; } // Some applications do not fill in the SizeImage field in the header. // (Actually the truth is more likely that some drivers do not fill the // field in and the apps do not compensate for these buggy drivers.) // Or it is a PM 1.X Dib. // Therefore, if compression was not used, we will(re)compute the size, // but if compression is used, we have no choice but to trust the size. // if (IsCore || infoHeader.biCompression == BI_RGB) { bitsAlloc = ScanBytes(W, bitCount) * H; if (!IsCore) infoHeader.biSizeImage = bitsAlloc; } Handle = ::GlobalAlloc(GMEM_MOVEABLE, infoHeader.biSize + colorAlloc + bitsAlloc); if (!Handle) THROW( TXOutOfMemory() ); Info = (LPBITMAPINFO)::GlobalLock(Handle); Info->bmiHeader = infoHeader; // Read color table. Expand to RGBQUADs if it is a PM Dib & we are converting // if (colorAlloc) { if (file.Read((char far*)Info+(int)infoHeader.biSize, colorRead) != colorRead) { TRACEX(OwlGDI, 0, "Could not read color table"); ::GlobalUnlock(Handle); return false; } #if defined(CVT_CORE_TO_INFO) if (IsCore) { for (int i = NumClrs-1; i >= 0; i--) { Info->bmiColors[i].rgbRed = ((RGBTRIPLE*)Info->bmiColors)[i].rgbtRed; Info->bmiColors[i].rgbGreen = ((RGBTRIPLE*)Info->bmiColors)[i].rgbtGreen; Info->bmiColors[i].rgbBlue = ((RGBTRIPLE*)Info->bmiColors)[i].rgbtBlue; Info->bmiColors[i].rgbReserved = 0; } } #endif } Mode = DIB_RGB_COLORS; // Locate & Read Bits, skipping Pad if any. Ignore offBits if it is zero. // Ignore offBits if less than the current position (it's probably bad) // Bits = (char far*)Info + ((int)infoHeader.biSize + colorAlloc); if (offBits && offBits - (long)(headerSize+colorRead) > 0) file.Seek(offBits - (headerSize+colorRead), TFile::cur); if (file.Read(Bits, bitsAlloc) != bitsAlloc) { TRACEX(OwlGDI, 0, "Could not read DIB bits"); return false; } return true; } #if !defined(BI_DATA_NEAR) #if defined(BI_PLAT_WIN16) static bool bigRead(istream& is, char HUGE* p, long len) { const int PtrIncSize = 0x4000; long bytesLeft = len; int passBytes = 0; // Bring pointer offset to right multiple // if (OFFSETOF(p) != 0 && bytesLeft > 0) { passBytes = (int)min(long(PtrIncSize - (OFFSETOF(p) % PtrIncSize)), bytesLeft); if (!is.read((char*)p, passBytes)) return false; p += passBytes; bytesLeft -= passBytes; } // Cycle through a chunk at a time // while (bytesLeft > 0) { passBytes = (int)min(long(PtrIncSize), bytesLeft); if (!is.read((char*)p, passBytes)) return false; p += passBytes; bytesLeft -= passBytes; } return true; } #endif // BI_PLAT_WIN16 // // Read a Windows 3.0 or PM 1.X device independent bitmap. (.BMP) // Check header, read Info, palette and bitmap. PM Dibs can be converted to // Win 3.0 Dibs on the fly. // Return true iff Dib was read OK // bool TDib::Read(istream& is, bool readFileHeader) { long offBits = 0; // Read file header and verify the signature. Grab bfOffBits if it is != 0 // We ignore all other information in the file header since some applications // do not put correct information in the fields... // if (readFileHeader) { BITMAPFILEHEADER bmf; if (!is.read((char*)&bmf, sizeof(bmf)) || bmf.bfType != 'BM') { TRACEX(OwlGDI, 0, "Not a Windows 3.x or PM 1.x bitmap file"); return false; } if (bmf.bfOffBits) offBits = bmf.bfOffBits - sizeof(BITMAPFILEHEADER); } uint32 headerSize; if (!is.read((char*)&headerSize, sizeof(headerSize)) || headerSize != sizeof(BITMAPCOREHEADER) && headerSize != sizeof(BITMAPINFOHEADER)) { TRACEX(OwlGDI, 0, "Not a Windows 3.x or PM 1.x bitmap file"); return false; } // Prepare to accept a header that is either Core(PM) or Info(Win) type // Note thet the biSize and the bcSize fields are the same(the only ones). // union { BITMAPINFOHEADER infoHeader; BITMAPCOREHEADER coreHeader; }; #if defined(CVT_CORE_TO_INFO) infoHeader.biSize = sizeof(BITMAPINFOHEADER); #else infoHeader.biSize = headerSize; #endif if (!is.read((char*)&infoHeader.biWidth, (int)headerSize-sizeof(uint32))) { TRACEX(OwlGDI, 0, "Invalid DIB Header"); return false; } // Type dependent fields kept independently // uint16 bitCount; int colorAlloc; int colorRead; uint32 bitsAlloc; // If this is a PM 1.X Dib, expand header and fill out reamining fields // for win3 dib info // Calculate size of color table in memory using RGBQUADs if converting. // For PM Dibs, this is NOT the size on disk. // if (headerSize == sizeof(BITMAPCOREHEADER)) { // check number of planes. Windows 3.x supports only 1 plane DIBs if (coreHeader.bcPlanes != 1) { TRACEX(OwlGDI, 0, "Invalid number of planes in PM 1.X bitmap"); return false; } bitCount = coreHeader.bcBitCount; NumClrs = NColors(bitCount); colorRead = (int)NumClrs * sizeof(RGBTRIPLE); // Color tables on disk W = coreHeader.bcWidth; H = coreHeader.bcHeight; #if defined(CVT_CORE_TO_INFO) IsCore = false; // Note reverse field order for copying in place infoHeader.biBitCount = coreHeader.bcBitCount; infoHeader.biPlanes = 1; infoHeader.biWidth = W; infoHeader.biHeight = H; infoHeader.biCompression = BI_RGB; infoHeader.biSizeImage = 0; // calculate this below infoHeader.biXPelsPerMeter = 0; infoHeader.biYPelsPerMeter = 0; infoHeader.biClrUsed = NumClrs; infoHeader.biClrImportant = 0; colorAlloc = NumClrs * sizeof(RGBQUAD); // size of color tables in mem #else IsCore = true; colorAlloc = colorRead; #endif bitsAlloc = 0; // Calculate below } else { // check number of planes. Windows 3.x supports only 1 plane DIBs if (infoHeader.biPlanes != 1) { TRACEX(OwlGDI, 0, "Invalid number of planes in Win 3.X bitmap"); return false; } IsCore = false; bitCount = infoHeader.biBitCount; if (!infoHeader.biClrUsed) infoHeader.biClrUsed = NColors(bitCount); NumClrs = (int)infoHeader.biClrUsed; colorAlloc = (int)NumClrs * sizeof(RGBQUAD); // size of color tables colorRead = colorAlloc; W = (int)infoHeader.biWidth; H = (int)infoHeader.biHeight; bitsAlloc = infoHeader.biSizeImage; } // Some applications do not fill in the SizeImage field in the header. // (Actually the truth is more likely that some drivers do not fill the // field in and the apps do not compensate for these buggy drivers.) // Or it is a PM 1.X Dib. // Therefore, if compression was not used, we will(re)compute the size, // but if compression is used, we have no choice but to trust the size. // if (IsCore || infoHeader.biCompression == BI_RGB) { bitsAlloc = ScanBytes(W, bitCount) * H; if (!IsCore) infoHeader.biSizeImage = bitsAlloc; } Handle = ::GlobalAlloc(GMEM_MOVEABLE, infoHeader.biSize + colorAlloc + bitsAlloc); if (!Handle) THROW( TXOutOfMemory() ); Info = (LPBITMAPINFO)::GlobalLock(Handle); Info->bmiHeader = infoHeader; // Read color table. Expand to RGBQUADs if it is a PM Dib & we are converting // if (colorAlloc) { if (!is.read((char*)Info+(int)infoHeader.biSize, colorRead)) { TRACEX(OwlGDI, 0, "Could not read color table"); ::GlobalUnlock(Handle); return false; } #if defined(CVT_CORE_TO_INFO) if (IsCore) { for (int i = NumClrs-1; i >= 0; i--) { Info->bmiColors[i].rgbRed = ((RGBTRIPLE*)Info->bmiColors)[i].rgbtRed; Info->bmiColors[i].rgbGreen = ((RGBTRIPLE*)Info->bmiColors)[i].rgbtGreen; Info->bmiColors[i].rgbBlue = ((RGBTRIPLE*)Info->bmiColors)[i].rgbtBlue; Info->bmiColors[i].rgbReserved = 0; } } #endif } Mode = DIB_RGB_COLORS; // Locate & Read Bits, skipping Pad if any. Ignore offBits if it is zero. // Ignore offBits if less than the current position (it's probably bad) // Bits = (char far*)Info + ((int)infoHeader.biSize + colorAlloc); if (offBits && offBits - (long)(headerSize+colorRead) > 0) is.seekg(offBits - (headerSize+colorRead), ios::cur); #if defined(BI_PLAT_WIN16) if (!bigRead(is, (char*)Bits, bitsAlloc)) { TRACEX(OwlGDI, 0, "Could not read DIB bits"); return false; } #else if (!is.read((char*)Bits, bitsAlloc)) { TRACEX(OwlGDI, 0, "Could not read DIB bits"); return false; } #endif return true; } #endif // !defined(BI_DATA_NEAR) #endif #if !defined(SECTION) || SECTION == 3 // constructing & reading DIB resources // // Construct a Dib given a module instance and a resource name or int Id // TDib::TDib(HINSTANCE instance, TResId resId) : Info(0), Bits(0), NumClrs(0), W(0), H(0), IsCore(false), IsResHandle(false) { if (!LoadResource(instance, resId)) THROW( TXGdi(IDS_GDIRESLOADFAIL) ); } // // Load a dib resource into an empty dib. // bool TDib::LoadResource(HINSTANCE instance, TResId resId) { // First, load the resource into a global memory block. // HRSRC resHandle = ::FindResource(instance, resId, RT_BITMAP); if (resHandle) Handle = ::LoadResource(instance, resHandle); else Handle = 0; if (!Handle) { TRACEX(OwlGDI, 0, "Cannot access bitmap resource"); return false; } IsResHandle = true; // Then update our pointers & other info. // InfoFromHandle(); // Under Win32, resources are read-only. So, to allow for later modification // of the Dib, a copy must be made. Could postpone this until dib needed // to be written on... // #if defined(BI_PLAT_WIN32) long size = ::SizeofResource(instance, resHandle); HANDLE tempHandle = ::GlobalAlloc(GMEM_MOVEABLE, size); if (!tempHandle) THROW( TXOutOfMemory() ); void* tempInfo = ::GlobalLock(tempHandle); hmemcpy(tempInfo, Info, size); // Handle will now be a memory handle, & no longer a res handle // Update Bits pointer & other members that may have moved. // Handle = tempHandle; Info = (LPBITMAPINFO)tempInfo; IsResHandle = false; InfoFromHandle(); #endif return true; } #endif #if !defined(SECTION) || SECTION == 4 // Writing BMP files // // // bool TDib::WriteFile(const char* name) { TFile file(name, TFile::WriteOnly|TFile::Create|TFile::DenyRdWr, TFile::PermRdWr); if (!file.IsOpen()) { TRACEX(OwlGDI, 0, "Cannot open bitmap file '" << name << "' to write"); return false; } bool ok = Write(file, true); file.Close(); if (!ok) { TRACEX(OwlGDI, 0, "Disk error writing file '" << name << "'"); return false; } return true; } // // // bool TDib::Write(TFile& file, bool writeFileHeader) { long size = ::GlobalSize(Handle); // write file header // if (writeFileHeader) { BITMAPFILEHEADER bmf; bmf.bfType = 'BM'; bmf.bfSize = sizeof(bmf) + size; bmf.bfReserved1 = 0; bmf.bfReserved2 = 0; bmf.bfOffBits = sizeof(bmf) + (char far*)Bits - (char far*)Info; if (file.Write(&bmf, sizeof(bmf)) != sizeof(bmf)) return false; } // Write rest of dib, including dib header, color table & bits // if (file.Write((void HUGE*)Info, size) != size) return false; return true; } #if !defined(BI_DATA_NEAR) #if defined(BI_PLAT_WIN16) static bool bigWrite(ostream& os, char HUGE* p, long len) { const int PtrIncSize = 0x4000; long bytesLeft = len; int passBytes = 0; // Bring pointer offset to proper multiple // if (OFFSETOF(p) != 0 && bytesLeft > 0) { passBytes = (int)min(long(PtrIncSize - (OFFSETOF(p) % PtrIncSize)), bytesLeft); if (!os.write((char*)p, passBytes)) return false; p += passBytes; bytesLeft -= passBytes; } // Cycle through a chunk at a time // while (bytesLeft > 0) { passBytes = (int)min(long(PtrIncSize), bytesLeft); if (!os.write((char*)p, passBytes)) return false; p += passBytes; bytesLeft -= passBytes; } return true; } #endif // BI_PLAT_WIN16 // // // bool TDib::Write(ostream& os, bool writeFileHeader) { long size = ::GlobalSize(Handle); // write file header // if (writeFileHeader) { BITMAPFILEHEADER bmf; bmf.bfType = 'BM'; bmf.bfSize = sizeof(bmf) + size; bmf.bfReserved1 = 0; bmf.bfReserved2 = 0; bmf.bfOffBits = sizeof(bmf) + (char far*)Bits - (char far*)Info; if (!os.write((char*)&bmf, sizeof(bmf))) return false; } // Write rest of dib, including dib header, color table & bits // #if defined(BI_PLAT_WIN16) if (!bigWrite(os, (char*)Info, size)) return false; #else if (!os.write((char*)Info, size)) return false; #endif return true; } #endif // !defined(BI_DATA_NEAR) #endif #if !defined(SECTION) || SECTION == 5 // // Construct a Dib given dimensions and color depth // TDib::TDib(int width, int height, int nColors, uint16 mode) : Info(0), Bits(0), NumClrs(0), W(0), H(0), IsCore(false), IsResHandle(false) { PRECONDITION(width && height && nColors); BITMAPINFOHEADER InfoHeader; InfoHeader.biSize = sizeof(BITMAPINFOHEADER); InfoHeader.biWidth = width; InfoHeader.biHeight = height; InfoHeader.biBitCount = NBits(nColors); InfoHeader.biPlanes = 1; InfoHeader.biXPelsPerMeter = 0; InfoHeader.biYPelsPerMeter = 0; InfoHeader.biClrUsed = nColors; InfoHeader.biClrImportant = 0; // nColors ?; InfoHeader.biCompression = BI_RGB; InfoHeader.biSizeImage = ScanBytes(width, InfoHeader.biBitCount) * height; int colorAlloc = nColors * sizeof(RGBQUAD); // size of color tables long bitsAlloc = InfoHeader.biSize + colorAlloc + InfoHeader.biSizeImage; Handle = ::GlobalAlloc(GMEM_MOVEABLE, bitsAlloc); if (!Handle) THROW( TXOutOfMemory() ); Info = (LPBITMAPINFO)::GlobalLock(Handle); Info->bmiHeader = InfoHeader; InfoFromHandle(); Mode = mode; if (Mode == DIB_PAL_COLORS) { // Generate a 1:1 palette relative color table- it can later be translated // to RGB given a palette. // for (uint16 i = 0; i < nColors; i++) ((uint16*)Info->bmiColors)[i] = i; } else { // Get the system palette and convert to RGB quad format. // TScreenDC dc; ::GetSystemPaletteEntries(dc, 0, nColors, (LPPALETTEENTRY)Info->bmiColors); for (int i = 0; i < nColors; i++) { Swap(Info->bmiColors[i].rgbRed, Info->bmiColors[i].rgbBlue); Info->bmiColors[i].rgbReserved = 0; } } } #endif #if !defined(SECTION) || SECTION == 6 // // Construct a TDib given a TBitmap and a TPalette // If no palette is give, uses the one in the focus window. // TDib::TDib(const TBitmap& bitmap, const TPalette* palette) : Info(0), Bits(0), NumClrs(0), W(0), H(0), IsCore(false), IsResHandle(false) { BITMAP bm; bitmap.GetObject(bm); uint16 bitCount; BITMAPINFOHEADER infoHeader; IsCore = false; infoHeader.biSize = sizeof(BITMAPINFOHEADER); infoHeader.biWidth = W = bm.bmWidth; infoHeader.biHeight = H = bm.bmHeight; if (palette) { uint16 nColors; palette->GetObject(nColors); infoHeader.biBitCount = bitCount = NBits(nColors); } else infoHeader.biBitCount = bitCount = uint16(bm.bmBitsPixel*bm.bmPlanes); infoHeader.biPlanes = 1; infoHeader.biXPelsPerMeter = 0; infoHeader.biYPelsPerMeter = 0; infoHeader.biClrUsed = NumClrs = NColors(bitCount); infoHeader.biClrImportant = 0; infoHeader.biCompression = BI_RGB; infoHeader.biSizeImage = ScanBytes(W, bitCount) * H; int colorAlloc = (int)NumClrs * sizeof(RGBQUAD); // size of color tables long bitsAlloc = infoHeader.biSize + colorAlloc + infoHeader.biSizeImage; Handle = ::GlobalAlloc(GMEM_MOVEABLE, bitsAlloc); if (!Handle) THROW( TXOutOfMemory() ); Info = (LPBITMAPINFO)::GlobalLock(Handle); Info->bmiHeader = infoHeader; TScreenDC dc; if (palette) dc.SelectObject(*palette, false); Bits = (char far*)Info + ((int)infoHeader.biSize + colorAlloc); Mode = DIB_RGB_COLORS; dc.GetDIBits(bitmap, StartScan(), NumScans(), Bits, *Info, Usage()); } #endif