2025-11-27 16:46:48 +09:00

2811 lines
69 KiB
C++

// ==========================================================================
// Class Implementation : COXDIB
// ==========================================================================
// Source file : oxdib.cpp
// Version: 9.3
// This software along with its related components, documentation and files ("The Libraries")
// is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
// governed by a software license agreement ("Agreement"). Copies of the Agreement are
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
// to obtain this file, or directly from our office. For a copy of the license governing
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
// //////////////////////////////////////////////////////////////////////////
#include "stdafx.h" // standard MFC include
#include "oxdib.h" // class specification
#include "limits.h" // For long -> int truncation
#ifndef NO_DITHER
#include "oxhlftne.h" // conversion tables and halftone palettefor 16 bit
#endif // NO_DITHER
#include <windowsx.h>
#include <windowsx.h>
#include "UTB64Bit.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[]=__FILE__;
#endif
#define DIB_HEADER_MARKER ((WORD) ('M' << 8) | 'B')
#define SIZE_ERROR_BUF 255
IMPLEMENT_SERIAL(COXDIB, CObject, 1)
#define new DEBUG_NEW
/////////////////////////////////////////////////////////////////////////////
// Definition of static members
// Data members -------------------------------------------------------------
// protected:
// HDIB m_hDIB;
// --- Handle(Global memory) to DIB (or NULL) when not connected to a DIB
// CPalette* m_pPalette;
// --- Pointer to the pallet belonging to the DIB (or NULL if none)
// private:
// Member functions ---------------------------------------------------------
// public:
COXDIB::COXDIB()
:
m_hDIB(NULL),
m_pPalette(NULL)
{
ASSERT_VALID(this);
}
COXDIB::COXDIB(HDIB hDIB)
:
m_hDIB(NULL),
m_pPalette(NULL)
{
// Copy the DIB memory and initialize the palette of the copy
m_hDIB=CopyHandle (hDIB);
if (m_hDIB != NULL)
{
LPSTR lpDIB=(LPSTR) ::GlobalLock((HGLOBAL) m_hDIB);
InitPalette(lpDIB);
::GlobalUnlock(m_hDIB);
}
ASSERT_VALID(this);
}
BOOL COXDIB::ClearSystemPalette()
{
//*** A dummy palette setup
struct
{
WORD Version;
WORD NumberOfEntries;
PALETTEENTRY aEntries[256];
} Palette =
{
0x300,
256
};
HPALETTE ScreenPalette=0;
HDC ScreenDC;
int Counter;
UINT nMapped=0;
BOOL bOK=FALSE;
int nOK=0;
// Reset everything in the system palette to black
for(Counter=0; Counter < 256; Counter++)
{
Palette.aEntries[Counter].peRed=0;
Palette.aEntries[Counter].peGreen=0;
Palette.aEntries[Counter].peBlue=0;
Palette.aEntries[Counter].peFlags=PC_NOCOLLAPSE;
}
// Create, select, realize, deselect, and delete the palette
ScreenDC=::GetDC(NULL);
ScreenPalette=::CreatePalette((LOGPALETTE*)&Palette);
if (ScreenPalette)
{
ScreenPalette=::SelectPalette(ScreenDC, ScreenPalette, FALSE);
nMapped=::RealizePalette(ScreenDC);
ScreenPalette=::SelectPalette(ScreenDC, ScreenPalette, FALSE);
bOK=::DeleteObject(ScreenPalette);
}
nOK=::ReleaseDC(NULL, ScreenDC);
return bOK && (nOK==1);
}
BOOL COXDIB::GetSystemPalette(CPalette* pPalette)
{
ASSERT(pPalette != NULL);
HDC hDC; // handle to a DC
HANDLE hLogPal; // handle to a logical palette
LPLOGPALETTE lpLogPal; // pointer to a logical palette
// Find out how many palette entries we want.
hDC=GetDC(NULL);
if (hDC==NULL)
return FALSE;
// For non-palette devices, there's no palette available
if ((::GetDeviceCaps(hDC, RASTERCAPS) & RC_PALETTE) != RC_PALETTE)
{
TRACE(_T("COXDIB::GetSystemPalette : No palette device\n"));
return FALSE;
}
// Find out the number of palette entries on this device.
int nColors=GetDeviceCaps(hDC, SIZEPALETTE);
// Sometimes we'll use the # of system reserved
// colors for our palette size.
if (nColors==0)
nColors=GetDeviceCaps(hDC, NUMCOLORS);
ASSERT(nColors != 0);
// Allocate room for the palette and lock it.
hLogPal=::GlobalAlloc(GHND, sizeof(LOGPALETTE)
+ sizeof(PALETTEENTRY)
* nColors);
// if not enough memory, clean up and return NULL
if (hLogPal==NULL)
{
TRACE(_T("COXDIB::GetSystemPalette : Not enough memory for logical palette\n"));
ReleaseDC(NULL, hDC);
return FALSE;
}
// get a pointer to the logical palette
lpLogPal=(LPLOGPALETTE) ::GlobalLock((HGLOBAL) hLogPal);
// set version and number of palette entries
lpLogPal->palVersion=PALVERSION;
lpLogPal->palNumEntries=(WORD)nColors;
// Copy the current system palette into our logical palette
::GetSystemPaletteEntries(hDC, 0, nColors,
(LPPALETTEENTRY)(lpLogPal->palPalEntry));
// Go ahead and create the palette. Once it's created,
// we no longer need the LOGPALETTE, so free it.
// -- create the palette and get handle to it
BOOL bResult=pPalette->CreatePalette(lpLogPal);
::GlobalUnlock((HGLOBAL) hLogPal);
::GlobalFree((HGLOBAL) hLogPal);
ReleaseDC(NULL, hDC);
return bResult;
}
HPALETTE COXDIB::CreateDIBPalette(LPBITMAPINFO lpbmi,int& nNumColors)
{
LPBITMAPINFOHEADER lpbi=NULL;
LPLOGPALETTE lpPal=NULL;
HANDLE hLogPal=NULL;
HPALETTE hPal=NULL;
int i=0;
// ... Initialize return variable
nNumColors=0;
lpbi=(LPBITMAPINFOHEADER)lpbmi;
if(lpbi->biBitCount<=8)
nNumColors=(1<<lpbi->biBitCount);
else
nNumColors=0; // No palette needed for 24 BPP DIB
if(lpbi->biClrUsed>0)
nNumColors=lpbi->biClrUsed; // Use biClrUsed
if (nNumColors!=0)
{
hLogPal=::GlobalAlloc(GHND,
sizeof(LOGPALETTE)+sizeof (PALETTEENTRY)*nNumColors);
lpPal=(LPLOGPALETTE)::GlobalLock(hLogPal);
lpPal->palVersion=(WORD)0x300;
lpPal->palNumEntries=(WORD)nNumColors;
for(i=0; i<nNumColors; i++)
{
lpPal->palPalEntry[i].peRed=lpbmi->bmiColors[i].rgbRed;
lpPal->palPalEntry[i].peGreen=lpbmi->bmiColors[i].rgbGreen;
lpPal->palPalEntry[i].peBlue=lpbmi->bmiColors[i].rgbBlue;
lpPal->palPalEntry[i].peFlags=0;
}
hPal=::CreatePalette(lpPal);
::GlobalUnlock(hLogPal);
::GlobalFree(hLogPal);
}
return hPal;
}
BOOL COXDIB::LoadResource(LPCTSTR lpszResourceName,
HINSTANCE hInstance/*=NULL*/)
{
BOOL bResult=FALSE;
HRSRC hRsrc=NULL;
HGLOBAL hGlobal=NULL;
HBITMAP hBitmapFinal=NULL;
HPALETTE hPal=NULL;
LPBITMAPINFOHEADER lpbi=NULL;
HDC hdc=NULL;
int iNumColors=0;
CPalette palette;
if(hInstance==NULL)
hInstance=AfxFindResourceHandle(lpszResourceName,RT_BITMAP);
if(hInstance!=NULL)
hRsrc=::FindResource(hInstance,lpszResourceName,RT_BITMAP);
if(hRsrc!=NULL)
hGlobal=::LoadResource(hInstance,hRsrc);
if(hGlobal!=NULL)
{
lpbi=(LPBITMAPINFOHEADER)::LockResource(hGlobal);
if(lpbi!=NULL)
{
hdc=::GetDC(NULL);
if(hdc!=NULL)
{
hPal=CreateDIBPalette((LPBITMAPINFO)lpbi,iNumColors);
if((hPal==NULL)&&(::GetDeviceCaps(hdc,SIZEPALETTE)==256))
{
// .... Trying to show bitmap without palette on
// 256-color display so let's use halftone palette
// (better than nothing)
if(GetHalfTonePalette(&palette))
hPal=(HPALETTE)palette.Detach();
}
if(hPal != NULL)
{
SelectPalette(hdc, hPal, FALSE);
RealizePalette(hdc);
}
hBitmapFinal=::CreateDIBitmap(hdc,(LPBITMAPINFOHEADER)lpbi,
(LONG)CBM_INIT,
(LPSTR)lpbi+lpbi->biSize+iNumColors*sizeof(RGBQUAD),
(LPBITMAPINFO)lpbi,DIB_RGB_COLORS);
palette.Attach(hPal);
bResult=(BitmapToDIB(hBitmapFinal,&palette)!=NULL);
::DeleteObject((HGDIOBJ)palette.Detach());
::DeleteObject((HGDIOBJ)hPal);
::DeleteObject((HGDIOBJ)hBitmapFinal);
::DeleteObject((HGDIOBJ)hPal);
::ReleaseDC(NULL,hdc);
}
::UnlockResource(hGlobal);
}
::FreeResource(hGlobal);
}
return bResult;
}
HDIB WINAPI COXDIB::MakeCopy()
{
return CopyHandle(m_hDIB);
}
CBitmap* COXDIB::MakeBitmap(CDC* pDC, CSize& bmSize)
{
BITMAP bm;
DWORD dwFore, dwBack;
LPSTR lpDIB; // pointer to packed-DIB
PDIB lpbmih; // pointer to a Win 3.0-style DIB
LPBITMAPINFO lpbmi; // pointer to the bitmap info
lpDIB=(LPSTR) ::GlobalLock((HGLOBAL) m_hDIB);
// point to the header (whether Win 3.0 and old)
lpbmi=(LPBITMAPINFO)lpDIB;
lpbmih=(PDIB)lpDIB;
// checks to see whether DIB buffer is properly loaded
// ... Check for valid DIB handle
if (m_hDIB==NULL)
{
TRACE(_T("COXDIB::MakeBitmap : DIB not loaded, nothing to copy to bitmap\n"));
bmSize.cx=bmSize.cy=0;
::GlobalUnlock((HGLOBAL) m_hDIB);
return NULL;
}
// checks to see wether DIB header is valid
// ... Check for valid DIB header compression member (must be uncompressed=BI_RGB)
if (lpbmi->bmiHeader.biCompression != BI_RGB || lpbmih->biCompression != BI_RGB)
{
TRACE(_T("COXDIB::MakeBitmap : DIB compressed, unable to handle bitmap\n"));
::GlobalUnlock((HGLOBAL) m_hDIB);
return NULL;
}
// this code conditions the bitmap for mono or color
int nPlanes=pDC->GetDeviceCaps(PLANES);
int nBitsPixel=pDC->GetDeviceCaps(BITSPIXEL);
CBitmap* pConfigBitmap=new CBitmap;
char bits[100];
if (GetNumBitsPerPixel(lpDIB)==1)
{
pConfigBitmap->CreateBitmap(1, 1, 1, 1, bits);
}
else
{
pConfigBitmap->CreateBitmap(1, 1, nPlanes, nBitsPixel, bits);
}
CBitmap* pOriginalBitmap =
(CBitmap*) pDC->SelectObject(pConfigBitmap);
// CreateDIBitmap "switches bits" for mono bitmaps, depending on colors,
// so we'll fool it
if(GetMonoColors(dwFore,dwBack,lpDIB))
{
SetMonoColors(0L,0xFFFFFFL,lpDIB);
}
// Get the DIB's palette, then select it into DC
HPALETTE hPal=NULL; // Our DIB's palette
HPALETTE hOldPal=NULL; // Previous palette
if (m_pPalette != NULL)
{
hPal=(HPALETTE) m_pPalette->m_hObject;
// ... Select as background since we have
// already realized in forground if needed
hOldPal=::SelectPalette(pDC->m_hDC, hPal, TRUE);
pDC->RealizePalette();
}
#ifdef WIN32
HBITMAP hBitmap=::CreateDIBitmap(pDC->GetSafeHdc(), lpbmih,
CBM_INIT, (CONST BYTE*) FindDIBBits(lpDIB), lpbmi, DIB_RGB_COLORS);
#else
HBITMAP hBitmap=::CreateDIBitmap(pDC->GetSafeHdc(), lpbmih,
CBM_INIT, FindDIBBits(lpDIB), lpbmi, DIB_RGB_COLORS);
#endif
// ... Reselect old palette
if (hOldPal != NULL)
{
::SelectPalette(pDC->m_hDC, hOldPal, TRUE);
}
if (hBitmap==NULL)
{
TRACE(_T("COXDIB::MakeBitmap: null bitmap\n"));
delete pDC->SelectObject(pOriginalBitmap); // delete config bitmap
::GlobalUnlock((HGLOBAL) m_hDIB);
return NULL; // untested error logic
}
if(GetNumBitsPerPixel(lpDIB)==1)
{
SetMonoColors(dwFore,dwBack,lpDIB);
}
// Can't use CBitmap::FromHandle here because we need to
// delete the object later
CBitmap* pBitmap=new CBitmap;
pBitmap->Attach(hBitmap);
pBitmap->GetObject(sizeof(bm), &bm);
bmSize.cx=bm.bmWidth;
bmSize.cy=bm.bmHeight;
delete pDC->SelectObject(pBitmap); // delete configuration bitmap
::GlobalUnlock((HGLOBAL) m_hDIB);
return pOriginalBitmap;
}
HDIB COXDIB::Detach()
{
HDIB hDIB=m_hDIB;
m_hDIB=NULL;
return hDIB;
}
BOOL COXDIB::IsEmpty() const
{
return (m_hDIB==NULL);
}
void COXDIB::Empty()
{
ASSERT_VALID(this);
if (m_hDIB != NULL)
{
::GlobalFree((HGLOBAL) m_hDIB);
m_hDIB=NULL;
delete m_pPalette; // May already be NULL
m_pPalette=NULL;
}
ASSERT_VALID(this);
}
void COXDIB::SetMonoColors(DWORD dwForeground, DWORD dwBackground,
LPSTR lpDIBHeader /*==NULL */)
{
BOOL bWasLockedBefore=TRUE;
// ... Check for valid Info pointer
if(lpDIBHeader==NULL)
{
lpDIBHeader=(LPSTR)::GlobalLock((HGLOBAL)m_hDIB);
if(lpDIBHeader==NULL)
{
TRACE(_T("COXDIB::SetMonoColors : fails with null pointer\n"));
return;
}
bWasLockedBefore=FALSE;
}
ASSERT(GetNumBitsPerPixel(lpDIBHeader)==1);
if(GetNumBitsPerPixel(lpDIBHeader)!=1)
{
if(!bWasLockedBefore)
::GlobalUnlock((HGLOBAL)lpDIBHeader);
return;
}
LPBITMAPINFOHEADER lpbmih; // pointer to a Win 3.0-style DIB
// point to the header (whether Win 3.0 and old)
lpbmih=(LPBITMAPINFOHEADER)lpDIBHeader;
#ifdef WIN32
ULONG* pPalette=(ULONG*)((LPSTR) lpbmih + sizeof(BITMAPINFOHEADER));
#else
unsigned long far* pPalette=
(unsigned long far*)((LPSTR) lpbmih + sizeof(BITMAPINFOHEADER));
#endif
dwForeground=RGB(GetBValue(dwForeground),GetGValue(dwForeground),
GetRValue(dwForeground));
dwBackground=RGB(GetBValue(dwBackground),GetGValue(dwBackground),
GetRValue(dwBackground));
*pPalette=dwForeground;
*(++pPalette)=dwBackground;
if(!bWasLockedBefore)
::GlobalUnlock((HGLOBAL)lpDIBHeader);
return;
}
///////////////////////////////////////////////////////////////////
BOOL COXDIB::GetMonoColors(DWORD& dwForeground, DWORD& dwBackground, LPSTR lpDIBHeader /*==NULL */)
{
BOOL bWasLockedBefore=TRUE;
// ... Check for valid Info pointer
if (lpDIBHeader==NULL)
{
lpDIBHeader=(LPSTR)::GlobalLock((HGLOBAL)m_hDIB);
if(lpDIBHeader==NULL)
{
TRACE(_T("COXDIB::GetMonoColors : fails with null pointer\n"));
return FALSE;
}
bWasLockedBefore=FALSE;
}
if (GetNumBitsPerPixel(lpDIBHeader) != 1)
{
if(!bWasLockedBefore)
::GlobalUnlock((HGLOBAL)lpDIBHeader);
return FALSE;
}
LPBITMAPINFOHEADER lpbmih; // pointer to a Win 3.0-style DIB
// point to the header (whether Win 3.0 and old)
lpbmih=(LPBITMAPINFOHEADER)lpDIBHeader;
unsigned long far* pPalette=(unsigned long far*)
((LPSTR) lpbmih + sizeof(BITMAPINFOHEADER));
dwForeground=*pPalette;
dwBackground=*(++pPalette);
if(!bWasLockedBefore)
::GlobalUnlock((HGLOBAL)lpDIBHeader);
return TRUE;
}
BOOL COXDIB::Paint(CDC* pDC, const CRect& rDCRect, const CRect& rDIBRect)
{
ASSERT_VALID(this);
LPSTR lpDIBHdr; // Pointer to BITMAPINFOHEADER
LPSTR lpDIBBits; // Pointer to DIB bits
BOOL bSuccess=FALSE; // Success/fail flag
HPALETTE hPal=NULL; // Our DIB's palette
HPALETTE hOldPal=NULL; // Previous palette
// ... Check for valid DIB handle
if (m_hDIB==NULL)
{
TRACE(_T("COXDIB::PaintDIB : DIB not loaded, nothing to paint\n"));
return FALSE;
}
// Lock down the DIB, and get a pointer to the beginning of the bit buffer
lpDIBHdr =(LPSTR) ::GlobalLock((HGLOBAL) m_hDIB);
lpDIBBits=FindDIBBits(lpDIBHdr);
// Get the DIB's palette, then select it into DC
if (m_pPalette != NULL)
{
hPal=(HPALETTE) m_pPalette->m_hObject;
// ... Select as background since we have
// already realized in forground if needed
hOldPal=::SelectPalette(pDC->m_hDC, hPal, FALSE);
::RealizePalette(pDC->m_hDC);
}
// ... Make sure to use the stretching mode best for color pictures
::SetStretchBltMode(pDC->m_hDC, COLORONCOLOR);
// Determine whether to call Stretcm_hDIBits() or SetDIBitsToDevice()
if ((rDCRect.Width()==rDIBRect.Width()) &&
(rDCRect.Height()==rDIBRect.Height()) &&
(pDC->GetMapMode()==MM_TEXT))
bSuccess=::SetDIBitsToDevice(pDC->m_hDC, // pDC->m_hDC
rDCRect.left, // DestX
rDCRect.top, // DestY
rDCRect.Width(), // nDestWidth
rDCRect.Height(), // nDestHeight
rDIBRect.left, // SrcX
(int)GetSize(lpDIBHdr).cy -
rDIBRect.top -
rDIBRect.Height(), // SrcY
0, // nStartScan
(WORD)GetSize(lpDIBHdr).cy, // nNumScans
lpDIBBits, // lpBits
(LPBITMAPINFO)lpDIBHdr, // lpBitsInfo
DIB_RGB_COLORS); // wUsage
else
bSuccess=::StretchDIBits(pDC->m_hDC, // pDC->m_hDC
rDCRect.left, // DestX
rDCRect.top, // DestY
rDCRect.Width(), // nDestWidth
rDCRect.Height(), // nDestHeight
rDIBRect.left, // SrcX
rDIBRect.top, // SrcY
rDIBRect.Width(), // wSrcWidth
rDIBRect.Height(), // wSrcHeight
lpDIBBits, // lpBits
(LPBITMAPINFO)lpDIBHdr, // lpBitsInfo
DIB_RGB_COLORS, // wUsage
SRCCOPY); // dwROP
::GlobalUnlock((HGLOBAL) m_hDIB);
// ... Reselect old palette
if (hOldPal != NULL)
{
::SelectPalette(pDC->m_hDC, hOldPal, TRUE);
}
return bSuccess;
}
LPSTR COXDIB::FindDIBBits(LPSTR lpDIBHeader/*=NULL*/)
{
ASSERT_VALID(this);
BOOL bWasLockedBefore=TRUE;
// if handle to DIB is invalid, return NULL
if (lpDIBHeader==NULL)
{
lpDIBHeader=(LPSTR)::GlobalLock((HGLOBAL)m_hDIB);
if(lpDIBHeader==NULL)
{
TRACE(_T("COXDIB::FindDIBBits: DIB not loaded, cannot find bits\n"));
return NULL;
}
bWasLockedBefore=FALSE;
}
LPSTR lpResult;
lpResult=(lpDIBHeader + *(LPDWORD)lpDIBHeader + GetPaletteSize(lpDIBHeader));
if(!bWasLockedBefore)
::GlobalUnlock((HGLOBAL)lpDIBHeader);
return lpResult;
}
CSize COXDIB::GetSize(LPSTR lpbi/*=NULL*/) const
{
ASSERT_VALID(this);
BOOL bOwnDIB=FALSE;
// if handle to DIB is invalid, return (0,0)
if (lpbi==NULL)
{
if (m_hDIB==NULL)
{
TRACE(_T("COXDIB::GetSize: DIB not loaded, returning (0,0)\n"));
return CSize(0,0);
}
else
{
lpbi=(LPSTR) ::GlobalLock((HGLOBAL) m_hDIB);
bOwnDIB=TRUE;
}
}
LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB
LPBITMAPCOREHEADER lpbmc; // pointer to an other-style DIB
CSize sResult;
// point to the header (whether Win 3.0 and old)
lpbmi=(LPBITMAPINFOHEADER)lpbi;
lpbmc=(LPBITMAPCOREHEADER)lpbi;
// return the DIB width if it is a Win 3.0 DIB
if (IS_WIN30_DIB(lpbi))
{
// Truncating long to int
ASSERT(lpbmi->biWidth < INT_MAX);
ASSERT(lpbmi->biHeight < INT_MAX);
sResult=CSize((int)lpbmi->biWidth, (int)lpbmi->biHeight);
}
else // it is an other-style DIB, so return its width
sResult=CSize(lpbmc->bcWidth, lpbmc->bcHeight);
if (bOwnDIB)
{
::GlobalUnlock((HGLOBAL) m_hDIB);
}
return sResult;
}
WORD COXDIB::GetPaletteSize(LPSTR lpDIBHeader/*=NULL*/) const
{
ASSERT_VALID(this);
BOOL bWasLockedBefore=TRUE;
// if handle to DIB is invalid, return 0
if (lpDIBHeader==NULL)
{
lpDIBHeader=(LPSTR)::GlobalLock((HGLOBAL)m_hDIB);
if(lpDIBHeader==NULL)
{
TRACE(_T("COXDIB::GetPaletteSize: DIB not loaded, returning 0\n"));
return 0;
}
bWasLockedBefore=FALSE;
}
// calculate the size required by the palette
BOOL bWin30;
bWin30=(IS_WIN30_DIB (lpDIBHeader));
WORD nResult=0;
if (bWin30)
nResult=(WORD)(GetNumColors(lpDIBHeader) * sizeof(RGBQUAD));
else
nResult=(WORD)(GetNumColors(lpDIBHeader) * sizeof(RGBTRIPLE));
if(!bWasLockedBefore)
::GlobalUnlock((HGLOBAL)lpDIBHeader);
return nResult;
}
CPalette* COXDIB::GetPalette() const
{
ASSERT_VALID(this);
return m_pPalette;
}
WORD COXDIB::GetNumBitsPerPixel(LPSTR lpbi) const
{
ASSERT_VALID(this);
BOOL bOwnDIB=FALSE;
// if handle to DIB is invalid, return 0
if (lpbi==NULL)
{
if (m_hDIB==NULL)
{
TRACE(_T("COXDIB::GetNumBitsPerPixel: DIB not loaded, returning 0\n"));
return 0;
}
else
{
lpbi=(LPSTR) ::GlobalLock((HGLOBAL) m_hDIB);
bOwnDIB=TRUE;
}
}
WORD wBitCount; // DIB bit count
// Calculate the number of bits per pixel for the DIB.
if (IS_WIN30_DIB(lpbi))
wBitCount=((LPBITMAPINFOHEADER)lpbi)->biBitCount;
else
wBitCount=((LPBITMAPCOREHEADER)lpbi)->bcBitCount;
if (bOwnDIB)
{
::GlobalUnlock((HGLOBAL) m_hDIB);
}
return wBitCount;
}
WORD COXDIB::GetNumColors(LPSTR lpbi) const
{
ASSERT_VALID(this);
BOOL bOwnDIB=FALSE;
// if handle to DIB is invalid, return 0
if (lpbi==NULL)
{
if (m_hDIB==NULL)
{
TRACE(_T("COXDIB::GetNumColors: DIB not loaded, returning 0\n"));
return 0;
}
else
{
lpbi=(LPSTR) ::GlobalLock((HGLOBAL) m_hDIB);
bOwnDIB=TRUE;
}
}
WORD wBitCount; // DIB bit count
// If this is a Windows-style DIB, the number of colors in the
// color table can be less than the number of bits per pixel
// allows for (i.e. lpbi->biClrUsed can be set to some value).
// If this is the case, return the appropriate value.
if (IS_WIN30_DIB(lpbi))
{
DWORD dwClrUsed;
dwClrUsed=((LPBITMAPINFOHEADER)lpbi)->biClrUsed;
if (dwClrUsed != 0)
{
if (bOwnDIB)
{
::GlobalUnlock((HGLOBAL) m_hDIB);
}
return (WORD)dwClrUsed;
}
}
// Calculate the number of colors in the color table based on
// the number of bits per pixel for the DIB.
if (IS_WIN30_DIB(lpbi))
wBitCount=((LPBITMAPINFOHEADER)lpbi)->biBitCount;
else
wBitCount=((LPBITMAPCOREHEADER)lpbi)->bcBitCount;
if (bOwnDIB)
{
::GlobalUnlock((HGLOBAL) m_hDIB);
}
// return number of colors based on bits per pixel
switch (wBitCount)
{
case 1:
return 2;
case 4:
return 16;
case 8:
return 256;
default:
return 0;
}
}
COXDIB::COXDIB(const COXDIB& DIBSrc)
:
m_hDIB(NULL),
m_pPalette(NULL)
{
ASSERT_VALID(this);
ASSERT_VALID(&DIBSrc);
TRACE(_T("COXDIB::COXDIB: Warning, copying bitmap\n"));
// Copy DIB memory
m_hDIB=CopyHandle(DIBSrc.m_hDIB);
if(m_hDIB!=NULL)
{
LPSTR pDIB=(LPSTR) ::GlobalLock((HGLOBAL) m_hDIB);
// Initialize the palette of the copy
InitPalette(pDIB);
::GlobalUnlock(m_hDIB);
}
}
COXDIB& COXDIB::operator=(const COXDIB& DIBSrc)
{
if(this==&DIBSrc)
return *this;
ASSERT_VALID(this);
ASSERT_VALID(&DIBSrc);
// Call COXDIB::operator=(HDIB hDIBSrc) to make a deep copy
*this=DIBSrc.m_hDIB;
// ... Make sure deep copy is made and succeeded
// ... The handles must be different, except when they are both NULL
ASSERT((m_hDIB != DIBSrc.m_hDIB) || ((m_hDIB==NULL) && (DIBSrc.m_hDIB==NULL)));
ASSERT_VALID(this);
return *this;
}
COXDIB& COXDIB::operator=(HDIB hDIBSrc)
{
ASSERT_VALID(this);
if (hDIBSrc != NULL)
{
LPSTR pDIBSrc=(LPSTR)::GlobalLock((HGLOBAL)hDIBSrc);
if (!IS_WIN30_DIB(pDIBSrc))
{
TRACE(_T("COXDIB::operator=: DIB is an other-style DIB (copy not supported)\n"));
ASSERT(FALSE);
}
else
{
// If this already contains a DIB, delete first
Empty();
// Copy DIB memory
m_hDIB=CopyHandle(hDIBSrc);
if (m_hDIB != NULL)
{
LPSTR pDIB=(LPSTR) ::GlobalLock((HGLOBAL) m_hDIB);
// Initialize the palette of the copy
InitPalette(pDIB);
::GlobalUnlock(m_hDIB);
}
}
::GlobalUnlock(hDIBSrc);
}
ASSERT_VALID(this);
return *this;
}
CBitmap* COXDIB::MakeBitmapFromDIB(CDC* pDC)
{
ASSERT_VALID(this);
ASSERT_VALID(pDC);
if (pDC==NULL)
return NULL;
BOOL bOwnDIB=FALSE;
// if handle to DIB is invalid, return 0
LPSTR lpbi=NULL; // pointer to packed-DIB
if (lpbi==NULL)
{
if (m_hDIB==NULL)
{
TRACE(_T("COXDIB::MakeBitmapFromDIB: DIB not loaded, returning 0\n"));
return 0;
}
else
{
lpbi=(LPSTR) ::GlobalLock((HGLOBAL) m_hDIB);
bOwnDIB=TRUE;
}
}
LPSTR lpDIBHdr, lpDIBBits;
HBITMAP hBitmap;
CPalette* pOldPal=NULL;
// Lock down the DIB, and get a pointer to the beginning of the bit buffer
lpDIBHdr =lpbi;
lpDIBBits=FindDIBBits(lpDIBHdr);
if (m_pPalette != NULL)
{
pOldPal=pDC->SelectPalette (m_pPalette, FALSE);
pDC->RealizePalette();
}
hBitmap=::CreateDIBitmap (pDC->GetSafeHdc(),
(LPBITMAPINFOHEADER)lpDIBHdr,
CBM_INIT,
lpDIBBits,
(LPBITMAPINFO) lpbi,
DIB_RGB_COLORS);
if (hBitmap==NULL)
{
TRACE(_T("COXDIB::MakeBitmapFromDIB: null bitmap\n"));
if (bOwnDIB)
{
::GlobalUnlock((HGLOBAL) m_hDIB);
}
return NULL; // untested error logic
}
if (pOldPal != NULL)
pDC->SelectPalette (pOldPal, FALSE);
CBitmap* pBitmap=new CBitmap;
pBitmap->Attach(hBitmap);
if (bOwnDIB)
{
::GlobalUnlock((HGLOBAL) m_hDIB);
}
return pBitmap;
}
BOOL COXDIB::SetPaletteUsage(CPalette* pPal, UINT wUsage)
{
PALETTEENTRY ape[256];
RGBQUAD FAR* pRgb;
WORD FAR* pw;
int nColors;
int n;
if (pPal==NULL)
pPal=CPalette::FromHandle((HPALETTE)GetStockObject(DEFAULT_PALETTE));
if (m_hDIB==NULL)
return FALSE;
PDIB pdib=(PDIB)::GlobalLock((HGLOBAL)m_hDIB);
nColors=DibNumColors(pdib);
if (nColors==3 && DibCompression(pdib)==BI_BITFIELDS)
nColors=0;
if (nColors>0)
{
pRgb=DibColors(pdib);
switch (wUsage)
{
//
// Set the DIB color table to palette indexes
//
case DIB_PAL_COLORS:
for (pw=(WORD FAR*)pRgb, n=0; n < nColors; n++, pw++)
*pw=(WORD)n;
break;
//
// Set the DIB color table to RGBQUADS
//
default:
case DIB_RGB_COLORS:
nColors=__min(nColors, 256);
pPal->GetPaletteEntries(0, nColors, ape);
for (n=0; n < nColors; n++)
{
pRgb[n].rgbRed =ape[n].peRed;
pRgb[n].rgbGreen =ape[n].peGreen;
pRgb[n].rgbBlue =ape[n].peBlue;
pRgb[n].rgbReserved=0;
}
break;
}
}
::GlobalUnlock((HGLOBAL)m_hDIB);
return TRUE;
}
BOOL COXDIB::CreateEmptyDIB(WORD wBitsPerPix, DWORD dwWidth, DWORD dwHeight)
{
PDIB lpbi;
DWORD dwSizeImage;
int i;
DWORD FAR* pdw;
dwSizeImage=dwHeight * WIDTHBYTES(dwWidth*wBitsPerPix);
lpbi=(PDIB)GlobalAllocPtr(GHND, sizeof(BITMAPINFOHEADER) + dwSizeImage + 1024);
if (lpbi==NULL)
return NULL;
InitBitmapInfoHeader(lpbi, dwWidth, dwHeight, wBitsPerPix);
pdw=(DWORD FAR*)((LPBYTE)lpbi + (int)lpbi->biSize);
for (i=0; i < (int)lpbi->biClrUsed / 16; i++)
{
*pdw++=0x00000000; // 0000 black
*pdw++=0x00800000; // 0001 dark red
*pdw++=0x00008000; // 0010 dark green
*pdw++=0x00808000; // 0011 mustard
*pdw++=0x00000080; // 0100 dark blue
*pdw++=0x00800080; // 0101 purple
*pdw++=0x00008080; // 0110 dark turquoise
*pdw++=0x00C0C0C0; // 1000 gray
*pdw++=0x00808080; // 0111 dark gray
*pdw++=0x00FF0000; // 1001 red
*pdw++=0x0000FF00; // 1010 green
*pdw++=0x00FFFF00; // 1011 yellow
*pdw++=0x000000FF; // 1100 blue
*pdw++=0x00FF00FF; // 1101 pink (magenta)
*pdw++=0x0000FFFF; // 1110 cyan
*pdw++=0x00FFFFFF; // 1111 white
}
// Discard existing DIB and assign newly created
Empty();
m_hDIB=(HDIB)GlobalPtrHandle(lpbi);
GlobalUnlockPtr(lpbi);
return TRUE;
}
BOOL COXDIB::ResizeDIB(DWORD dwWidth, DWORD dwHeight)
{
if (m_hDIB==NULL)
return FALSE;
PDIB pdibSource=(PDIB)::GlobalLock((HGLOBAL)m_hDIB);
WORD wBitPixel= GetNumBitsPerPixel((LPSTR)pdibSource);
int nBytePerPixel=wBitPixel / 8;
if (nBytePerPixel <= 0)
{
TRACE(_T("In COXDIB::ResizeDIB: Resizing only supported for 24 and 8 bit DIB's\n"));
::GlobalUnlock((HGLOBAL)m_hDIB);
return FALSE;
}
// Create a new empty destination memory block to hold the new resized DIB
// needs the same number of bits per pixel as the source DIB
// we're going to use some pointers to the DIB Bits, so lock down the memory block
DWORD dwSizeImage=dwHeight * (DWORD)((dwWidth * wBitPixel / 8 + 3)& ~3);
PDIB pDIBDest=(PDIB)GlobalAllocPtr(GHND,
sizeof(BITMAPINFOHEADER) + dwSizeImage + 1024);
if (pDIBDest==NULL)
{
TRACE(_T("COXDIB::ResizeDIB: Could not create an empty but allocated DIB\n"));
::GlobalUnlock((HGLOBAL)m_hDIB);
return FALSE;
}
// The destination DIB must have the same bitmap info header + palette as the source DIB
// so copy a (bitmap info + palette) memory block.
DWORD_PTR dwInfoAndPal=(BYTE*)DibPtr(pdibSource) - (BYTE*)pdibSource;
memcpy(pDIBDest, pdibSource, (size_t)dwInfoAndPal);
// because its a resize adjust the old values (stored in the new memory
// block by the memcpy) to the new size values
pDIBDest->biWidth = dwWidth;
pDIBDest->biHeight = dwHeight;
pDIBDest->biSizeImage = dwSizeImage;
// Assign and precalculate some values, to use in the formula
// P=2 * (D - S) with D is destination and S is Source
// When do we put a pixel extra or leave one out : (first version of formula)
// accumulator += P
// accumulator>S is the same as accumulator / S>1
// We spotted some rounding errors --> second formula
// (accumulator + sign(accumulator)S) / 2 * S>1=divresult
// then accumulator -= 2 * S * divresult;
DWORD dwSourceWidth=DibWidth(pdibSource);
DWORD dwSourceHeight=DibHeight(pdibSource);
DWORD dwOffsetWidth=2 * (dwWidth - dwSourceWidth);
DWORD dwOffsetHeight=2 * (dwHeight - dwSourceHeight);
WORD* WidthCopyArray=new WORD[dwSourceWidth];
WORD* pWCpy=WidthCopyArray;
int nTempTotal=0;
int nAccumulator=0;
int nDivResult=0;
// Compute the transformation array for one scanline
int Pixel;
int nSourceWidth=(int)dwSourceWidth;
int nDoubleSWidth=2 * nSourceWidth;
for(Pixel=0; Pixel < nSourceWidth; Pixel++)
{
// Per new pixel the acc must be incremented
nAccumulator += (int)dwOffsetWidth;
// Do we need to write a pixel
nDivResult=(nAccumulator + nSourceWidth * ((nAccumulator>0) ? 1 : -1)) / nDoubleSWidth;
ASSERT(nDivResult >=-1);
if (nDivResult != 0)
// we needed to write or delete a pixel, so adjust the acc to account for that
nAccumulator -= nDoubleSWidth * nDivResult;
// write the number of pixels to write in the correct place in the array and
// move the array pointer one place further
*(pWCpy++)=(WORD)(nDivResult + 1);
#ifdef _DEBUG
nTempTotal += nDivResult + 1;
#endif
}
#ifdef _DEBUG
ASSERT(dwWidth==(DWORD)nTempTotal);
#endif
WORD* HeightCopyArray=new WORD[dwSourceHeight];
WORD* pHCpy=HeightCopyArray;
// Compute the transformation array for the different scanlines (= height DIB)
nTempTotal=0;
nAccumulator=0;
int Scanline;
int nSourceHeight=(int)dwSourceHeight;
int nDoubleSHeight=2 * nSourceHeight;
for(Scanline=0; Scanline < nSourceHeight; Scanline++)
{
nAccumulator += (int)dwOffsetHeight;
nDivResult=(nAccumulator + nSourceHeight * ((nAccumulator>0) ? 1 : -1)) / nDoubleSHeight;
ASSERT(nDivResult >=-1);
if (nDivResult != 0)
nAccumulator -= nDoubleSHeight * nDivResult;
*(pHCpy++)=(WORD)(nDivResult + 1);
#ifdef _DEBUG
nTempTotal += nDivResult + 1;
#endif
}
ASSERT(dwHeight==(DWORD)nTempTotal);
// Reset the transformation array pointers to their begin
pHCpy=HeightCopyArray;
pWCpy=WidthCopyArray;
// Get pointers to begin of each bitmap
BYTE _huge* pSourceScanline=(BYTE _huge*)DibXY(pdibSource, 0, 0);
BYTE _huge* pWithinSourceScanline=pSourceScanline;
BYTE _huge* pDestScanline=(BYTE _huge*)DibXY(pDIBDest, 0, 0);
BYTE _huge* pWithinDestScanline=pDestScanline;
// Step through, resizing each pixel in each scan line
// to its required size
int OldScanline=0;
ULONG ul;
while(OldScanline < nSourceHeight)
{
// If equal to 0, this scanline disappears, so skip and proceed with next one
if (*pHCpy != 0)
{
DWORD nDup=0;
int OldPixel=0;
pWCpy=WidthCopyArray;
// iterate the pixels on one scanline
while(OldPixel < nSourceWidth)
{
nDup=*(pWCpy++);
// if the pixel we're dealing with has to be copied several times
while(nDup>0)
{
for(int j=0; j < nBytePerPixel; j++)
*(pWithinDestScanline++)=*(pWithinSourceScanline + j);
nDup--;
}
pWithinSourceScanline += nBytePerPixel;
OldPixel++;
}
ASSERT((pWithinDestScanline - pDestScanline)==(LONG)dwWidth * nBytePerPixel);
ul=(ULONG)(ULONG_PTR)pWithinDestScanline;
ul +=3;
ul >>=2;
ul <<=2;
pWithinDestScanline=(LPBYTE)ULongToPtr(ul);
DWORD dwAlignedScanLineLength=PtrToLong(pWithinDestScanline - pDestScanline);
nDup=1;
while(nDup < *pHCpy)
{
memcpy(pWithinDestScanline, pDestScanline, (size_t)dwAlignedScanLineLength);
pWithinDestScanline += dwAlignedScanLineLength;
nDup++;
}
// align the source and destination pointers on DWORD boundaries
ul=(ULONG)(ULONG_PTR)pWithinDestScanline;
ul +=3;
ul >>=2;
ul <<=2;
pWithinDestScanline=(LPBYTE)ULongToPtr(ul);
pDestScanline=pWithinDestScanline;
}
else
pWithinSourceScanline += nSourceWidth * nBytePerPixel;
// align the source and destination pointers on DWORD boundaries
ul=(ULONG)(ULONG_PTR)pWithinSourceScanline;
ul +=3;
ul >>=2;
ul <<=2;
pWithinSourceScanline=(LPBYTE)LongToPtr(ul);
OldScanline++;
pHCpy++;
}
delete[] WidthCopyArray;
delete[] HeightCopyArray;
::GlobalUnlock((HGLOBAL)m_hDIB);
GlobalUnlockPtr(pDIBDest);
// Release the old source DIB handle
// and assign the new DIB memory handle to this COXDIB object
::GlobalFree((HGLOBAL) m_hDIB);
m_hDIB=(HDIB)GlobalPtrHandle(pDIBDest);
return TRUE;
}
BOOL COXDIB::GetHalfTonePalette(CPalette* pPalette)
{
ASSERT(pPalette != NULL);
BOOL bResult(FALSE);
CDC* pDC=CWnd::GetDesktopWindow()->GetDC();
if (pDC==NULL)
{
TRACE(_T("COXDIB::GetHalfTonePalette: Could not allocate a DC for the desktopwindow\n"));
return FALSE;
}
// Find out the number of palette entries on this device.
int nColors=pDC->GetDeviceCaps(SIZEPALETTE);
// For non-palette devices, we'll use the # of system
// colors for our palette size.
if (nColors==0)
nColors=pDC->GetDeviceCaps(NUMCOLORS);
if (nColors < 256)
{
CWnd::GetDesktopWindow()->ReleaseDC(pDC);
return FALSE;
}
#ifdef WIN32
bResult=pPalette->CreateHalftonePalette(pDC);
#else
HANDLE hLogPal; // handle to a logical palette
LPLOGPALETTE lpLogPal; // pointer to a logical palette
// Allocate room for the palette and lock it.
hLogPal=::GlobalAlloc(GHND, sizeof(LOGPALETTE)+sizeof(PALETTEENTRY)*256);
// if not enough memory, clean up and return NULL
if (hLogPal==NULL)
{
TRACE(_T("COXDIB::GetHalfTonePalette: Not enough memory for logical palette\n"));
CWnd::GetDesktopWindow()->ReleaseDC(pDC);
return FALSE;
}
// get a pointer to the logical palette
lpLogPal=(LPLOGPALETTE) ::GlobalLock((HGLOBAL) hLogPal);
// set version and number of palette entries
lpLogPal->palVersion=PALVERSION;
lpLogPal->palNumEntries=(WORD)256;
// Copy the Halftone palette into our logical palette
memcpy(lpLogPal->palPalEntry, aHalfTonePalette, sizeof(aHalfTonePalette));
// Go ahead and create the palette. Once it's created,
// we no longer need the LOGPALETTE, so free it.
// -- create the palette and get handle to it
bResult=pPalette->CreatePalette(lpLogPal);
::GlobalUnlock((HGLOBAL) hLogPal);
::GlobalFree((HGLOBAL) hLogPal);
#endif
CWnd::GetDesktopWindow()->ReleaseDC(pDC);
return bResult;
}
#ifndef NO_DITHER
BOOL COXDIB::HalfToneDitherDIB()
{
if (m_hDIB==NULL)
return FALSE;
PDIB pdibSource=(PDIB)::GlobalLock((HGLOBAL)m_hDIB);
// Only work on 24-bit sources
if(GetNumBitsPerPixel((LPSTR)pdibSource) < 24)
{
TRACE(_T("COXDIB::SetHalfTone: Setting halftone only works for 24 bit images\n"));
::GlobalUnlock((HGLOBAL)m_hDIB);
return FALSE;
}
CPalette* pHalfTonePal=new CPalette;
if (!GetHalfTonePalette(pHalfTonePal))
{
TRACE(_T("COXDIB::SetHalfTone: Could not create a halftone palette\n"));
::GlobalUnlock((HGLOBAL)m_hDIB);
delete pHalfTonePal;
return FALSE;
}
BOOL bWinGHalfTone=FALSE;
// test whether the halftone palette is a WING halftone palette (Win95) or
// a Win NT halftone palette
PALETTEENTRY PaletteEntry;
pHalfTonePal->GetPaletteEntries(1, 1, &PaletteEntry);
if (NT_REF != RGB(PaletteEntry.peRed, PaletteEntry.peGreen, PaletteEntry.peBlue))
bWinGHalfTone=TRUE;
//Create an 8-bit DIB to halftone to
COXDIB* pHalfToneDIB=new COXDIB;
if (!pHalfToneDIB->CreateEmptyDIB(8, DibWidth(pdibSource), DibHeight(pdibSource)))
{
TRACE(_T("In COXDIB::SetHalfTone(): Could not create an empty but allocated DIB\n"));
::GlobalUnlock((HGLOBAL)m_hDIB);
delete pHalfToneDIB;
delete pHalfTonePal;
return FALSE;
}
int Scanline;
// Fill in the DIB color table with the halftone palette
pHalfToneDIB->SetPaletteUsage(pHalfTonePal, DIB_RGB_COLORS);
PDIB pDIBDest=(PDIB)::GlobalLock((HGLOBAL)(pHalfToneDIB->m_hDIB));
// Step through, converting each pixel in each scan line
// to the nearest halftone match
for(Scanline=0; Scanline < (int)DibHeight(pdibSource); Scanline++)
{
BYTE _huge* pSourceScanline=(BYTE _huge*)DibXY(pdibSource, 0, Scanline);
BYTE _huge* pDestScanline=(BYTE _huge*)DibXY(pDIBDest, 0, Scanline);
int Pixel;
for(Pixel=0; Pixel < (int)DibWidth(pdibSource); Pixel++)
{
// This is the meat of the halftoning algorithm:
// Convert an RGB into an index into the halftone palette.
// First, extract the raw RGB information
int Red=pSourceScanline[Pixel * 3 + 2];
int Green=pSourceScanline[Pixel * 3 + 1];
int Blue=pSourceScanline[Pixel * 3];
// Now, look up each value in the halftone matrix
// using an 8x8 ordered dither.
BYTE RedTemp=(BYTE)(aDividedBy51[Red] +
(aModulo51[Red]>aHalftone8x8[(Pixel%8)* 8 + Scanline%8]));
BYTE GreenTemp=(BYTE)(aDividedBy51[(BYTE)Green] +
(aModulo51[Green]>aHalftone8x8[(Pixel%8)*8 + Scanline%8]));
BYTE BlueTemp=(BYTE)(aDividedBy51[(BYTE)Blue] +
(aModulo51[Blue]>aHalftone8x8[(Pixel%8)*8 + Scanline%8]));
// Recombine the halftoned RGB values into a palette index
BYTE PaletteIndex=(BYTE)(RedTemp + aTimes6[GreenTemp] + aTimes36[BlueTemp]);
if (!bWinGHalfTone)
pDestScanline[Pixel]=PaletteIndex;
else
// And translate through the WinG Halftone Palette
// translation vector to give the correct value.
pDestScanline[Pixel]=aWinGHalftoneTranslation[PaletteIndex];
}
}
::GlobalUnlock((HGLOBAL)m_hDIB);
::GlobalUnlock((HGLOBAL)(pHalfToneDIB->m_hDIB));
Empty();
m_hDIB=pHalfToneDIB->m_hDIB;
m_pPalette=pHalfTonePal;
// Clean up temporary DIB. First reset his HDIB handle, because we already assigned it to
// this COXDib object, otherwise the destructor would free and destroy it.
pHalfToneDIB->m_hDIB=NULL;
delete pHalfToneDIB;
return TRUE;
}
#endif // NO_DITHER
void COXDIB::InitBitmapInfoHeader (PDIB lpBmInfoHdr,
DWORD dwWidth,
DWORD dwHeight,
WORD nBPP)
{
#ifdef WIN32
memset (lpBmInfoHdr, 0, sizeof (BITMAPINFOHEADER));
#else
_fmemset (lpBmInfoHdr, 0, sizeof (BITMAPINFOHEADER));
#endif
lpBmInfoHdr->biSize = sizeof (BITMAPINFOHEADER);
lpBmInfoHdr->biWidth = dwWidth;
lpBmInfoHdr->biHeight = dwHeight;
lpBmInfoHdr->biPlanes = 1;
lpBmInfoHdr->biCompression =BI_RGB;
if (nBPP <= 1)
nBPP=1;
else if (nBPP <= 4)
{
nBPP=4;
lpBmInfoHdr->biClrUsed=16;
}
else if (nBPP <= 8)
{
nBPP=8;
lpBmInfoHdr->biClrUsed=256;
}
else
nBPP=24;
lpBmInfoHdr->biBitCount =nBPP;
lpBmInfoHdr->biSizeImage=WIDTHBYTES (dwWidth * nBPP) * dwHeight;
}
HDIB COXDIB::BitmapToDIB(HBITMAP hBitmap, CPalette* pPal /*=NULL */)
{
BITMAP Bitmap;
BITMAPINFOHEADER bmInfoHdr;
LPBITMAPINFOHEADER lpbmInfoHdr;
LPSTR lpBits;
HDC hMemDC;
CDC* pDC=NULL;
CPalette* pOldPal=NULL;
// Do some setup -- make sure the Bitmap passed in is valid,
// get info on the bitmap (like its height, width, etc.),
// then setup a BITMAPINFOHEADER.
if (!hBitmap)
return NULL;
if (!::GetObject (hBitmap, sizeof (Bitmap), (LPSTR) &Bitmap))
return NULL;
InitBitmapInfoHeader(&bmInfoHdr, Bitmap.bmWidth, Bitmap.bmHeight,
WORD(Bitmap.bmPlanes*Bitmap.bmBitsPixel));
// If DIB was already allocated, dealocate first
Empty();
// Now allocate memory for the DIB. Then, set the BITMAPINFOHEADER
// into this memory, and find out where the bitmap bits go.
m_hDIB=(HDIB)::GlobalAlloc (GHND, sizeof (BITMAPINFOHEADER) +
GetPaletteSize((LPSTR) &bmInfoHdr) + bmInfoHdr.biSizeImage);
if (!m_hDIB)
return NULL;
lpbmInfoHdr=(LPBITMAPINFOHEADER) ::GlobalLock((HGLOBAL) m_hDIB);
*lpbmInfoHdr=bmInfoHdr;
lpBits =FindDIBBits ((LPSTR) lpbmInfoHdr);
// Now, we need a DC to hold our bitmap. If the app passed us
// a palette, it should be selected into the DC.
hMemDC=GetDC (NULL);
pDC=CDC::FromHandle(hMemDC);
if (pPal != NULL)
{
pOldPal=pDC->SelectPalette (pPal, FALSE);
pDC->RealizePalette();
}
// We're finally ready to get the DIB. Call the driver and let
// it party on our bitmap. It will fill in the color table,
// and bitmap bits of our global memory block.
if (!::GetDIBits (hMemDC,hBitmap,0,Bitmap.bmHeight,lpBits,
(LPBITMAPINFO) lpbmInfoHdr,DIB_RGB_COLORS))
{
::GlobalUnlock (m_hDIB);
::GlobalFree (m_hDIB);
m_hDIB=NULL;
}
else
::GlobalUnlock (m_hDIB);
// Finally, clean up and return.
if (pOldPal != NULL)
pDC->SelectPalette (pOldPal, FALSE);
// Copy Palette
if (pPal != NULL)
{
SetPaletteUsage(pPal, DIB_RGB_COLORS);
LPSTR lpDIB=(LPSTR) ::GlobalLock((HGLOBAL) m_hDIB);
InitPalette(lpDIB);
::GlobalUnlock(m_hDIB);
}
::ReleaseDC (NULL, hMemDC);
return m_hDIB;
}
#ifdef _WIN32
HDIB COXDIB::IconToDIB(HICON hIcon, CSize sizeIcon, CPalette* pPal /*=NULL */)
{
// If DIB was already allocated, dealocate first
Empty();
CDC SrcDC;
VERIFY(SrcDC.CreateDC(_T("DISPLAY"),NULL,NULL,NULL));
CDC memDC;
CBitmap bitmap;
VERIFY(memDC.CreateCompatibleDC(&SrcDC));
VERIFY(bitmap.CreateCompatibleBitmap(&SrcDC,sizeIcon.cx,sizeIcon.cy));
CBitmap* pOldBitmap=memDC.SelectObject(&bitmap);
VERIFY(::DrawIconEx(
memDC.GetSafeHdc(),0,0,hIcon,sizeIcon.cx,sizeIcon.cy,0,NULL,DI_NORMAL));
memDC.SelectObject(pOldBitmap);
SrcDC.DeleteDC();
memDC.DeleteDC();
return BitmapToDIB((HBITMAP)bitmap,pPal);
}
#endif
BOOL COXDIB::Write(CArchive& ar)
{
ASSERT_VALID(this);
BITMAPFILEHEADER bmfHdr; // Header for Bitmap file
LPBITMAPINFOHEADER lpBI; // Pointer to DIB info structure
DWORD dwDIBSize;
if (m_hDIB==NULL)
{
TRACE(_T("COXDIB::Write: DIB not loaded, cannot save\n"));
return FALSE;
}
// Get a pointer to the DIB memory, the first of which contains
// a BITMAPINFO structure
lpBI=(LPBITMAPINFOHEADER) ::GlobalLock((HGLOBAL) m_hDIB);
if (lpBI==NULL)
{
TRACE(_T("COXDIB::Write : Out of memory\n"));
return FALSE;
}
if (!IS_WIN30_DIB(lpBI))
{
::GlobalUnlock((HGLOBAL) m_hDIB);
TRACE(_T("COXDIB::Write : DIB is an other-style DIB (save not supported)\n"));
return FALSE;
}
// Fill in the fields of the file header
// Fill in file type (first 2 bytes must be "BM" for a bitmap)
bmfHdr.bfType=DIB_HEADER_MARKER; // "BM"
// Calculating the size of the DIB is a bit tricky (if we want to
// do it right). The easiest way to do this is to call GlobalSize()
// on our global handle, but since the size of our global memory may have
// been padded a few bytes, we may end up writing out a few too
// many bytes to the file (which may cause problems with some apps).
//
// So, instead let's calculate the size manually (if we can)
//
// First, find size of header plus size of color table. Since the
// first DWORD in both BITMAPINFOHEADER and BITMAPCOREHEADER conains
// the size of the structure, let's use this.
dwDIBSize=*(LPDWORD)lpBI + GetPaletteSize((LPSTR)lpBI); // Partial Calculation
// Now calculate the size of the image
if ((lpBI->biCompression==BI_RLE8) || (lpBI->biCompression==BI_RLE4))
{
// It's an RLE bitmap, we can't calculate size, so trust the
// biSizeImage field
dwDIBSize += lpBI->biSizeImage;
}
else
{
DWORD dwBmBitsSize; // Size of Bitmap Bits only
// It's not RLE, so size is Width (DWORD aligned) * Height
dwBmBitsSize=WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) * lpBI->biHeight;
dwDIBSize += dwBmBitsSize;
// Now, since we have calculated the correct size, why don't we
// fill in the biSizeImage field (this will fix any .BMP files which
// have this field incorrect).
lpBI->biSizeImage=dwBmBitsSize;
}
// Calculate the file size by adding the DIB size to sizeof(BITMAPFILEHEADER)
bmfHdr.bfSize=dwDIBSize + sizeof(BITMAPFILEHEADER);
bmfHdr.bfReserved1=0;
bmfHdr.bfReserved2=0;
// Now, calculate the offset the actual bitmap bits will be in
// the file -- It's the Bitmap file header plus the DIB header,
// plus the size of the color table.
bmfHdr.bfOffBits=(DWORD)sizeof(BITMAPFILEHEADER) + lpBI->biSize
+ GetPaletteSize((LPSTR)lpBI);
TRY
{
// Write the file header
ar.Write((LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER));
//
// Write the DIB header and the bits
//
WriteHuge(ar, lpBI, dwDIBSize);
}
CATCH (CFileException, e)
{
::GlobalUnlock((HGLOBAL) m_hDIB);
THROW_LAST();
}
END_CATCH
::GlobalUnlock((HGLOBAL) m_hDIB);
return TRUE;
}
BOOL COXDIB::Write(LPCTSTR pszPath)
{
CFile file;
CFileException fe;
if(!file.Open(pszPath,
CFile::modeCreate|CFile::modeReadWrite|CFile::shareExclusive,&fe))
{
TRACE1("COXDIB::Write : Could not open DIB file : %s\n", pszPath);
return FALSE;
}
if (!Write(&file))
{
file.Abort(); // will not throw an exception
TRACE1("COXDIB::Write : Error writing file : %s\n", pszPath);
return FALSE;
}
return TRUE;
}
BOOL COXDIB::Write(CFile* pDIBFile, BOOL bCloseFile/*=TRUE*/)
{
BOOL bSuccess=FALSE;
TRY
{
CArchive ar(pDIBFile, CArchive::store);
bSuccess=Write(ar);
ar.Close();
if(bCloseFile)
pDIBFile->Close();
}
CATCH (CException, eSave)
{
TRACE(_T("COXDIB::Write : Catching file exception while writing file\n"));
return FALSE;
}
END_CATCH
return bSuccess;
}
// save as JPEG file
#ifdef OXDIB_SUPPORTJPEG
BOOL COXDIB::WriteJPEG(LPCTSTR pszPath)
{
DWORD LastError=0;
if(IsEmpty())
return FALSE;
BOOL bSuccess=FALSE;
// mem file for conversion purpose
CMemFile tmpBMPFile;
CArchive ar(&tmpBMPFile,CArchive::store);
bSuccess=Write(ar);
ar.Close();
if(!bSuccess)
return FALSE;
// go to the beginning of the file
tmpBMPFile.SeekToBegin();
// create bitmap file
COXBMPFile bmpFile(&tmpBMPFile);
// create empty JPEG file
COXJPEGFile jpgFile(pszPath);
LastError=GetLastError();
if(!ConvertDIBtoJPEG(&bmpFile,&jpgFile))
return FALSE;
SetLastError(LastError);
return TRUE;
}
BOOL COXDIB::WriteJPEG(CFile* pFile)
{
ASSERT(pFile!=NULL);
DWORD LastError=0;
if(IsEmpty())
return FALSE;
BOOL bSuccess=FALSE;
// mem file for conversion purpose
CMemFile tmpBMPFile;
CArchive ar(&tmpBMPFile,CArchive::store);
bSuccess=Write(ar);
ar.Close();
if(!bSuccess)
return FALSE;
// go to the beginning of the file
tmpBMPFile.SeekToBegin();
// create bitmap file
COXBMPFile bmpFile(&tmpBMPFile);
// create empty JPEG file
COXJPEGFile jpgFile(pFile);
LastError=GetLastError();
if(!ConvertDIBtoJPEG(&bmpFile,&jpgFile))
return FALSE;
SetLastError(LastError);
return TRUE;
}
#endif
PDIB COXDIB::ReadBitmapInfo(CArchive& ar)
{
BITMAPFILEHEADER bmfHeader;
PDIB pdibInfo=NULL;
// Go read the DIB file header and check if it's valid.
if ((ar.Read((LPSTR)&bmfHeader, sizeof(bmfHeader)) !=
sizeof(bmfHeader)) || (bmfHeader.bfType != DIB_HEADER_MARKER))
{
TRACE(_T("COXDIB::ReadBitmapInfo : Invalid bitmap header\n"));
return NULL;
}
// Go read the size of the struct that follows the bitmapfileheader
DWORD dwSize;
if (ar.Read(&dwSize, sizeof(dwSize)) != sizeof(dwSize))
{
TRACE(_T("COXDIB::ReadBitmapInfo : Invalid bitmap size\n"));
return NULL;
}
// what type of bitmap info is this?
BITMAPCOREHEADER bmCoreHdr;
BITMAPINFOHEADER bminfo;
switch (dwSize)
{
default:
case sizeof(BITMAPINFOHEADER):
{
// Go read the DIB bitmap info header
BYTE* pByte=(BYTE*)&bminfo;
// allready read the size so skip it
pByte=pByte + sizeof(DWORD);
if (ar.Read(pByte, sizeof(bminfo) - sizeof(DWORD)) != (sizeof(bminfo) - sizeof(DWORD)))
{
TRACE(_T("COXDIB::ReadBitmapInfo : Invalid bitmap info\n"));
return NULL;
}
bminfo.biSize=dwSize;
}
break;
case sizeof(BITMAPCOREHEADER):
{
// Go read the DIB bitmap info header
BYTE* pByte=(BYTE*)&bmCoreHdr;
// allready read the size so skip it
pByte=pByte + sizeof(DWORD);
if (ar.Read(pByte, sizeof(bmCoreHdr) - sizeof(DWORD)) != (sizeof(bmCoreHdr)-sizeof(DWORD)))
{
TRACE(_T("COXDIB::ReadBitmapInfo : Invalid bitmap core header\n"));
return NULL;
}
bminfo.biSize =sizeof(BITMAPINFOHEADER);
bminfo.biWidth =(DWORD)bmCoreHdr.bcWidth;
bminfo.biHeight =(DWORD)bmCoreHdr.bcHeight;
bminfo.biPlanes = (WORD)bmCoreHdr.bcPlanes;
bminfo.biBitCount = (WORD)bmCoreHdr.bcBitCount;
bminfo.biCompression =BI_RGB;
bminfo.biSizeImage =0;
bminfo.biXPelsPerMeter =0;
bminfo.biYPelsPerMeter =0;
bminfo.biClrUsed =0;
bminfo.biClrImportant =0;
}
break;
}
int nNumColors=DibNumColors(&bminfo);
FixBitmapInfo(&bminfo);
pdibInfo=(PDIB)GlobalAllocPtr(GMEM_MOVEABLE,(LONG)bminfo.biSize +
nNumColors * sizeof(RGBQUAD));
if (pdibInfo==NULL)
return NULL;
// assign contents of bitmap info to dibinfo
*pdibInfo=bminfo;
RGBQUAD FAR* pRgb;
pRgb=DibColors(pdibInfo);
if (nNumColors != 0)
{
if (dwSize==sizeof(BITMAPCOREHEADER))
{
/*
* convert a old color table (3 byte entries) to a new
* color table (4 byte entries)
*/
if (ar.Read((LPVOID)pRgb, nNumColors * sizeof(RGBTRIPLE)) !=
(nNumColors * sizeof(RGBTRIPLE)))
{
TRACE(_T("COXDIB::ReadBitmapInfo : Invalid RGB color table\n"));
GlobalFreePtr(pdibInfo);
return NULL;
}
for (int i=nNumColors - 1; i >= 0; i--)
{
RGBQUAD rgb;
rgb.rgbRed =((RGBTRIPLE FAR*)pRgb)[i].rgbtRed;
rgb.rgbBlue =((RGBTRIPLE FAR*)pRgb)[i].rgbtBlue;
rgb.rgbGreen =((RGBTRIPLE FAR*)pRgb)[i].rgbtGreen;
rgb.rgbReserved=(BYTE)0;
pRgb[i]=rgb;
}
}
else
{
if (ar.Read((LPVOID)pRgb, nNumColors * sizeof(RGBQUAD)) != (nNumColors * sizeof(RGBQUAD)))
{
TRACE(_T("COXDIB::ReadBitmapInfo : Invalid RGB color table\n"));
GlobalFreePtr(pdibInfo);
return NULL;
}
}
}
if (bmfHeader.bfOffBits != 0L)
{
TRACE(_T("COXDIB::ReadBitmapInfo : BMP with offset bits\n"));
}
return pdibInfo;
}
BOOL COXDIB::Read(CArchive& ar)
{
// If DIB was already allocated, dealocate first
Empty();
PDIB pdib=ReadBitmapInfo(ar);
if (pdib==NULL)
{
TRACE(_T("COXDIB::Read : Could not read bitmap info\n"));
return FALSE;
}
// How much memory do we need to hold the DIB
DWORD dwBits=pdib->biSizeImage;
DWORD dwLen =pdib->biSize + DibPaletteSize(pdib) + dwBits;
// Can we get more memory?
LPVOID pGlobal=GlobalReAllocPtr(pdib, dwLen, 0);
if (pGlobal==NULL)
{
GlobalFreePtr(pdib);
pdib=NULL;
}
else
{
pdib=(PDIB)pGlobal;
m_hDIB=(HDIB)GlobalPtrHandle(pdib);
}
if (pdib != NULL)
{
// Go read the bits.
if (ReadHuge(ar, (LPBYTE)pdib + (UINT)pdib->biSize + DibPaletteSize(pdib), dwBits) != dwBits)
{
GlobalFreePtr(pdib);
m_hDIB=NULL;
TRACE(_T("COXDIB::Read : Invalid bitmap size\n"));
return FALSE;
}
// Initialize the palette
if (!InitPalette((LPSTR)pdib))
return FALSE;
GlobalUnlockPtr(pdib);
}
else
{
TRACE(_T("COXDIB::Read : Invalid bitmap memory block\n"));
Empty();
return FALSE;
}
ASSERT_VALID(this);
return TRUE;
}
BOOL COXDIB::Read(LPCTSTR pszPath)
{
CFile file;
CFileException fe;
if(!file.Open(pszPath,CFile::modeRead|CFile::shareDenyWrite,&fe))
{
TRACE1("COXDIB::Read : Could not open DIB file : %s\n", pszPath);
return FALSE;
}
if(!Read(&file))
{
file.Abort(); // will not throw an exception
TRACE1("COXDIB::Read : Error reading file : %s\n", pszPath);
return FALSE;
}
return TRUE;
}
BOOL COXDIB::Read(CFile* pDIBFile)
{
// replace calls to Serialize with Read function
BOOL bSuccess=FALSE;
TRY
{
CArchive ar(pDIBFile, CArchive::load);
bSuccess=Read(ar);
ar.Close();
}
CATCH (CFileException, eLoad)
{
TRACE(_T("COXDIB::Read : Catching file exception while reading file\n"));
return FALSE;
}
END_CATCH
return bSuccess;
}
// load JPEG file
#ifdef OXDIB_SUPPORTJPEG
BOOL COXDIB::ReadJPEG(LPCTSTR pszPath)
{
// mem file for conversion purpose
CMemFile tmpBMPFile;
// create bitmap file
COXBMPFile bmpFile(&tmpBMPFile);
// create JPEG file object
COXJPEGFile jpgFile(pszPath);
if(!ConvertJPEGtoDIB(&jpgFile,&bmpFile))
return FALSE;
tmpBMPFile.SeekToBegin();
return Read(&tmpBMPFile);
}
BOOL COXDIB::ReadJPEG(CFile* pFile)
{
ASSERT(pFile!=NULL);
// mem file for conversion purpose
CMemFile tmpBMPFile;
// create bitmap file
COXBMPFile bmpFile(&tmpBMPFile);
// create JPEG file object
COXJPEGFile jpgFile(pFile);
if(!ConvertJPEGtoDIB(&jpgFile,&bmpFile))
return FALSE;
tmpBMPFile.SeekToBegin();
return Read(&tmpBMPFile);
}
#endif // #ifdef OXDIB_SUPPORTJPEG
void COXDIB::Serialize(CArchive& ar)
{
if (ar.IsStoring())
Write(ar);
else
Read(ar);
}
// static functions for JPEG/DIB conversions
#ifdef OXDIB_SUPPORTJPEG
BOOL COXDIB::ConvertDIBtoJPEG(LPCTSTR pszDIBPath, LPCTSTR pszJPEGPath)
{
COXDIB dib;
if(!dib.Read(pszDIBPath))
return FALSE;
if(dib.IsEmpty())
return FALSE;
return dib.WriteJPEG(pszJPEGPath);
}
BOOL COXDIB::ConvertDIBtoJPEG(COXBMPFile* pDIBFile, COXJPEGFile* pJPEGFile)
{
ASSERT(pDIBFile!=NULL);
ASSERT(pJPEGFile!=NULL);
// object responsible for conversion
COXJPEGCompressor JCompr;
short nReturn(1);
TCHAR ErrorBuffer[SIZE_ERROR_BUF];
TRY
{
// the only line of code we need to convert bitmap to JPEG
nReturn=JCompr.DoCompress(pDIBFile,pJPEGFile);
if(nReturn==2)
{
TRACE(JCompr.GetWarningMessages());
}
}
CATCH(COXJPEGException, e)
{
// if something went wrong then notify about it
e->GetErrorMessage(ErrorBuffer, SIZE_ERROR_BUF);
CString sErrorMessage=_T("COXDIB::ConvertDIBtoJPEG: Exception ");
sErrorMessage+=ErrorBuffer;
TRACE(sErrorMessage);
}
END_CATCH
return (nReturn==0);
}
BOOL COXDIB::ConvertJPEGtoDIB(LPCTSTR pszJPEGPath, LPCTSTR pszDIBPath)
{
COXDIB dib;
if(!dib.ReadJPEG(pszJPEGPath))
return FALSE;
if(dib.IsEmpty())
return FALSE;
return dib.Write(pszDIBPath);
}
BOOL COXDIB::ConvertJPEGtoDIB(COXJPEGFile* pJPEGFile, COXBMPFile* pDIBFile)
{
ASSERT(pJPEGFile!=NULL);
ASSERT(pDIBFile!=NULL);
// object responsible for conversion
COXJPEGDecompressor JDecompr;
short nReturn(1);
TCHAR ErrorBuffer[SIZE_ERROR_BUF];
TRY
{
// the only line of code that we need to decompress JPEG to bitmap file
nReturn=JDecompr.DoDecompress(pJPEGFile,pDIBFile);
if(nReturn==2)
{
TRACE(JDecompr.GetWarningMessages());
}
}
CATCH(COXJPEGException, e)
{
// if something went wrong then notify about it
e->GetErrorMessage(ErrorBuffer, SIZE_ERROR_BUF);
CString sErrorMessage=_T("COXDIB::ConvertJPEGtoDIB: Exception ");
sErrorMessage+=ErrorBuffer;
TRACE(sErrorMessage);
}
END_CATCH
if(nReturn!=0)
return FALSE;
return TRUE;
}
#endif
BOOL COXDIB::Rotate(int nAngleDegree, BOOL bFlipHorz/*=FALSE*/,
BOOL bFlipVert/*=FALSE*/)
{
if((nAngleDegree%90)!=0)
{
TRACE(_T("COXDIB::Rotate: support only 90 degrees rotation step\n"));
return FALSE;
}
if(nAngleDegree<0)
{
nAngleDegree+=(nAngleDegree/360)*360;
nAngleDegree=360-nAngleDegree;
}
else
nAngleDegree-=(nAngleDegree/360)*360;
if(IsEmpty())
return FALSE;
if(nAngleDegree==0 && !bFlipVert && !bFlipHorz)
return TRUE;
COXDIB dibCopy=*this;
Empty();
LPSTR lpDIBSrc=(LPSTR)::GlobalLock((HGLOBAL)dibCopy.m_hDIB);
int nWidthSrc=dibCopy.GetSize().cx;
int nHeightSrc=dibCopy.GetSize().cy;
WORD nBitsPerPixel=dibCopy.GetNumBitsPerPixel(lpDIBSrc);
// calculate resulting size of image
int nWidthDest=((nAngleDegree%180)==0 ? nWidthSrc : nHeightSrc);
int nHeightDest=((nAngleDegree%180)==0 ? nHeightSrc : nWidthSrc);
// recreate DIB
if(!CreateEmptyDIB(nBitsPerPixel,nWidthDest,nHeightDest))
{
::GlobalUnlock((HGLOBAL)dibCopy.m_hDIB);
*this=dibCopy;
TRACE(_T("COXDIB::Rotate: failed to create empty DIB\n"));
return FALSE;
}
LPSTR lpDIBDest=(LPSTR)::GlobalLock((HGLOBAL)m_hDIB);
// copy image and rotate pixels
//
LPSTR lpDIBBitsSrc=dibCopy.FindDIBBits(lpDIBSrc);
LPSTR lpDIBBitsDest=FindDIBBits(lpDIBDest);
int nWidthBytesSrc=WIDTHBYTES(nWidthSrc*(DWORD)nBitsPerPixel);
int nWidthBytesDest=WIDTHBYTES(nWidthDest*(DWORD)nBitsPerPixel);
// mask for monochrome DIB
BYTE BitMask=0x80;
// masks for 16-color DIB
BYTE LoMask=0x0F;
BYTE HiMask=0xF0;
// copy color table for non true-color images
if(nBitsPerPixel<=8)
{
// Copy source DIB's color table to destination DIB
RGBQUAD* lpSrcColor=(RGBQUAD*)(lpDIBSrc+(sizeof(BITMAPINFOHEADER)));
RGBQUAD* lpDestColor=(RGBQUAD*)(lpDIBDest+(sizeof(BITMAPINFOHEADER)));
WORD wNumColors=dibCopy.GetNumColors(lpDIBSrc);
for(int nIndex=0; nIndex<(int)wNumColors; nIndex++)
*lpDestColor++=*lpSrcColor++;
// Initialize the palette of the copy
InitPalette(lpDIBSrc);
}
int nBytesPerPixel=(nBitsPerPixel>=8 ? (nBitsPerPixel>>3) : 1);
int nPixelsPerByte=(nBitsPerPixel>=8 ? 1 : 8/nBitsPerPixel);
for(int nRow=0; nRow<nHeightSrc; nRow++)
{
for(int nCol=0; nCol<nWidthSrc; nCol++)
{
for(int nIndex=0; nIndex<nBytesPerPixel; nIndex++)
{
int nPositionSrc=nRow*nWidthBytesSrc+
(nCol/nPixelsPerByte)*nBytesPerPixel+nIndex;
int nPositionDest=nPositionSrc;
switch(nAngleDegree)
{
case 0:
nPositionDest=
(bFlipHorz ? nHeightDest-1-nRow : nRow)*nWidthBytesDest+
((bFlipVert ? nWidthDest-1-nCol : nCol)/nPixelsPerByte)*
nBytesPerPixel+nIndex;
break;
case 90:
nPositionDest=
(bFlipHorz ? nCol : nHeightDest-1-nCol)*nWidthBytesDest+
((bFlipVert ? nWidthDest-1-nRow : nRow)/nPixelsPerByte)*
nBytesPerPixel+nIndex;
break;
case 180:
nPositionDest=
(bFlipHorz ? nRow : nHeightDest-1-nRow)*nWidthBytesDest+
((bFlipVert ? nCol : nWidthDest-1-nCol)/nPixelsPerByte)*
nBytesPerPixel+nIndex;
break;
case 270:
nPositionDest=
(bFlipHorz ? nHeightDest-1-nCol : nCol)*nWidthBytesDest+
((bFlipVert ? nRow : nWidthDest-1-nRow)/nPixelsPerByte)*
nBytesPerPixel+nIndex;
break;
default:
ASSERT(FALSE);
}
// flag that specifies that bits in the byte should be flipped
// for monochrome or 16-color bitmaps
BOOL bFlip=bFlipVert;
switch(nBitsPerPixel)
{
// monochrome bitmap
case 1:
{
// Get the source byte
BYTE srcByte=lpDIBBitsSrc[nPositionSrc];
// Get the destination byte
BYTE destByte=lpDIBBitsDest[nPositionDest];
// Mask off the bit we want from the src
srcByte&=(BYTE)(BitMask>>(nCol%nPixelsPerByte));
switch(nAngleDegree)
{
case 180:
bFlip=!bFlip;
case 0:
{
if(bFlip)
{
// Shift src bit to dest bit's position
srcByte<<=(nCol%nPixelsPerByte);
srcByte>>=((nWidthDest-nCol-1)%nPixelsPerByte);
// Zero out only the bit we're going to replace
destByte&=~(BitMask>>((nWidthDest-nCol-1)%
nPixelsPerByte));
}
else
{
// Zero out only the bit we're going to replace
destByte&=~(BitMask>>(nCol%nPixelsPerByte));
}
break;
}
case 270:
bFlip=!bFlip;
case 90:
{
if(bFlip)
{
// Shift src bit to dest bit's position
srcByte<<=(nCol%nPixelsPerByte);
srcByte>>=((nWidthDest-nRow-1)%
nPixelsPerByte);
// Zero out only the bit we're going to replace
destByte&=~(BitMask>>((nWidthDest-nRow-1)%
nPixelsPerByte));
}
else
{
// Shift src bit to dest bit's position
srcByte<<=(nCol%nPixelsPerByte);
srcByte>>=(nRow%nPixelsPerByte);
// Zero out only the bit we're going to replace
destByte&=~(BitMask>>(nRow%nPixelsPerByte));
}
break;
}
default:
ASSERT(FALSE);
}
// Set the destination bit
lpDIBBitsDest[nPositionDest]=(BYTE)(srcByte|destByte);
break;
}
// 16-color bitmap
case 4:
{
// Get the source byte
BYTE srcByte=lpDIBBitsSrc[nPositionSrc];
// Get the destination byte
BYTE destByte=lpDIBBitsDest[nPositionDest];
if(nCol%2==0)
srcByte&=HiMask;
else
srcByte&=LoMask;
switch(nAngleDegree)
{
case 180:
bFlip=!bFlip;
case 0:
{
if(bFlip)
{
if(nCol%2==0 && (nWidthDest-nCol-1)%2!=0)
srcByte>>=nBitsPerPixel;
else if(nCol%2!=0 && (nWidthDest-nCol-1)%2==0)
srcByte<<=nBitsPerPixel;
if((nWidthDest-nCol-1)%2==0)
destByte&=LoMask;
else
destByte&=HiMask;
}
else
{
if(nCol%2==0)
destByte&=LoMask;
else
destByte&=HiMask;
}
break;
}
case 270:
bFlip=!bFlip;
case 90:
{
if(bFlip)
{
if(nCol%2==0 && (nWidthDest-nRow-1)%2!=0)
srcByte>>=nBitsPerPixel;
else if(nCol%2!=0 && (nWidthDest-nRow-1)%2==0)
srcByte<<=nBitsPerPixel;
if((nWidthDest-nRow-1)%2==0)
destByte&=LoMask;
else
destByte&=HiMask;
}
else
{
if(nCol%2==0 && nRow%2!=0)
srcByte>>=nBitsPerPixel;
else if(nCol%2!=0 && nRow%2==0)
srcByte<<=nBitsPerPixel;
if(nRow%2==0)
destByte&=LoMask;
else
destByte&=HiMask;
}
break;
}
default:
ASSERT(FALSE);
}
// Set the destination bit
lpDIBBitsDest[nPositionDest]=(BYTE)(srcByte|destByte);
break;
}
// 256-color and true-color bitmaps
case 8:
case 24:
default:
{
lpDIBBitsDest[nPositionDest]=lpDIBBitsSrc[nPositionSrc];
break;
}
}
}
}
}
//
//////////////////////////////////////////
::GlobalUnlock((HGLOBAL)m_hDIB);
ASSERT(m_hDIB!=NULL);
::GlobalUnlock((HGLOBAL)dibCopy.m_hDIB);
ASSERT(dibCopy.m_hDIB!=NULL);
return TRUE;
}
COXDIB::~COXDIB()
{
Empty();
}
// Diagnostics --------------------------------------------------------------
#ifdef _DEBUG
void COXDIB::AssertValid() const
{
CObject::AssertValid();
if (m_hDIB != NULL)
{
// Handle to global memory must be valid
#ifdef WIN32
BYTE *lp=(BYTE *) ::GlobalLock((HGLOBAL) m_hDIB);
#else
BYTE huge* lp=(BYTE huge *) ::GlobalLock((HGLOBAL) m_hDIB);
#endif
ASSERT(lp != NULL);
::GlobalUnlock((HGLOBAL) m_hDIB);
}
if (m_pPalette != NULL)
{
// Palette may only exist together with a DIB
ASSERT(m_hDIB != NULL);
ASSERT_VALID(m_pPalette);
}
}
void COXDIB::Dump(CDumpContext& dc) const
{
CObject::Dump(dc);
dc << TEXT("\nm_hDIB : ") << m_hDIB;
dc << TEXT("\nm_pPalette : ") << (const void*)m_pPalette;
}
#endif //_DEBUG
// protected:
BOOL COXDIB::InitPalette(LPSTR lpbi)
// --- In :
// --- Out :
// --- Returns : Whether it succeeded or not
// --- Effect : This function creates a palette from a DIB by allocating memory for the
// logical palette, reading and storing the colors from the DIB's color table
// into the logical palette, creating a palette from this logical palette,
// and then returning the palette's handle. This allows the DIB to be
// displayed using the best possible colors (important for DIBs with 256 or
// more colors).
{
LPLOGPALETTE lpPal; // pointer to a logical palette
HANDLE hLogPal; // handle to a logical palette
int i; // loop index
WORD wNumColors; // number of colors in color table
LPBITMAPINFO lpbmi; // pointer to BITMAPINFO structure (Win3.0)
LPBITMAPCOREINFO lpbmc; // pointer to BITMAPCOREINFO structure (old)
BOOL bWinStyleDIB; // flag which signifies whether this is a Win3.0 DIB
BOOL bResult=TRUE; // Initialized with TRUE because when NumColors returns ZERO
// ie. when reading a TRUE COLOR DIB, NumColors returns ZERO
// and then InitPalette succeedes because there is no need
// for a palette.
// if handle to DIB is invalid, return FALSE
if (lpbi==NULL)
{
TRACE(_T("COXDIB::InitPalette : DIB not loaded, cannot create palette\n"));
return FALSE;
}
// get pointer to BITMAPINFO (Win 3.0)
lpbmi=(LPBITMAPINFO)lpbi;
// get pointer to BITMAPCOREINFO (old 1.x)
lpbmc=(LPBITMAPCOREINFO)lpbi;
// get the number of colors in the DIB
wNumColors=GetNumColors(lpbi);
if (wNumColors != 0)
{
// allocate memory block for logical palette
hLogPal=::GlobalAlloc(GHND, sizeof(LOGPALETTE)
+ sizeof(PALETTEENTRY)
* wNumColors);
// if not enough memory, clean up and return NULL
if (hLogPal==0)
{
TRACE(_T("COXDIB::InitPalette : Not enough memory for logical palette\n"));
return FALSE;
}
lpPal=(LPLOGPALETTE) ::GlobalLock((HGLOBAL) hLogPal);
// set version and number of palette entries
lpPal->palVersion=PALVERSION;
lpPal->palNumEntries=(WORD)wNumColors;
// is this a Win 3.0 DIB?
bWinStyleDIB=IS_WIN30_DIB(lpbi);
for (i=0; i < (int)wNumColors; i++)
{
if (bWinStyleDIB)
{
lpPal->palPalEntry[i].peRed=lpbmi->bmiColors[i].rgbRed;
lpPal->palPalEntry[i].peGreen=lpbmi->bmiColors[i].rgbGreen;
lpPal->palPalEntry[i].peBlue=lpbmi->bmiColors[i].rgbBlue;
lpPal->palPalEntry[i].peFlags=0;
}
else
{
lpPal->palPalEntry[i].peRed=lpbmc->bmciColors[i].rgbtRed;
lpPal->palPalEntry[i].peGreen=lpbmc->bmciColors[i].rgbtGreen;
lpPal->palPalEntry[i].peBlue=lpbmc->bmciColors[i].rgbtBlue;
lpPal->palPalEntry[i].peFlags=0;
}
}
// Cannot initialize the palette twice for the same DIB
ASSERT(m_pPalette==NULL);
m_pPalette=new CPalette;
if (m_pPalette==NULL)
{
// we must be really low on memory
TRACE(_T("COXDIB::InitPalette : Out of memory\n"));
Empty();
return FALSE;
}
// create the palette and get handle to it
bResult=m_pPalette->CreatePalette(lpPal);
::GlobalUnlock((HGLOBAL) hLogPal);
::GlobalFree((HGLOBAL) hLogPal);
}
return bResult;
}
DWORD COXDIB::ReadHuge(CArchive& ar, void FAR* lpBuffer, DWORD dwCount)
// --- In :ar : archive to read from
// lpBuffer : pointer to buffer to read
// dwCount : Number of bytes to read
// --- Out :
// --- Returns :Number of bytes read
// --- Effect : Helper function to read large bitmaps (see filex.cpp for original)
{
DWORD dwToRead=dwCount;
while (dwToRead>0)
{
UINT nRead=CalcSize(dwToRead, lpBuffer);
UINT nActuallyRead;
if ((nActuallyRead=ar.Read(lpBuffer, nRead)) < nRead)
return ((dwCount - dwToRead) + nActuallyRead);
ASSERT(nActuallyRead==nRead);
dwToRead -= nRead;
#ifdef WIN32
lpBuffer=((BYTE*)lpBuffer) + nRead;
#else
lpBuffer=((BYTE _huge*)lpBuffer) + nRead;
#endif
}
return dwCount;
}
void COXDIB::WriteHuge(CArchive& ar, const void FAR* lpBuffer, DWORD dwCount)
// --- In :ar : archive to read from
// lpBuffer : pointer to buffer to write
// dwCount : Number of bytes to write
// --- Out :
// --- Returns :Number of bytes read
// --- Effect : Helper function to write ead large bitmaps (see filex.cpp for original)
{
DWORD dwToWrite=dwCount;
while (dwToWrite>0)
{
UINT nWrite=CalcSize(dwToWrite, lpBuffer);
ar.Write(lpBuffer, nWrite);
dwToWrite -= nWrite;
#ifdef WIN32
lpBuffer=((const BYTE*)lpBuffer) + nWrite;
#else
lpBuffer=((const BYTE _huge*)lpBuffer) + nWrite;
#endif
}
}
UINT COXDIB::CalcSize(DWORD cbTotal, const void FAR* lpStart)
// --- In :
// --- Out :
// --- Returns :Number of bytes to read or write
// --- Effect : Helper function
{
// return size to read/write (16K max unless limited by segment bounds)
#ifdef WIN32
lpStart;
DWORD cb=cbTotal;
#else
DWORD cb=0x10000L - _AFX_FP_OFF(lpStart);
if (cb>cbTotal)
cb=cbTotal;
#endif
return (cb>16384) ? 16384 : (UINT)cb;
}
HDIB WINAPI COXDIB::CopyHandle(HDIB hDIB, DWORD dwExtraBytes /*=0 */)
// --- In : h :Handle to global memory to duplicate.
// --- Out :
// --- Returns :Returns a handle to the new memory block (NULL on error)
// --- Effect : Makes a copy of the given global memory block.
{
#ifdef WIN32
BYTE *lpCopy;
BYTE *lp;
HDIB hCopy;
DWORD_PTR dwLen;
#else
BYTE huge *lpCopy;
BYTE huge *lp;
HDIB hCopy;
DWORD dwLen;
#endif
if (hDIB==NULL)
return NULL;
dwLen=::GlobalSize((HGLOBAL) hDIB) + dwExtraBytes;
if ((hCopy=(HDIB) ::GlobalAlloc(GHND, dwLen)) != NULL)
{
#ifdef WIN32
lpCopy=(BYTE *) ::GlobalLock((HGLOBAL) hCopy);
lp =(BYTE *) ::GlobalLock((HGLOBAL) hDIB);
#else
lpCopy=(BYTE huge *) ::GlobalLock((HGLOBAL) hCopy);
lp =(BYTE huge *) ::GlobalLock((HGLOBAL) hDIB);
#endif
while (dwLen--)
*lpCopy++=*lp++;
::GlobalUnlock((HGLOBAL) hCopy);
::GlobalUnlock((HGLOBAL) hDIB);
}
else
{
TRACE1("COXDIB::CopyHandle : Could not GlobalAlloc( ,%i)\n", dwLen);
}
return hCopy;
}
DWORD COXDIB::CalcPadding(DWORD dwBitsPerPixel, DWORD dwPixels)
{
DWORD dwBits=dwBitsPerPixel*dwPixels;
DWORD dwPadBits=0;
int nBitsInDWORD=sizeof(DWORD)<<3;
if((dwBits%nBitsInDWORD)==0)
// already DWORD aligned, no padding needed
return 0;
else
dwPadBits=nBitsInDWORD-(dwBits%nBitsInDWORD);
return (dwPadBits/8+(((dwPadBits%8)>0) ? 1 : 0));
}
// private:
// ==========================================================================