home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Windows Graphics Programming
/
Feng_Yuan_Win32_GDI_DirectX.iso
/
Samples
/
include
/
Dib.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
2000-05-12
|
28KB
|
1,118 lines
//-----------------------------------------------------------------------------------//
// Windows Graphics Programming: Win32 GDI and DirectDraw //
// ISBN 0-13-086985-6 //
// //
// Written by Yuan, Feng www.fengyuan.com //
// Copyright (c) 2000 by Hewlett-Packard Company www.hp.com //
// Published by Prentice Hall PTR, Prentice-Hall, Inc. www.phptr.com //
// //
// FileName : dib.cpp //
// Description: Device independent Bitmap Handling //
// Version : 1.00.000, May 31, 2000 //
//-----------------------------------------------------------------------------------//
#define STRICT
#define _WIN32_WINNT 0x0500
#define WINVER 0x500
#define NOCRYPT
#define OEMRESOURCE
#include <windows.h>
#include <assert.h>
#include <tchar.h>
#include <math.h>
#include "Color.h"
#include "Dib.h"
#include "Affine.h"
#include "BitmapInfo.h"
#include "filedialog.h"
const TCHAR * mess_DIBFormat[] =
{
_T("DIB_1BPP"), // 2 color image, palette-based
_T("DIB_2BPP"), // 4 color image, palttte-based
_T("DIB_4BPP"), // 16 color image, palette-based
_T("DIB_4BPPRLE"), // 16 color image, palette-based, RLE compressed
_T("DIB_8BPP"), // 256 color image, palette-based
_T("DIB_8BPPRLE"), // 256 color image, palette-based, RLE compressed
_T("DIB_16RGB555"), // 15 bit RGB color image, 5-5-5
_T("DIB_16RGB565"), // 16 bit RGB color image, 5-6-5, 1 bit unused
_T("DIB_24RGB888"), // 24 bit RGB color image, 8-8-8
_T("DIB_32RGB888"), // 32 bit RGB color image, 8-8-8, 8 bit unused
_T("DIB_32RGBA8888"), // 32 bit RGBA color image, 8-8-8-8
_T("DIB_16RGBbitfields"), // 16 bit RGB color image, non-standard bit masks, NT-only
_T("DIB_32RGBbitfields"), // 32 bit RGB color image, non-standard bit masks, NT-only
_T("DIB_JPEG"), // embedded JPEG image
_T("DIB_PNG") // embedded PNG image
};
const TCHAR * PixelFormatName(int id)
{
if ( (id>=DIB_1BPP) && (id<=DIB_PNG) )
return mess_DIBFormat[id - DIB_1BPP];
else
return _T("Unknown Pixel Format");
}
KDIB::KDIB()
{
m_pBMI = NULL;
m_pBits = NULL;
m_Flags = 0;
m_nWidth = 0;
m_nHeight = 0;
m_nPlanes = 1;
m_nBitCount = 1;
m_nColorDepth = 1;
m_nImageSize = 0;
m_nImageFormat = DIB_1BPP;
m_pRGBTRIPLE = NULL;
m_pRGBQUAD = NULL;
}
void KDIB::ReleaseDIB(void)
{
if ( m_Flags & DIB_BMI_NEEDFREE )
{
delete [] (BYTE *) m_pBMI;
m_Flags &= ~ DIB_BMI_NEEDFREE;
m_pBMI = NULL;
}
if ( m_Flags & DIB_BITS_NEEDFREE )
{
delete [] m_pBits;
m_Flags &= ~ DIB_BITS_NEEDFREE;
m_pBits = NULL;
}
}
KDIB::~KDIB()
{
try
{
ReleaseDIB();
}
catch (...)
{
}
}
bool KDIB::AttachDIB(BITMAPINFO * pDIB, BYTE * pBits, int flags)
{
if ( IsBadReadPtr(pDIB, sizeof(BITMAPCOREHEADER)) )
return false;
ReleaseDIB();
m_pBMI = pDIB;
m_Flags = flags;
DWORD size = * (DWORD *) pDIB; // always DWORD size, key to information header
int compression;
// gather information from bitmap information header structures
switch ( size )
{
case sizeof(BITMAPCOREHEADER):
{
BITMAPCOREHEADER * pHeader = (BITMAPCOREHEADER *) pDIB;
m_nWidth = pHeader->bcWidth;
m_nHeight = pHeader->bcHeight;
m_nPlanes = pHeader->bcPlanes;
m_nBitCount = pHeader->bcBitCount;
m_nImageSize= 0;
compression = BI_RGB;
if ( m_nBitCount <= 8 )
{
m_nClrUsed = 1 << m_nBitCount;
m_nClrImpt = m_nClrUsed;
m_pRGBTRIPLE = (RGBTRIPLE *) ((BYTE *) m_pBMI + size);
m_pBits = (BYTE *) & m_pRGBTRIPLE[m_nClrUsed];
}
else
m_pBits = (BYTE *) m_pBMI + size;
break;
}
case sizeof(BITMAPINFOHEADER):
case sizeof(BITMAPV4HEADER):
case sizeof(BITMAPV5HEADER):
{
BITMAPINFOHEADER * pHeader = & m_pBMI->bmiHeader;
m_nWidth = pHeader->biWidth;
m_nHeight = pHeader->biHeight;
m_nPlanes = pHeader->biPlanes;
m_nBitCount = pHeader->biBitCount;
m_nImageSize= pHeader->biSizeImage;
compression = pHeader->biCompression;
m_nClrUsed = pHeader->biClrUsed;
m_nClrImpt = pHeader->biClrImportant;
if ( m_nBitCount<=8 )
if ( m_nClrUsed==0 ) // 0 means full color table
m_nClrUsed = 1 << m_nBitCount;
if ( m_nClrUsed ) // has a color table
{
if ( m_nClrImpt==0 ) // 0 means all important
m_nClrImpt = m_nClrUsed;
if ( compression==BI_BITFIELDS )
{
m_pBitFields = (DWORD *) ((BYTE *)pDIB+size);
m_pRGBQUAD = (RGBQUAD *) ((BYTE *)pDIB+size + 3*sizeof(DWORD));
}
else
m_pRGBQUAD = (RGBQUAD *) ((BYTE *)pDIB+size);
m_pBits = (BYTE *) & m_pRGBQUAD[m_nClrUsed];
}
else
{
if ( compression==BI_BITFIELDS )
{
m_pBitFields = (DWORD *) ((BYTE *)pDIB+size);
m_pBits = (BYTE *) m_pBMI + size + 3 * sizeof(DWORD);
}
else
m_pBits = (BYTE *) m_pBMI + size;
}
break;
}
default:
return false;
}
if ( pBits )
m_pBits = pBits;
// precalculate information DIB parameters
m_nColorDepth = m_nPlanes * m_nBitCount;
m_nBPS = (m_nWidth * m_nBitCount + 31) / 32 * 4;
if (m_nHeight < 0 ) // top-down bitmap
{
m_nHeight = - m_nHeight; // change to positive
m_nDelta = m_nBPS; // forward
m_pOrigin = m_pBits; // scan0 .. scanN-1
}
else
{
m_nDelta = - m_nBPS; // backward
m_pOrigin = m_pBits + (m_nHeight-1) * m_nBPS * m_nPlanes; // scanN-1..scan0
}
if ( m_nImageSize==0 )
m_nImageSize = m_nBPS * m_nPlanes * m_nHeight;
// convert compression mode to image format
switch ( m_nBitCount )
{
case 0:
if ( compression==BI_JPEG )
m_nImageFormat = DIB_JPEG;
else if ( compression==BI_PNG )
m_nImageFormat = DIB_PNG;
else
return false;
case 1:
m_nImageFormat = DIB_1BPP;
break;
case 2:
m_nImageFormat = DIB_2BPP;
break;
case 4:
if ( compression==BI_RLE4 )
m_nImageFormat = DIB_4BPPRLE;
else
m_nImageFormat = DIB_4BPP;
break;
case 8:
if ( compression==BI_RLE8 )
m_nImageFormat = DIB_8BPPRLE;
else
m_nImageFormat = DIB_8BPP;
break;
case 16:
if ( compression==BI_BITFIELDS )
m_nImageFormat = DIB_16RGBbitfields;
else
m_nImageFormat = DIB_16RGB555; // see below
break;
case 24:
m_nImageFormat = DIB_24RGB888;
break;
case 32:
if ( compression == BI_BITFIELDS )
m_nImageFormat = DIB_32RGBbitfields;
else
m_nImageFormat = DIB_32RGB888; // see below
break;
default:
return false;
}
// try to understand bit fields
if ( compression==BI_BITFIELDS )
{
DWORD red = m_pBitFields[0];
DWORD green = m_pBitFields[1];
DWORD blue = m_pBitFields[2];
if ( (blue==0x001F) && (green==0x03E0) && (red==0x7C00) )
m_nImageFormat = DIB_16RGB555;
else if ( (blue==0x001F) && (green==0x07E0) && (red==0xF800) )
m_nImageFormat = DIB_16RGB565;
else if ( (blue==0x00FF) && (green==0xFF00) && (red==0xFF0000) )
m_nImageFormat = DIB_32RGB888;
}
return true;
}
bool KDIB::LoadBitmap(HMODULE hModule, LPCTSTR pBitmapName)
{
HRSRC hRes = FindResource(hModule, pBitmapName, RT_BITMAP);
if ( hRes==NULL )
return false;
HGLOBAL hGlb = LoadResource(hModule, hRes);
if ( hGlb==NULL )
return false;
BITMAPINFO * pDIB = (BITMAPINFO *) LockResource(hGlb);
if ( pDIB==NULL )
return false;
return AttachDIB(pDIB, NULL, DIB_BMI_READONLY | DIB_BITS_READONLY);
}
bool KDIB::LoadFile(const TCHAR * pFileName)
{
if ( pFileName==NULL )
return false;
HANDLE handle = CreateFile(pFileName, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if ( handle == INVALID_HANDLE_VALUE )
return false;
BITMAPFILEHEADER bmFH;
DWORD dwRead = 0;
ReadFile(handle, & bmFH, sizeof(bmFH), & dwRead, NULL);
if ( (bmFH.bfType == 0x4D42) && (bmFH.bfSize<=GetFileSize(handle, NULL)) )
{
BITMAPINFO * pDIB = (BITMAPINFO *) new BYTE[bmFH.bfSize];
if ( pDIB )
{
ReadFile(handle, pDIB, bmFH.bfSize, & dwRead, NULL);
CloseHandle(handle);
return AttachDIB(pDIB, NULL, DIB_BMI_NEEDFREE);
}
}
CloseHandle(handle);
return false;
}
BOOL KDIB::SaveFile(const TCHAR * pFileName)
{
if ( m_pBMI )
return SaveDIBToFile(pFileName, m_pBMI, m_pBits);
else
return FALSE;
}
void KDIB::DecodeDIBFormat(TCHAR mess[])
{
wsprintf(mess, _T("DIB %dx%dx%dx%d "), m_nWidth, m_nHeight,
m_nPlanes, m_nBitCount);
if ( m_nImageSize < 1024 )
wsprintf(mess+_tcslen(mess), _T(", %d b"), m_nImageSize);
else if ( m_nImageSize < 1024 * 1024 )
wsprintf(mess+_tcslen(mess), _T(", %d,%03d b"), m_nImageSize/1024, m_nImageSize%1024);
else
wsprintf(mess+_tcslen(mess), _T(", %d,%03d,%03d b"), m_nImageSize/1024/1024, m_nImageSize/1024%1024,
m_nImageSize%1024);
_tcscat(mess, PixelFormatName(m_nImageFormat));
_tcscat(mess, _T(" "));
}
int GetDIBPixelSize(const BITMAPINFOHEADER & bmih)
{
if ( bmih.biSizeImage )
return bmih.biSizeImage;
else
return ( bmih.biWidth * bmih.biBitCount + 31 ) / 32 * 4 * bmih.biPlanes * abs(bmih.biHeight);
}
int GetDIBColorCount(const BITMAPINFOHEADER & bmih)
{
if ( bmih.biBitCount <= 8 )
if ( bmih.biClrUsed )
return bmih.biClrUsed;
else
return 1 << bmih.biBitCount;
else if ( bmih.biCompression==BI_BITFIELDS )
return 3 + bmih.biClrUsed;
else
return bmih.biClrUsed;
}
BITMAPINFO * BitmapToDIB(HPALETTE hPal, // palette for color conversion
HBITMAP hBmp, // DDB for convert
int nBitCount, int nCompression) // format wanted
{
typedef struct
{
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[256+3];
} DIBINFO;
BITMAP ddbinfo;
DIBINFO dibinfo;
// retrieve DDB information
if ( GetObject(hBmp, sizeof(BITMAP), & ddbinfo)==0 )
return NULL;
// fill out BITMAPINFOHEADER based on size and required format
memset(&dibinfo, 0, sizeof(dibinfo));
dibinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
dibinfo.bmiHeader.biWidth = ddbinfo.bmWidth;
dibinfo.bmiHeader.biHeight = ddbinfo.bmHeight;
dibinfo.bmiHeader.biPlanes = 1;
dibinfo.bmiHeader.biBitCount = nBitCount;
dibinfo.bmiHeader.biCompression = nCompression;
HDC hDC = GetDC(NULL); // screen DC
HGDIOBJ hpalOld;
if ( hPal )
hpalOld = SelectPalette(hDC, hPal, FALSE);
else
hpalOld = NULL;
// query GDI for image size
GetDIBits(hDC, hBmp, 0, ddbinfo.bmHeight, NULL, (BITMAPINFO *) & dibinfo, DIB_RGB_COLORS);
int nInfoSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * GetDIBColorCount(dibinfo.bmiHeader);
int nTotalSize = nInfoSize + GetDIBPixelSize(dibinfo.bmiHeader);
BYTE * pDIB = new BYTE[nTotalSize];
if ( pDIB )
{
memcpy(pDIB, & dibinfo, nInfoSize);
if ( ddbinfo.bmHeight != GetDIBits(hDC, hBmp, 0, ddbinfo.bmHeight, pDIB + nInfoSize, (BITMAPINFO *) pDIB, DIB_RGB_COLORS) )
{
delete [] pDIB;
pDIB = NULL;
}
}
if ( hpalOld )
SelectObject(hDC, hpalOld);
ReleaseDC(NULL, hDC);
return (BITMAPINFO *) pDIB;
}
int PixelFormat(HDC hdc)
{
typedef struct
{
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[256+3];
} DIBINFO;
DIBINFO dibinfo;
HBITMAP hBmp = CreateCompatibleBitmap(hdc, 1, 1);
if ( hBmp==NULL )
return -1;
memset(&dibinfo, 0, sizeof(dibinfo));
dibinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
// 1st call to get hdc biBitCount.
GetDIBits(hdc, hBmp, 0, 1, NULL, (BITMAPINFO*) & dibinfo, DIB_RGB_COLORS);
// 2nd calls to get color table or bitfields
GetDIBits(hdc, hBmp, 0, 1, NULL, (BITMAPINFO*) & dibinfo, DIB_RGB_COLORS);
DeleteObject(hBmp);
// try to understand bit fields
if ( dibinfo.bmiHeader.biBitCount==BI_BITFIELDS )
{
DWORD * pBitFields = (DWORD *) dibinfo.bmiColors;
DWORD red = pBitFields[0];
DWORD green = pBitFields[1];
DWORD blue = pBitFields[2];
if ( (blue==0x001F) && (green==0x03E0) && (red==0x7C00) )
return DIB_16RGB555;
else if ( (blue==0x001F) && (green==0x007E) && (red==0xF800) )
return DIB_16RGB565;
else if ( (blue==0x00FF) && (green==0xFF00) && (red==0xFF0000) )
return DIB_32RGB888;
else
return -1;
}
switch ( dibinfo.bmiHeader.biBitCount )
{
case 1: return DIB_1BPP;
case 2: return DIB_2BPP;
case 4: return DIB_4BPP;
case 8: return DIB_8BPP;
case 24: return DIB_24RGB888;
case 16: return DIB_16RGB555;
case 32: return DIB_32RGB888;
default: return -1;
}
}
HBITMAP CaptureWindow(HWND hWnd)
{
RECT wnd;
if ( ! GetWindowRect(hWnd, & wnd) )
return NULL;
HDC hDC = GetWindowDC(hWnd);
HBITMAP hBmp = CreateCompatibleBitmap(hDC, wnd.right - wnd.left, wnd.bottom - wnd.top);
if ( hBmp )
{
HDC hMemDC = CreateCompatibleDC(hDC);
HGDIOBJ hOld = SelectObject(hMemDC, hBmp);
BitBlt(hMemDC, 0, 0, wnd.right - wnd.left, wnd.bottom - wnd.top,
hDC, 0, 0, SRCCOPY);
SelectObject(hMemDC, hOld);
DeleteObject(hMemDC);
}
ReleaseDC(hWnd, hDC);
return hBmp;
}
BOOL SaveDIBToFile(const TCHAR * pFileName, const BITMAPINFO * pBMI, const void * pBits)
{
KFileDialog fi;
if ( pFileName==NULL )
{
if ( ! fi.GetSaveFileName(NULL, _T("bmp"), _T("Bitmap Files")) )
return FALSE;
pFileName = fi.m_TitleName;
}
HANDLE handle = CreateFile(pFileName, GENERIC_WRITE, FILE_SHARE_READ,
NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
if ( handle == INVALID_HANDLE_VALUE )
return FALSE;
BITMAPFILEHEADER bmFH;
int nHeadSize = sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * GetDIBColorCount(pBMI->bmiHeader);
bmFH.bfType = 0x4D42;
bmFH.bfSize = nHeadSize + GetDIBPixelSize(pBMI->bmiHeader);
bmFH.bfReserved1 = 0;
bmFH.bfReserved2 = 0;
bmFH.bfOffBits = nHeadSize + sizeof(BITMAPFILEHEADER);
DWORD dwRead = 0;
WriteFile(handle, & bmFH, sizeof(bmFH), & dwRead, NULL);
if ( pBits==NULL ) // packed DIB
pBits = (BYTE *) pBMI + nHeadSize;
WriteFile(handle, pBMI, nHeadSize, & dwRead, NULL);
WriteFile(handle, pBits, GetDIBPixelSize(pBMI->bmiHeader), & dwRead, NULL);
CloseHandle(handle);
return TRUE;
}
void SaveWindowToDIB(HWND hWnd, int nBitCount, int nCompression)
{
HBITMAP hBmp = CaptureWindow(hWnd);
if ( hBmp )
{
BITMAPINFO * pDIB = BitmapToDIB(NULL, hBmp, nBitCount, nCompression);
if ( pDIB )
{
SaveDIBToFile(NULL, pDIB, NULL);
delete [] (BYTE *) pDIB;
}
DeleteObject(hBmp);
}
}
const BYTE Shift1bpp[] = { 7, 6, 5, 4, 3, 2, 1, 0 };
const BYTE Mask1bpp [] = { ~0x80, ~0x40, ~0x20, ~0x10, ~0x08, ~0x04, ~0x02, ~0x01 };
const BYTE Shift2bpp[] = { 6, 4, 2, 0 };
const BYTE Mask2bpp [] = { ~0xC0, ~0x30, ~0x0C, ~0x03 };
const BYTE Shift4bpp[] = { 4, 0 };
const BYTE Mask4bpp [] = { ~0xF0, ~0x0F };
DWORD KDIB::GetPixelIndex(int x, int y) const
{
if ( (x<0) || (x>=m_nWidth) )
return -1;
if ( (y<0) || (y>=m_nHeight) )
return -1;
BYTE * pPixel = m_pOrigin + y * m_nDelta;
switch ( m_nImageFormat )
{
case DIB_1BPP:
return ( pPixel[x/8] >> Shift1bpp[x%8] ) & 0x01;
case DIB_2BPP:
return ( pPixel[x/4] >> Shift2bpp[x%4] ) & 0x03;
case DIB_4BPP:
return ( pPixel[x/2] >> Shift4bpp[x%4] ) & 0x0F;
case DIB_8BPP:
return pPixel[x];
case DIB_16RGB555:
case DIB_16RGB565:
return ((WORD *)pPixel)[x];
case DIB_24RGB888:
pPixel += x * 3;
return (pPixel[0]) | (pPixel[1] << 8) | (pPixel[2] << 16);
case DIB_32RGB888:
case DIB_32RGBA8888:
return ((DWORD *)pPixel)[x];
}
return -1;
}
BOOL KDIB::SetPixelIndex(int x, int y, DWORD index)
{
if ( (x<0) || (x>=m_nWidth) )
return FALSE;
if ( (y<0) || (y>=m_nHeight) )
return FALSE;
BYTE * pPixel = m_pOrigin + y * m_nDelta;
switch ( m_nImageFormat )
{
case DIB_1BPP:
pPixel[x/8] = (BYTE) ( ( pPixel[x/8] & Mask1bpp[x%8] ) | ( (index & 1) << Shift1bpp[x%8] ) );
break;
case DIB_2BPP:
pPixel[x/4] = (BYTE) ( ( pPixel[x/4] & Mask2bpp[x%4] ) | ( (index & 3) << Shift2bpp[x%4] ) );
break;
case DIB_4BPP:
pPixel[x/2] = (BYTE) ( ( pPixel[x/2] & Mask4bpp[x%2] ) | ( (index & 15) << Shift4bpp[x%2] ) );
break;
case DIB_8BPP:
pPixel[x] = (BYTE) index;
break;
case DIB_16RGB555:
case DIB_16RGB565:
((WORD *)pPixel)[x] = (WORD) index;
break;
case DIB_24RGB888:
((RGBTRIPLE *)pPixel)[x] = * ((RGBTRIPLE *) & index);
break;
case DIB_32RGB888:
case DIB_32RGBA8888:
((DWORD *)pPixel)[x] = index;
break;
default:
return FALSE;
}
return TRUE;
}
BOOL KDIB::PlgBlt(const POINT * pPoint,
KDIB * pSrc, int nXSrc, int nYSrc, int nWidth, int nHeight)
{
KReverseAffine map(pPoint);
map.Setup(nXSrc, nYSrc, nWidth, nHeight);
for (int dy=map.miny; dy<=map.maxy; dy++)
for (int dx=map.minx; dx<=map.maxx; dx++)
{
float sx, sy;
map.Map(dx, dy, sx, sy);
if ( (sx>=nXSrc) && (sx<(nXSrc+nWidth)) )
if ( (sy>=nYSrc) && (sy<(nYSrc+nHeight)) )
SetPixelIndex(dx, dy, pSrc->GetPixelIndex( (int)sx, (int)sy));
}
return TRUE;
}
BOOL KDIB::PlgBltGetPixel(const POINT * pPoint,
HDC hSrc, int nXSrc, int nYSrc, int nWidth, int nHeight, HDC hDst)
{
KReverseAffine map(pPoint);
map.Setup(nXSrc, nYSrc, nWidth, nHeight);
for (int dy=map.miny; dy<=map.maxy; dy++)
for (int dx=map.minx; dx<=map.maxx; dx++)
{
float sx, sy;
map.Map(dx, dy, sx, sy);
if ( (sx>=nXSrc) && (sx<(nXSrc+nWidth)) )
if ( (sy>=nYSrc) && (sy<(nYSrc+nHeight)) )
SetPixel(hDst, dx, dy, GetPixel(hSrc, (int)sx, (int)sy));
}
return TRUE;
}
BOOL KDIB::PlgBlt24(const POINT * pPoint,
KDIB * pSrc, int nXSrc, int nYSrc, int nWidth, int nHeight)
{
// factor to change FLOAT to fixed point
const int FACTOR = 65536;
// generate reverse transformation from destination to source
KReverseAffine map(pPoint);
map.Setup(nXSrc, nYSrc, nWidth, nHeight);
// make sure within destination bitmap dimension
if ( map.minx < 0 ) map.minx = 0;
if ( map.maxx > m_nWidth ) map.maxx = m_nWidth;
if ( map.miny < 0 ) map.miny = 0;
if ( map.maxy > m_nHeight ) map.maxy = m_nHeight;
// source rectangle in fixed point
int sminx = nXSrc * FACTOR;
int sminy = nYSrc * FACTOR;
int smaxx = ( nXSrc + nWidth ) * FACTOR;
int smaxy = ( nYSrc + nHeight ) * FACTOR;
// transformation matrix in fixed point
int m11 = (int) (map.m_xm.eM11 * FACTOR);
int m12 = (int) (map.m_xm.eM12 * FACTOR);
int m21 = (int) (map.m_xm.eM21 * FACTOR);
int m22 = (int) (map.m_xm.eM22 * FACTOR);
int mdx = (int) (map.m_xm.eDx * FACTOR);
int mdy = (int) (map.m_xm.eDy * FACTOR);
BYTE * SOrigin = pSrc->m_pOrigin;
int SDelta = pSrc->m_nDelta;
// in destination bitmap, scan from first to last scanline
for (int dy=map.miny; dy<map.maxy; dy++)
{
/*
// search for the first pixel on the scanline within source rectangle
int sx = m11 * map.minx + m21 * dy + mdx;
int sy = m12 * map.minx + m22 * dy + mdy;
for (int dx=map.minx; dx<map.maxx; dx++, sx+=m11, sy+=m12)
// if within source rectangle
if ( (sx>=sminx) && (sx<smaxx) )
if ( (sy>=sminy) && (sy<smaxy) )
break;
int minx = dx;
// search for the last pixel on the scaneline within source rectangle
sx = m11 * map.maxx + m21 * dy + mdx;
sy = m12 * map.maxx + m22 * dy + mdy;
for (dx=map.maxx; dx>=map.minx; dx--, sx-=m11, sy-=m12)
// if within source rectangle
if ( (sx>=sminx) && (sx<smaxx) )
if ( (sy>=sminy) && (sy<smaxy) )
break;
int maxx = dx;
*/
// precalculate destination pixel address for first pixel
BYTE * pDPixel = m_pOrigin + dy * m_nDelta + map.minx * 3;
// source pixel address for the first pixel
int sx = m11 * map.minx + m21 * dy + mdx;
int sy = m12 * map.minx + m22 * dy + mdy;
// go through each pixel on the scan line
for (int dx=map.minx; dx<map.maxx; dx++, pDPixel+=3, sx+=m11, sy+=m12)
if ( (sx>=sminx) && (sx<smaxx) )
if ( (sy>=sminy) && (sy<smaxy) )
{
// source pixel address
BYTE * pSPixel = SOrigin + (sy/FACTOR) * SDelta;
// copy three bytes
* ((RGBTRIPLE *)pDPixel) = ((RGBTRIPLE *)pSPixel)[sx/FACTOR];
}
}
return TRUE;
}
BOOL KDIB::Create(int width, int height, int bitcount)
{
KBitmapInfo dibinfo;
dibinfo.SetFormat(width, height, bitcount, BI_RGB);
int nBitsSize = ( width * bitcount + 31 ) /32 * 4 * height;
BYTE * pBits = new BYTE[nBitsSize];
if ( pBits )
return AttachDIB(dibinfo.CopyBMI(), pBits, 0);
else
return FALSE;
}
void Map(XFORM * xm, int x, int y, int & rx, int & ry)
{
rx = (int) ( xm->eM11 * x + xm->eM21 * y + xm->eDx );
ry = (int) ( xm->eM12 * x + xm->eM22 * y + xm->eDy );
}
BOOL Invert(XFORM & xm)
{
FLOAT det = xm.eM11 * xm.eM22 - xm.eM21 * xm.eM12;
if ( det==0 )
return FALSE;
XFORM old = xm;
xm.eM11 = old.eM22 / det;
xm.eM12 = - old.eM12 / det;
xm.eM21 = - old.eM21 / det;
xm.eM22 = old.eM11 / det;
xm.eDx = - ( xm.eM11 * old.eDx + xm.eM21 * old.eDy );
xm.eDy = - ( xm.eM12 * old.eDx + xm.eM22 * old.eDy );
return TRUE;
}
DWORD dibtick;
HBITMAP KDIB::TransformBitmap(XFORM * xm, COLORREF crBack, int method)
{
int x0, y0, x1, y1, x2, y2, x3, y3;
Map(xm, 0, 0, x0, y0); // 0 1
Map(xm, m_nWidth, 0, x1, y1); //
Map(xm, 0, m_nHeight, x2, y2); // 2 3
Map(xm, m_nWidth, m_nHeight, x3, y3);
int xmin, xmax;
int ymin, ymax;
minmax(x0, x1, x2, x3, xmin, xmax);
minmax(y0, y1, y2, y3, ymin, ymax);
int destwidth = xmax - xmin;
int destheight = ymax - ymin;
KBitmapInfo dest;
dest.SetFormat(destwidth, destheight, m_pBMI->bmiHeader.biBitCount, m_pBMI->bmiHeader.biCompression);
if ( m_nClrUsed )
memcpy(dest.m_dibinfo.bmiColors, m_pRGBQUAD, sizeof(RGBQUAD) * m_nClrUsed);
// create destination DIB section
BYTE * pBits;
HBITMAP hBitmap = CreateDIBSection(NULL, dest.GetBMI(), DIB_RGB_COLORS, (void **) & pBits, NULL, NULL);
if ( hBitmap==NULL )
{
assert(false);
return NULL;
}
// For testing GDI GetPixel speed, we need a HDC for the source bitmap
HBITMAP hSrcBmp = NULL;
HDC hSrcDC = NULL;
HGDIOBJ hSrcOld = NULL;
if ( method==method_gdi )
{
hSrcBmp = CreateDIBSection(NULL, m_pBMI, DIB_RGB_COLORS, (void **) & pBits, NULL, NULL);
assert(hSrcBmp);
hSrcDC = CreateCompatibleDC(NULL);
hSrcOld = SelectObject(hSrcDC, hSrcBmp);
// copy pixels from DIB to source DIB section
DrawDIB(hSrcDC, 0, 0, m_nWidth, m_nHeight, 0, 0, m_nWidth, m_nHeight, SRCCOPY);
}
// clear DIB section to background color
HDC hDstDC = CreateCompatibleDC(NULL);
HGDIOBJ hDstOld = SelectObject(hDstDC, hBitmap);
HBRUSH hBrush = CreateSolidBrush(crBack);
RECT rect = { 0, 0, destwidth, destheight };
FillRect(hDstDC, & rect, hBrush);
DeleteObject(hBrush);
KDIB destDIB;
destDIB.AttachDIB(dest.GetBMI(), pBits, 0);
POINT P[3] = { { x0-xmin, y0-ymin }, { x1-xmin, y1-ymin }, { x2-xmin, y2-ymin } };
dibtick = GetTickCount();
if ( (m_nBitCount<=8) && (method==method_24bpp) )
method = method_direct;
switch ( method )
{
case method_gdi:
destDIB.PlgBltGetPixel(P, hSrcDC, 0, 0, m_nWidth, m_nHeight, hDstDC);
break;
case method_direct:
destDIB.PlgBlt(P, this, 0, 0, m_nWidth, m_nHeight);
break;
case method_24bpp:
destDIB.PlgBlt24(P, this, 0, 0, m_nWidth, m_nHeight);
break;
}
dibtick = GetTickCount() - dibtick;
SelectObject(hDstDC, hDstOld);
DeleteObject(hDstDC);
if ( method==method_gdi )
{
SelectObject(hSrcDC, hSrcOld);
DeleteObject(hSrcDC);
DeleteObject(hSrcBmp);
}
return hBitmap;
}
// Calculate DIB pixel offset
inline int GetOffset(BITMAPINFO * pBMI, int x, int y)
{
if ( pBMI->bmiHeader.biHeight > 0 ) // for bottom up, reflect y
y = pBMI->bmiHeader.biHeight - 1 - y;
return ( pBMI->bmiHeader.biWidth * pBMI->bmiHeader.biBitCount + 31 ) / 32 * 4 * y +
( pBMI->bmiHeader.biBitCount / 8 ) * x;
}
// Alpha Blending between two 32-bpp DIBs
BOOL AlphaBlend3232(BITMAPINFO * pBMIDst, BYTE * pBitsDst, int dx, int dy, int w, int h,
BITMAPINFO * pBMISrc, BYTE * pBitsSrc, int sx, int sy,
BLENDFUNCTION blend)
{
int alpha = blend.SourceConstantAlpha; // constant alpha
int beta = 255 - alpha; // constant beta
int format;
if ( blend.AlphaFormat==0 )
format = 0;
else if ( alpha==255 )
format = 1;
else
format = 2;
for (int j=0; j<h; j++)
{
BYTE * D = pBitsDst + GetOffset(pBMIDst, dx, j + dy);
BYTE * S = pBitsSrc + GetOffset(pBMISrc, sx, j + sy);
int i;
switch ( format )
{
case 0: // constant alpha only
for (i=0; i<w; i++)
{
D[0] = ( S[0] * alpha + beta * D[0] + 127 ) / 255;
D[1] = ( S[1] * alpha + beta * D[1] + 127 ) / 255;
D[2] = ( S[2] * alpha + beta * D[2] + 127 ) / 255;
D[3] = ( S[3] * alpha + beta * D[3] + 127 ) / 255;
D += 4; S += 4;
}
break;
case 1: // alpha channel only
for (i=0; i<w; i++)
{
beta = 255 - S[3];
D[0] = S[0] + ( beta * D[0] + 127 ) / 255;
D[1] = S[1] + ( beta * D[1] + 127 ) / 255;
D[2] = S[2] + ( beta * D[2] + 127 ) / 255;
D[3] = S[3] + ( beta * D[3] + 127 ) / 255;
D += 4; S += 4;
}
break;
case 2: // both constant alpha and alpha channel
for (i=0; i<w; i++)
{
beta = 255 - ( S[3] * alpha + 127 ) / 255;
D[0] = ( S[0] * alpha + beta * D[0] + 127 ) / 255;
D[1] = ( S[1] * alpha + beta * D[1] + 127 ) / 255;
D[2] = ( S[2] * alpha + beta * D[2] + 127 ) / 255;
D[3] = ( S[3] * alpha + beta * D[3] + 127 ) / 255;
D += 4; S += 4;
}
}
}
return FALSE;
}
// AlphaBlending a 32-bpp DIB to hdc
BOOL AlphaBlend(HDC hdc, int x0, int y0, const BITMAPINFO *pbmpInfo, const void * pAlphaImageData)
{
if ( pbmpInfo->bmiHeader.biBitCount!=32 )
return FALSE;
if ( pbmpInfo->bmiHeader.biCompression!=BI_RGB )
return FALSE;
int width = pbmpInfo->bmiHeader.biWidth;
int height = pbmpInfo->bmiHeader.biHeight;
BITMAPINFOHEADER bmih = { sizeof(BITMAPINFOHEADER), width, height, 1, 24 };
VOID * pBits;
HBITMAP hBmp = CreateDIBSection(NULL, (BITMAPINFO *) & bmih, DIB_RGB_COLORS, & pBits, NULL, NULL);
if ( hBmp==NULL )
return FALSE;
HDC hMemDC = CreateCompatibleDC(hdc);
HGDIOBJ hOld = SelectObject(hMemDC, hBmp);
BitBlt(hMemDC, 0, 0, width, height, hdc, x0, y0, SRCCOPY); // copy destination, not working on printer
const BYTE * psrc = (const BYTE *) pAlphaImageData;
BYTE * pdst = (BYTE *) pBits;
for (int y = 0; y < abs(height); y++)
{
for (int x = width; x>0; x--)
{
BYTE alpha = psrc[3]; //Get alpha channel byte.
BYTE salpha = 255 - alpha;
pdst[0] = (BYTE)(( psrc[0] * alpha + pdst[0] * salpha) / 255);
pdst[1] = (BYTE)(( psrc[1] * alpha + pdst[1] * salpha) / 255);
pdst[2] = (BYTE)(( psrc[2] * alpha + pdst[2] * salpha) / 255);
pdst += 3;
psrc += 4;
}
pdst += width % 3;
}
BOOL rslt = BitBlt(hdc, x0, y0, width, height, hMemDC, 0, 0, SRCCOPY);
SelectObject(hMemDC, hOld);
DeleteObject(hBmp);
DeleteObject(hMemDC);
return rslt;
}