//----------------------------------------------------------------------------
// ObjectWindows
// Copyright (c) 1992, 1996 by Borland International, All Rights Reserved
//
/// \file
/// Implementation of TDib class, an encapsulation of Device Independent Bitmaps
/// on disk and in memory.
//----------------------------------------------------------------------------
#include <owl/pch.h>
#include <owl/gdiobjec.h>
#include <owl/metafile.h>
#include <owl/clipboar.h>
#include <owl/except.h>
#include <owl/file.h>
#include <owl/wsyscls.h>
#if defined(__BORLANDC__)
# pragma option -w-ccc // Disable "Condition is always true/false"
#endif
#define BFT_BITMAP 0x4d42 /* 'BM' */
using namespace std;
namespace owl {
OWL_DIAGINFO;
DIAG_DECLARE_GROUP(OwlGDI); // General GDI diagnostic group
//
// Internal DIB file Read/Write functions talk to this IO implementation
//
class TFileIO : public TDib::IFileIn, public TDib::IFileOut {
public:
TFileIO(TFile& file) : File(file) {}
virtual long Read(void * buffer, long size)
{
return File.Read(buffer, size);
}
virtual void Skip(long size)
{
File.Seek(size, TFile::cur);
}
virtual bool Write(void * buffer, long size)
{
return File.Write(buffer, size);
}
private:
TFile& File;
};
//
/// Given a BITMAPINFOHEADER, allocate a global buffer for Handle & init Info
//
void
TDib::InfoFromHeader(const BITMAPINFOHEADER& infoHeader)
{
// Allocate & lock down the actual single memory block used by this DIB
//
int maskAlloc = infoHeader.biCompression==BI_BITFIELDS ? 3*sizeof(uint32) : 0;
int colorAlloc = int(infoHeader.biClrUsed * sizeof(RGBQUAD)); // Color table size in mem
IsResHandle = false;
uint32 size = sizeof(BITMAPINFOHEADER) + maskAlloc + colorAlloc + infoHeader.biSizeImage;
Handle = ::GlobalAlloc(GMEM_MOVEABLE, size);
if (!Handle)
TXOutOfMemory::Raise();
// Setup Info ptr & copy over working infoHeader. Finish by using
// InfoFromHandle to update all members from Info.
//
Info = (LPBITMAPINFO)::GlobalLock(Handle);
Info->bmiHeader = infoHeader;
InfoFromHandle();
}
//
/// Locks the global/res handle if needed and extracts the pointers and cached info
/// maintained as member variables from Info.
///
/// Needs only Info setup, or if Info is 0 then Handle & IsResHandle setup
//
void
TDib::InfoFromHandle()
{
// Get the BITMAPINFO Info from the handle if needed
//
if (!Info) {
if (IsResHandle)
Info = (LPBITMAPINFO)::LockResource(Handle);
else
Info = (LPBITMAPINFO)::GlobalLock(Handle);
if (!Info)
TXGdi::Raise(IDS_INVALIDDIBHANDLE);
}
// Fail if the header does not look OK
//
if (Info->bmiHeader.biSize != sizeof(BITMAPINFOHEADER)) {
if (!IsResHandle)
::GlobalUnlock(Handle);
TXGdi::Raise(IDS_INVALIDDIBHANDLE);
}
// Determine if there is a bit mask (used by 16 & 32 bpp bmps) and where
// the color table starts
//
if (Info->bmiHeader.biCompression == BI_BITFIELDS) {
Mask = (uint32 *)Info->bmiColors;
Colors = (TRgbQuad *)((char *)Info->bmiColors + 3 * sizeof(uint32));
}
else {
Mask = 0;
Colors = (TRgbQuad *)Info->bmiColors;
}
// Figure out the number of colors in the color table using biClrsUsed &
// biBitCount.
//
NumClrs = Info->bmiHeader.biClrUsed
? Info->bmiHeader.biClrUsed
: NColors(Info->bmiHeader.biBitCount);
Bits = (char *)(char *)Colors + (int)NumClrs * sizeof(RGBQUAD);
// Zero out Colors if there is no color table.
//
if (!NumClrs)
Colors = 0;
Mode = DIB_RGB_COLORS;
}
//
/// Under Win32, resources are read-only. So, to allow for modification of the
/// Dib, a copy must be made.
//
void
TDib::ResToMemHandle()
{
const char* begin = reinterpret_cast<const char*>(Info);
const char* end = static_cast<const char*>(Bits) + Info->bmiHeader.biSizeImage;
size_t size = end - begin;
HANDLE tempHandle = ::GlobalAlloc(GMEM_MOVEABLE, size);
if (!tempHandle)
TXOutOfMemory::Raise();
void* tempInfo = ::GlobalLock(tempHandle);
memcpy(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();
}
//
/// Creates a TDib object and sets the Handle data member to the given borrowed
/// handle. The ShouldDelete data member defaults to false, ensuring that the
/// borrowed handle will not be deleted when the C++ object is destroyed.
//
TDib::TDib(HGLOBAL handle, TAutoDelete autoDelete)
:
TGdiBase(handle, autoDelete),
Info(0), IsResHandle(false)
{
InfoFromHandle();
}
//
/// Constructs a TDib object with a handle borrowed from the given Clipboard.
//
TDib::TDib(const TClipboard& clipboard)
:
TGdiBase(clipboard.GetClipboardData(CF_DIB)),
Info(0), IsResHandle(false)
{
InfoFromHandle();
}
//
/// This public copy constructor creates a complete copy of the given src object as
/// in:
/// \code
/// TDib mySrc = yourSrc;
/// \endcode
//
TDib::TDib(const TDib& src)
:
IsResHandle(false)
{
PRECONDITION(src.Info != 0);
// long size = ::GlobalSize(src.Handle); // !CQ assumes src has a mem handle
uint32 size = src.SizeDib();
Handle = ::GlobalAlloc(GMEM_MOVEABLE, size);
if (!Handle)
TXOutOfMemory::Raise();
Info = (LPBITMAPINFO)::GlobalLock(Handle);
memcpy(Info, src.Info, size);
Mask = (uint32 *)(src.Mask ?
(char *)Info + ((char *)src.Mask - (char *)src.Info) : 0);
Bits = (char *)Info + ((char *)src.Bits - (char *)src.Info);
NumClrs = src.NumClrs;
// Zero out Colors if there is no color table.
//
if (!NumClrs)
Colors = 0;
else
Colors = (TRgbQuad *)((char *)Info + ((char *)src.Colors - (char *)src.Info));
Mode = src.Mode;
}
//
/// Destruct a TDib by unlocking & freeing its global memory handle as required
//
TDib::~TDib()
{
if (!Handle || IsResHandle) return;
::GlobalUnlock(Handle);
if (ShouldDelete)
::GlobalFree(Handle);
}
//
/// Converts the existing color table in place to use palette relative values. The
/// palette that is passed is used as a reference. Returns true if the call is
/// successful; otherwise returns false.
///
/// 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 == Colors[c].rgbRed &&
pe.peGreen == Colors[c].rgbGreen &&
pe.peBlue == Colors[c].rgbBlue) {
index = i;
break;
}
}
((uint16*)Colors)[c] = index;
}
Mode = DIB_PAL_COLORS;
return true;
}
//
/// Converts the existing color table in place to use absolute RGB values. The
/// palette that is passed is used as a reference. Returns true if the call is
/// successful; otherwise returns false.
///
/// Makes sure that color table is pal relative & that there is enough space
//
bool
TDib::ChangeModeToRGB(const TPalette& pal)
{
if (Mode != DIB_PAL_COLORS ||
(uint)((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*)Colors)[c];
if (i >= nEntries)
i = 0;
PALETTEENTRY pe;
pal.GetPaletteEntry(i, pe);
Colors[c].rgbRed = pe.peRed;
Colors[c].rgbGreen = pe.peGreen;
Colors[c].rgbBlue = pe.peBlue;
}
Mode = DIB_RGB_COLORS;
return true;
}
//
// Get, set, find and map the color table entries as colors (RGBQUADs)
//
/// Returns the color for the given palette entry.
//
TColor
TDib::GetColor(int entry) const
{
if (entry >= 0 && entry < NumClrs)
if (Mode == DIB_RGB_COLORS)
return GetColors()[entry];
return TColor();
}
//
/// Sets the given color for the given palette entry.
//
void
TDib::SetColor(int entry, const TColor& color)
{
if (entry >= 0 && entry < NumClrs)
if (Mode == DIB_RGB_COLORS)
GetColors()[entry] = color;
}
//
/// Returns the palette entry for the given color.
//
int
TDib::FindColor(const TColor& color)
{
for (int entry = 0; entry < NumClrs; entry++)
if (color == GetColors()[entry]) // Small data model requires this order
return entry;
return -1;
}
//
/// Maps the first or all occurances of fromColor to the toColor in the current palette of this DIB.
/// Returns the palette entry for the given color. Returns the palette entry for the
/// toColor argument.
//
int
TDib::MapColor(const TColor& fromColor, const TColor& toColor, bool mapAll)
{
int count = 0;
for (int entry = 0; entry < NumClrs; entry++)
if (fromColor == GetColors()[entry]) { // Small data model requires this order
GetColors()[entry] = toColor;
count++;
if (!mapAll)
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;
}
//
/// Sets the given index for the given entry.
//
void
TDib::SetIndex(int entry, uint16 index)
{
if (entry >= 0 && entry < NumClrs)
if (Mode == DIB_PAL_COLORS)
((uint16*)GetColors())[entry] = index;
}
//
/// Returns the palette entry corresponding to the given index.
//
int
TDib::FindIndex(uint16 index)
{
for (int entry = 0; entry < NumClrs; entry++)
if (GetIndices()[entry] == index)
return entry;
return -1;
}
//
/// Maps the fromIndex to the toIndex in the current palette of this DIB.
/// Returns the palette entry for the toIndex argument.
//
int
TDib::MapIndex(uint16 fromIndex, uint16 toIndex, bool doAll)
{
int count = 0;
for (int entry = 0; entry < NumClrs; entry++)
if (GetIndices()[entry] == fromIndex) {
GetIndices()[entry] = toIndex;
count++;
if (!doAll)
break;
}
return count;
}
//
/// Maps the UI colors to the value specified in the parameter, mapColors, which is
/// one of the values of the Map enum. Use this function to get the colors for the
/// face shading on push buttons, the highlighting for a selected control button,
/// the text on push buttons, the shade of the window frame and the background
/// color.
//
/// Use MapColor to map selected standard UI colors in this DIB to their
/// current system values. Also can map a background color. Used to update a
/// UI DIB to current colors before rendering.
///
/// - \c \b LtGray -> 3d Face
/// - \c \b Black -> Button Text
/// - \c \b Gray -> 3d Shadow
/// - \c \b White -> 3d Hilight
/// - \c \b Magenta -> Window Frame
/// - \c \b LtYellow -> bkColor
//
void
TDib::MapUIColors(uint mapColors, const TColor* bkColor)
{
if (mapColors & TDib::MapFace)
#ifdef UNIX
MapColor(TColor::LtGray, TColor::SysWindow); //copied from old owl (DLN UNIX color
//problem TColor::Sys3dFace);) (04-16-01 JAM)
#else
MapColor(TColor::LtGray, TColor::Sys3dFace);
#endif
if (mapColors & TDib::MapText)
MapColor(TColor::Black, TColor::SysBtnText);
if (mapColors & TDib::MapShadow)
MapColor(TColor::Gray, TColor::Sys3dShadow);
if (mapColors & TDib::MapHighlight)
MapColor(TColor::White, TColor::Sys3dHilight);
if (mapColors & TDib::MapFrame)
MapColor(TColor::LtMagenta, TColor::SysWindowFrame);
if (bkColor)
MapColor(TColor::LtYellow, *bkColor);
}
//
/// Moves this dib to the clipboard. Ownership of the DIB handle is passed to the
/// clipboard.
//
void
TDib::ToClipboard(TClipboard& clipboard)
{
if (Handle) {
if (IsResHandle) {
}
else {
::GlobalUnlock(Handle);
}
clipboard.SetClipboardData(CF_DIB, Handle);
ShouldDelete = false;
Info = 0;
Bits = 0;
Handle = 0;
}
}
//
/// Creates a DIB object from the given resource file (.bmp).
//
TDib::TDib(LPCTSTR filename)
{
if (!ReadFile(filename))
TXGdi::Raise(IDS_GDIFILEREADFAIL);
}
//
/// String-aware overload
//
TDib::TDib(const tstring& filename)
{
if (!ReadFile(filename))
TXGdi::Raise(IDS_GDIFILEREADFAIL);
}
//
/// Creates a DIB from the file.
//
TDib::TDib(TFile& file, bool readFileHeader)
{
if (!Read(file, readFileHeader))
TXGdi::Raise(IDS_GDIFILEREADFAIL);
}
//
/// Creates a DIB from the file stream.
//
TDib::TDib( istream& is, bool readFileHeader)
{
if (!Read(is, readFileHeader))
TXGdi::Raise(IDS_GDIFILEREADFAIL);
}
//
/// Constructs an empty DIB for use by derived classes.
//
TDib::TDib()
:
Info(0), Mask(0), Colors(0), Bits(0),
NumClrs(0),
IsResHandle(false)
{
// Handle must be set by derived class
// InfoFromHandle() or equivalent must then be called
}
//
/// Tests if the passed file is a Windows 3.x (or PM 1.x) DIB and if so read it.
///
/// Returns true if Dib was read OK.
//
bool
TDib::ReadFile(const tstring& name)
{
TFile file(name, TFile::ReadOnly|TFile::OpenExisting);
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.x or PM 1.x device independent bitmap from a TFile
/// Return true iff Dib was read OK
//
bool
TDib::Read(TFile& file, bool readFileHeader)
{
TFileIO in(file);
return Read(in, readFileHeader);
}
//
// The ios version of the DIB read requires large data model since the buffers
// are quite large.
//
//
//
//
class TStreamIn : public TDib::IFileIn {
public:
TStreamIn(istream& is) : Is(is) {}
virtual long Read(void* buffer, long size)
{
PRECONDITION(size >= 0);
streamsize n = Is.read(static_cast<char*>(buffer), size).gcount();
// Note: 'n' cannot be larger than 'size'; hence we can cast unchecked.
// TODO: Widen the return type to avoid the narrowing cast.
return static_cast<long>(n);
}
virtual void Skip(long size)
{
Is.seekg(size, ios::cur);
}
private:
istream& Is;
};
//
//
/// Read a Windows 3.0 or PM 1.X device independent bitmap from an istream
///
/// Checks header, read Info, palette and bitmap. PM DIBs can be converted to
/// Win 3.x DIBs on the fly.
///
/// Returns true iff DIB was read OK
//
bool
TDib::Read( istream& is, bool readFileHeader)
{
TStreamIn in(is);
return Read(in, readFileHeader);
}
//
/// Reads a Windows 3.0 or PM 1.X device independent bitmap. (.BMP) from an
/// implementor of TDib's IFileIn interface
///
/// Checks header, read Info, palette and bitmap. PM Dibs are converted to
/// Windows 3.x Dibs on the fly.
///
/// Returns true iff Dib was read OK
//
bool
TDib::Read(IFileIn& in, 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 ((size_t)in.Read(&bmf, sizeof(bmf)) != sizeof(bmf) || bmf.bfType != BFT_BITMAP) {
TRACEX(OwlGDI, 0, "Not a Windows 3.x or PM 1.x bitmap file");
TXBadFormat::Raise();
return false;
}
if (bmf.bfOffBits)
offBits = bmf.bfOffBits - sizeof(BITMAPFILEHEADER);
}
// Read bitmap header size & check it. It must be one of the two known header
// sizes.
// Will add BITMAPV4HEADER support when available
//
uint32 headerSize;
size_t n = static_cast<size_t>(in.Read(&headerSize, sizeof(headerSize)));
if (n != sizeof(headerSize) ||
(headerSize != sizeof(BITMAPCOREHEADER) && headerSize != sizeof(BITMAPINFOHEADER)))
{
TRACEX(OwlGDI, 0, "Not a Windows 3.x or PM 1.x bitmap file");
TXBadFormat::Raise();
return false;
}
// Prepare to build or read a header that is an Info (Windows) type
//
BITMAPINFOHEADER infoHeader;
infoHeader.biSize = sizeof(BITMAPINFOHEADER);
// If this is a PM 1.x DIB, read the core header & copy over to the Info header
//
bool isCore = headerSize == sizeof(BITMAPCOREHEADER);
if (isCore) {
// Read in the rest of the core header, aborting if it is truncated
//
BITMAPCOREHEADER coreHeader;
int size = (int)headerSize-sizeof(uint32);
if (in.Read(&coreHeader.bcWidth, size) != size) {
TRACEX(OwlGDI, 0, "Invalid PM 1.x DIB Header");
TXBadFormat::Raise();
return false;
}
// Copy core fields over to info fields, filling in the missing pieces
//
infoHeader.biWidth = coreHeader.bcWidth;
infoHeader.biHeight = coreHeader.bcHeight;
infoHeader.biPlanes = coreHeader.bcPlanes;
infoHeader.biBitCount = coreHeader.bcBitCount;
infoHeader.biCompression = BI_RGB; // No compression
infoHeader.biSizeImage = 0; // Calculate this below
infoHeader.biXPelsPerMeter = 0; // Zero is OK
infoHeader.biYPelsPerMeter = 0; // Zero is OK
infoHeader.biClrUsed = 0; // Calculate this below
infoHeader.biClrImportant = 0; // Zero is OK
}
// This is a Win 3.x DIB, read the info header
//
else {
// Read in the rest of the info header, aborting if it is truncated
//
int size = (int)headerSize-sizeof(uint32);
if (in.Read(&infoHeader.biWidth, size) != size) {
TRACEX(OwlGDI, 0, "Invalid Win 3.x DIB Header");
TXBadFormat::Raise();
return false;
}
}
// Check number of planes. Windows supports only 1 plane DIBs
//
if (infoHeader.biPlanes != 1) {
TRACEX(OwlGDI, 0, "Invalid number of planes in DIB");
TXBadFormat::Raise();
return false;
}
// Fill in the default value for biClrsUsed, if not supplied, using the
// bit count. Will remain 0 for 16bpp or greater.
//
if (!infoHeader.biClrUsed)
infoHeader.biClrUsed = NColors(infoHeader.biBitCount);
// Some applications do not fill in the biSizeImage 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.)
//
// Therefore, if compression was not used, we (re)compute the size,
// but if compression is used, we have no choice but to trust the size.
//
if (infoHeader.biCompression == BI_RGB ||
infoHeader.biCompression == BI_BITFIELDS)
infoHeader.biSizeImage =
ScanBytes(infoHeader.biWidth,
infoHeader.biBitCount) * infoHeader.biHeight;
// Setup all members based on InfoHeader
//
InfoFromHeader(infoHeader);
// Read color mask directly into allocated memory
//
if (Mask) {
int size = 3*sizeof(uint32);
if (in.Read((char *)Mask, size) != size) {
TRACEX(OwlGDI, 0, "Could not read DIB color mask");
::GlobalUnlock(Handle);
return false;
}
}
// Read color table directly into allocated memory
// Walk backwards & expand to RGBQUADs if it is a PM Core DIB
//
int colorRead = isCore ? // Color table size on disk
(int)NumClrs * sizeof(RGBTRIPLE) :
(int)NumClrs * sizeof(RGBQUAD);
if (Colors) {
if (in.Read((char *)Colors, colorRead) != colorRead) {
TRACEX(OwlGDI, 0, "Could not read DIB color table");
::GlobalUnlock(Handle);
return false;
}
if (isCore) {
for (int i = int(NumClrs-1); i >= 0; i--) {
Colors[i].rgbRed = ((RGBTRIPLE*)Colors)[i].rgbtRed;
Colors[i].rgbGreen = ((RGBTRIPLE*)Colors)[i].rgbtGreen;
Colors[i].rgbBlue = ((RGBTRIPLE*)Colors)[i].rgbtBlue;
Colors[i].rgbReserved = 0;
}
}
}
// Locate & Read Bits, skipping Pad if any.
// Ignore offBits if it is zero, or if less than the current position--it's
// probably bad
//
if (offBits && offBits - (long)(headerSize+colorRead) > 0)
in.Skip(offBits - (headerSize+colorRead));
if (!in.Read(Bits, infoHeader.biSizeImage)) {
TRACEX(OwlGDI, 0, "Could not read DIB bits");
return false;
}
return true;
}
//
/// Creates a TDib given a module instance and a resource name or int Id
//
TDib::TDib(HINSTANCE instance, TResId resId)
:
Info(0), Mask(0), Colors(0), Bits(0),
NumClrs(0),
IsResHandle(false)
{
if (!LoadResource(instance, resId))
TXGdi::Raise(IDS_GDIRESLOADFAIL);
}
//
/// Loads this DIB from the given resource and returns true if successful.
//
bool
TDib::LoadResource(HINSTANCE instance, TResId resId)
{
PRECONDITION(!Handle);
// First, load the resource into a global memory block.
//
HRSRC resHandle = ::FindResource(instance, resId, RT_BITMAP);
Handle = resHandle ? ::LoadResource(instance, resHandle) : 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...
//
ResToMemHandle();
return true;
}
//
/// Writes the DIB into an external file.
///
/// Returns true if the call is successful; otherwise returns false.
//
bool
TDib::WriteFile(const tstring& name)
{
TFile file(name, TFile::WriteOnly|TFile::PermExclusive|TFile::CreateAlways);
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;
}
//
/// Write this DIB to a file object.
//
bool
TDib::Write(TFile& file, bool writeFileHeader)
{
TFileIO out(file);
return Write(out, writeFileHeader);
}
//
// The ios version of the DIB read requires large data model since the buffers
// are quite large.
//
//
//
//
class TStreamOut : public TDib::IFileOut {
public:
TStreamOut( ostream& os) : Os(os) {}
virtual bool Write(void * buffer, long size)
{
return Os.write((char*)buffer, size).good();
}
private:
ostream& Os;
};
//
/// Writes this DIB to an ostream.
//
bool
TDib::Write( ostream& os, bool writeFileHeader)
{
TStreamOut out(os);
return Write(out, writeFileHeader);
}
//
/// Writes the DIB into a file stream.
//
bool
TDib::Write(IFileOut& out, bool writeFileHeader)
{
size_t size = ::GlobalSize(Handle);
// Write file header.
//
if (writeFileHeader)
{
size_t bfSize = size + sizeof(BITMAPFILEHEADER);
if (!IsRepresentable<DWORD>(bfSize))
return false;
const char* begin = reinterpret_cast<const char*>(Info);
const char* end = static_cast<const char*>(Bits) + sizeof(BITMAPFILEHEADER);
size_t bfOffBits = end - begin;
if (!IsRepresentable<DWORD>(bfOffBits))
return false;
BITMAPFILEHEADER bmf;
bmf.bfType = BFT_BITMAP;//'BM';
bmf.bfSize = static_cast<DWORD>(bfSize);
bmf.bfReserved1 = 0;
bmf.bfReserved2 = 0;
bmf.bfOffBits = static_cast<DWORD>(bfOffBits);
if (!out.Write(&bmf, sizeof(bmf)))
return false;
}
// Write rest of dib, including dib header, color table & bits.
//
if (!IsRepresentable<long>(size))
return false;
if (!out.Write(Info, static_cast<long>(size))) // TODO: Widen parameter type to avoid this narrowing cast.
return false;
return true;
}
//
/// Creates a DIB object with the given width, height, number of colors, mode
/// values.
//
TDib::TDib(int width, int height, uint32 nColors, uint16 mode)
{
PRECONDITION(width && height && nColors);
BITMAPINFOHEADER infoHeader;
infoHeader.biSize = sizeof(BITMAPINFOHEADER);
infoHeader.biWidth = width;
infoHeader.biHeight = height;
infoHeader.biPlanes = 1;
infoHeader.biBitCount = NBits(nColors);
infoHeader.biCompression = BI_RGB;
uint32 bytes = ScanBytes(width, infoHeader.biBitCount);
infoHeader.biSizeImage = bytes * height;
infoHeader.biXPelsPerMeter = 0;
infoHeader.biYPelsPerMeter = 0;
infoHeader.biClrUsed = infoHeader.biBitCount > 8 ? 0 : nColors;
infoHeader.biClrImportant = 0;
// Setup all members based on infoHeader
//
InfoFromHeader(infoHeader);
// Initialize the color table--either Palette or RGB
//
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 (uint i = 0; i < nColors; i++)
((uint16*)Colors)[i] = (uint16)i;
}
else if(nColors){
// Get the system palette and convert to RGB quad format if exist support.
//
TScreenDC dc;
if(dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE){
uint clrCnt = ::GetSystemPaletteEntries(dc, 0, nColors, (LPPALETTEENTRY)Colors);
for (uint32 i = 0; i < clrCnt; i++) {
Swap(Colors[i].rgbRed, Colors[i].rgbBlue);
Colors[i].rgbReserved = 0;
}
}
}
}
//
/// Creates a DIB object from the given resource bitmap and palette. If pal is 0
/// (the default), the default palette is used.
//
TDib::TDib(const TBitmap& bitmap, const TPalette* palette)
{
BITMAP bm;
bitmap.GetObject(bm);
BITMAPINFOHEADER infoHeader;
infoHeader.biSize = sizeof(BITMAPINFOHEADER);
infoHeader.biWidth = bm.bmWidth;
infoHeader.biHeight = bm.bmHeight;
infoHeader.biPlanes = 1;
uint16 nColors;
if (palette) {
palette->GetObject(nColors);
infoHeader.biBitCount = NBits(nColors);
}
else {
infoHeader.biBitCount = uint16(bm.bmBitsPixel*bm.bmPlanes);
nColors = (uint16)NColors(infoHeader.biBitCount);
}
infoHeader.biCompression = BI_RGB;
infoHeader.biSizeImage = ScanBytes(infoHeader.biWidth,
infoHeader.biBitCount) * infoHeader.biHeight;
infoHeader.biXPelsPerMeter = 0;
infoHeader.biYPelsPerMeter = 0;
infoHeader.biClrUsed = nColors;
infoHeader.biClrImportant = 0;
// Setup all members based on infoHeader
//
InfoFromHeader(infoHeader);
// Copy pixels from given bitmap into our new empty DIB, selecting palette
// if provided
//
TScreenDC dc;
if (palette)
dc.SelectObject(*palette, false);
dc.GetDIBits(bitmap, StartScan(), NumScans(), Bits, *Info, Usage());
}
//
/// Modifies this DIB so that the pixels and color table coincide with a given
/// palette.
/// !CQ 8bpp only!
//
void
TDib::MapToPalette(const TPalette& pal)
{
// Create a mapping from our current color table to the target palette
//
uint8 map[256];
for (int i = 0; i < 256; i++)
map[i] = (uint8)pal.GetNearestPaletteIndex(GetColor(i));
// Use the map to translate all of the pixels into indexes in the target
// palette
//
uint8 * bits = (uint8 *)GetBits();
long size = Pitch() * Height();
while (size--) {
*bits = map[*bits];
bits++;
}
// Now copy the target palette into our color table
//
PALETTEENTRY pe[256];
pal.GetPaletteEntries(0, 256, pe);
TRgbQuad * colorTab = GetColors();
for (int j = 0; j < 256; j++) {
colorTab->rgbRed = pe[j].peRed;
colorTab->rgbGreen = pe[j].peGreen;
colorTab->rgbBlue = pe[j].peBlue;
colorTab++;
}
}
} // OWL namespace
↑ V220 Suspicious sequence of types castings: memsize -> 32-bit integer -> memsize. The value being cast: '((char *) Bits - (char *) Info)'.
↑ V614 Uninitialized variable 'coreHeader.bcHeight' used.
↑ V614 Uninitialized variable 'coreHeader.bcPlanes' used.
↑ V614 Uninitialized variable 'coreHeader.bcBitCount' used.
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: Mode.
↑ V1004 The 'src.Info' pointer was used unsafely after it was verified against nullptr. Check lines: 202, 211.
↑ V1032 The pointer 'GetColors()' is cast to a more strictly aligned pointer type.
↑ V1032 The pointer 'GetColors()' is cast to a more strictly aligned pointer type.
↑ V614 Potentially uninitialized variable 'infoHeader.biPlanes' used.
↑ V614 Potentially uninitialized variable 'infoHeader.biClrUsed' used.
↑ V614 Potentially uninitialized variable 'infoHeader.biCompression' used.
↑ V1027 Pointer to an object of the 'TRgbQuad' class is cast to unrelated 'tagRGBTRIPLE' class.
↑ V1027 Pointer to an object of the 'TRgbQuad' class is cast to unrelated 'tagRGBTRIPLE' class.
↑ V1027 Pointer to an object of the 'TRgbQuad' class is cast to unrelated 'tagRGBTRIPLE' class.