滤镜功能只是简单的矩阵变换。读入,变换,写出。
CDib 里的函数,看英文名和里面的注解应当能懂。
头文件:
// cdib.h declaration for Inside Visual C++ CDib class
#ifndef _INSIDE_VISUAL_CPP_CDIB
#define _INSIDE_VISUAL_CPP_CDIB
class CDib : public CObject
{
enum Alloc {noAlloc, crtAlloc, heapAlloc}
DECLARE_SERIAL(CDib)
public:
LPVOID m_lpvColorTable
HBITMAP m_hBitmap
LPBYTE m_lpImage // starting address of DIB bits
LPBITMAPINFOHEADER m_lpBMIH// buffer containing the BITMAPINFOHEADER
private:
HGLOBAL m_hGlobal// For external windows we need to free
// could be allocated by this class or allocated externally
Alloc m_nBmihAlloc
Alloc m_nImageAlloc
DWORD m_dwSizeImage// of bits -- not BITMAPINFOHEADER or BITMAPFILEHEADER
int m_nColorTableEntries
HANDLE m_hFile
HANDLE m_hMap
LPVOID m_lpvFile
HPALETTE m_hPalette
public:
CDib()
CDib(CSize size, int nBitCount)// builds BITMAPINFOHEADER
~CDib()
int GetSizeImage() {return m_dwSizeImage}
int GetSizeHeader()
{return sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries}
CSize GetDimensions()
BOOL AttachMapFile(const char* strPathname, BOOL bShare = FALSE)
BOOL CopyToMapFile(const char* strPathname)
BOOL AttachMemory(LPVOID lpvMem, BOOL bMustDelete = FALSE, HGLOBAL hGlobal = NULL)
BOOL Draw(CDC* pDC, CPoint origin, CSize size) // until we implemnt CreateDibSection
HBITMAP CreateSection(CDC* pDC = NULL)
UINT UsePalette(CDC* pDC, BOOL bBackground = FALSE)
BOOL MakePalette()
BOOL SetSystemPalette(CDC* pDC)
BOOL Compress(CDC* pDC, BOOL bCompress = TRUE)// FALSE means decompress
HBITMAP CreateBitmap(CDC* pDC)
BOOL Read(CFile* pFile)
BOOL ReadSection(CFile* pFile, CDC* pDC = NULL)
BOOL Write(CFile* pFile)
void Serialize(CArchive&ar)
void Empty()
private:
void DetachMapFile()
void ComputePaletteSize(int nBitCount)
void ComputeMetrics()
}
#endif // _INSIDE_VISUAL_CPP_CDIB
cpp 文件:
// cdib.cpp
// new version for WIN32
#include "stdafx.h"
#include "cdib.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__
#endif
IMPLEMENT_SERIAL(CDib, CObject, 0)
CDib::CDib()
{
m_hFile = NULL
m_hBitmap = NULL
m_hPalette = NULL
m_nBmihAlloc = m_nImageAlloc = noAlloc
Empty()
}
CDib::CDib(CSize size, int nBitCount)
{
m_hFile = NULL
m_hBitmap = NULL
m_hPalette = NULL
m_nBmihAlloc = m_nImageAlloc = noAlloc
Empty()
ComputePaletteSize(nBitCount)
m_lpBMIH = (LPBITMAPINFOHEADER) new
char[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries]
m_nBmihAlloc = crtAlloc
m_lpBMIH->biSize = sizeof(BITMAPINFOHEADER)
m_lpBMIH->biWidth = size.cx
m_lpBMIH->biHeight = size.cy
m_lpBMIH->biPlanes = 1
m_lpBMIH->biBitCount = nBitCount
m_lpBMIH->biCompression = BI_RGB
m_lpBMIH->biSizeImage = 0
m_lpBMIH->biXPelsPerMeter = 0
m_lpBMIH->biYPelsPerMeter = 0
m_lpBMIH->biClrUsed = m_nColorTableEntries
m_lpBMIH->biClrImportant = m_nColorTableEntries
ComputeMetrics()
memset(m_lpvColorTable, 0, sizeof(RGBQUAD) * m_nColorTableEntries)
m_lpImage = NULL // no data yet
}
CDib::~CDib()
{
Empty()
}
CSize CDib::GetDimensions()
{
if(m_lpBMIH == NULL) return CSize(0, 0)
return CSize((int) m_lpBMIH->biWidth, (int) m_lpBMIH->biHeight)
}
BOOL CDib::AttachMapFile(const char* strPathname, BOOL bShare) // for reading
{
// if we open the same file twice, Windows treats it as 2 separate files
// doesn't work with rare BMP files where # palette entries >biClrUsed
HANDLE hFile = ::CreateFile(strPathname, GENERIC_WRITE | GENERIC_READ,
bShare ? FILE_SHARE_READ : 0,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)
ASSERT(hFile != INVALID_HANDLE_VALUE)
DWORD dwFileSize = ::GetFileSize(hFile, NULL)
HANDLE hMap = ::CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL)
DWORD dwErr = ::GetLastError()
if(hMap == NULL) {
AfxMessageBox("Empty bitmap file")
return FALSE
}
LPVOID lpvFile = ::MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0)// map whole file
ASSERT(lpvFile != NULL)
if(((LPBITMAPFILEHEADER) lpvFile)->bfType != 0x4d42) {
AfxMessageBox("Invalid bitmap file")
DetachMapFile()
return FALSE
}
AttachMemory((LPBYTE) lpvFile + sizeof(BITMAPFILEHEADER))
m_lpvFile = lpvFile
m_hFile = hFile
m_hMap = hMap
return TRUE
}
BOOL CDib::CopyToMapFile(const char* strPathname)
{
// copies DIB to a new file, releases prior pointers
// if you previously used CreateSection, the HBITMAP will be NULL (and unusable)
BITMAPFILEHEADER bmfh
bmfh.bfType = 0x4d42 // 'BM'
bmfh.bfSize = m_dwSizeImage + sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * m_nColorTableEntries + sizeof(BITMAPFILEHEADER)
// meaning of bfSize open to interpretation
bmfh.bfReserved1 = bmfh.bfReserved2 = 0
bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * m_nColorTableEntries
HANDLE hFile = ::CreateFile(strPathname, GENERIC_WRITE | GENERIC_READ, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)
ASSERT(hFile != INVALID_HANDLE_VALUE)
int nSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * m_nColorTableEntries + m_dwSizeImage
HANDLE hMap = ::CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, nSize, NULL)
DWORD dwErr = ::GetLastError()
ASSERT(hMap != NULL)
LPVOID lpvFile = ::MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0)// map whole file
ASSERT(lpvFile != NULL)
LPBYTE lpbCurrent = (LPBYTE) lpvFile
memcpy(lpbCurrent, &bmfh, sizeof(BITMAPFILEHEADER))// file header
lpbCurrent += sizeof(BITMAPFILEHEADER)
LPBITMAPINFOHEADER lpBMIH = (LPBITMAPINFOHEADER) lpbCurrent
memcpy(lpbCurrent, m_lpBMIH,
sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries)// info
lpbCurrent += sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries
memcpy(lpbCurrent, m_lpImage, m_dwSizeImage)// bit image
DWORD dwSizeImage = m_dwSizeImage
Empty()
m_dwSizeImage = dwSizeImage
m_nBmihAlloc = m_nImageAlloc = noAlloc
m_lpBMIH = lpBMIH
m_lpImage = lpbCurrent
m_hFile = hFile
m_hMap = hMap
m_lpvFile = lpvFile
ComputePaletteSize(m_lpBMIH->biBitCount)
ComputeMetrics()
MakePalette()
return TRUE
}
BOOL CDib::AttachMemory(LPVOID lpvMem, BOOL bMustDelete, HGLOBAL hGlobal)
{
// assumes contiguous BITMAPINFOHEADER, color table, image
// color table could be zero length
Empty()
m_hGlobal = hGlobal
if(bMustDelete == FALSE) {
m_nBmihAlloc = noAlloc
}
else {
m_nBmihAlloc = ((hGlobal == NULL) ? crtAlloc : heapAlloc)
}
try {
m_lpBMIH = (LPBITMAPINFOHEADER) lpvMem
ComputeMetrics()
ComputePaletteSize(m_lpBMIH->biBitCount)
m_lpImage = (LPBYTE) m_lpvColorTable + sizeof(RGBQUAD) * m_nColorTableEntries
MakePalette()
}
catch(CException* pe) {
AfxMessageBox("AttachMemory error")
pe->Delete()
return FALSE
}
return TRUE
}
UINT CDib::UsePalette(CDC* pDC, BOOL bBackground /* = FALSE */)
{
if(m_hPalette == NULL) return 0
HDC hdc = pDC->GetSafeHdc()
::SelectPalette(hdc, m_hPalette, bBackground)
return ::RealizePalette(hdc)
}
BOOL CDib::Draw(CDC* pDC, CPoint origin, CSize size)
{
if(m_lpBMIH == NULL) return FALSE
if(m_hPalette != NULL) {
::SelectPalette(pDC->GetSafeHdc(), m_hPalette, TRUE)
}
pDC->SetStretchBltMode(COLORONCOLOR)
::StretchDIBits(pDC->GetSafeHdc(), origin.x, origin.y, size.cx, size.cy,
0, 0, m_lpBMIH->biWidth, m_lpBMIH->biHeight,
m_lpImage, (LPBITMAPINFO) m_lpBMIH, DIB_RGB_COLORS, SRCCOPY)
return TRUE
}
HBITMAP CDib::CreateSection(CDC* pDC /* = NULL */)
{
if(m_lpBMIH == NULL) return NULL
if(m_lpImage != NULL) return NULL// can only do this if image doesn't exist
m_hBitmap = ::CreateDIBSection(pDC->GetSafeHdc(), (LPBITMAPINFO) m_lpBMIH,
DIB_RGB_COLORS, (LPVOID*) &m_lpImage, NULL, 0)
ASSERT(m_lpImage != NULL)
return m_hBitmap
}
BOOL CDib::MakePalette()
{
// makes a logical palette (m_hPalette) from the DIB's color table
// this palette will be selected and realized prior to drawing the DIB
if(m_nColorTableEntries == 0) return FALSE
if(m_hPalette != NULL) ::DeleteObject(m_hPalette)
TRACE("CDib::MakePalette -- m_nColorTableEntries = %d\n", m_nColorTableEntries)
LPLOGPALETTE pLogPal = (LPLOGPALETTE) new char[2 * sizeof(WORD) +
m_nColorTableEntries * sizeof(PALETTEENTRY)]
pLogPal->palVersion = 0x300
pLogPal->palNumEntries = m_nColorTableEntries
LPRGBQUAD pDibQuad = (LPRGBQUAD) m_lpvColorTable
for(int i = 0i <m_nColorTableEntriesi++) {
pLogPal->palPalEntry[i].peRed = pDibQuad->rgbRed
pLogPal->palPalEntry[i].peGreen = pDibQuad->rgbGreen
pLogPal->palPalEntry[i].peBlue = pDibQuad->rgbBlue
pLogPal->palPalEntry[i].peFlags = 0
pDibQuad++
}
m_hPalette = ::CreatePalette(pLogPal)
delete pLogPal
return TRUE
}
BOOL CDib::SetSystemPalette(CDC* pDC)
{
// if the DIB doesn't have a color table, we can use the system's halftone palette
if(m_nColorTableEntries != 0) return FALSE
m_hPalette = ::CreateHalftonePalette(pDC->GetSafeHdc())
return TRUE
}
HBITMAP CDib::CreateBitmap(CDC* pDC)
{
if (m_dwSizeImage == 0) return NULL
HBITMAP hBitmap = ::CreateDIBitmap(pDC->GetSafeHdc(), m_lpBMIH,
CBM_INIT, m_lpImage, (LPBITMAPINFO) m_lpBMIH, DIB_RGB_COLORS)
ASSERT(hBitmap != NULL)
return hBitmap
}
BOOL CDib::Compress(CDC* pDC, BOOL bCompress /* = TRUE */)
{
// 1. makes GDI bitmap from existing DIB
// 2. makes a new DIB from GDI bitmap with compression
// 3. cleans up the original DIB
// 4. puts the new DIB in the object
if((m_lpBMIH->biBitCount != 4) &&(m_lpBMIH->biBitCount != 8)) return FALSE
// compression supported only for 4 bpp and 8 bpp DIBs
if(m_hBitmap) return FALSE// can't compress a DIB Section!
TRACE("Compress: original palette size = %d\n", m_nColorTableEntries)
HDC hdc = pDC->GetSafeHdc()
HPALETTE hOldPalette = ::SelectPalette(hdc, m_hPalette, FALSE)
HBITMAP hBitmap // temporary
if((hBitmap = CreateBitmap(pDC)) == NULL) return FALSE
int nSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries
LPBITMAPINFOHEADER lpBMIH = (LPBITMAPINFOHEADER) new char[nSize]
memcpy(lpBMIH, m_lpBMIH, nSize) // new header
if(bCompress) {
switch (lpBMIH->biBitCount) {
case 4:
lpBMIH->biCompression = BI_RLE4
break
case 8:
lpBMIH->biCompression = BI_RLE8
break
default:
ASSERT(FALSE)
}
// calls GetDIBits with null data pointer to get size of compressed DIB
if(!::GetDIBits(pDC->GetSafeHdc(), hBitmap, 0, (UINT) lpBMIH->biHeight,
NULL, (LPBITMAPINFO) lpBMIH, DIB_RGB_COLORS)) {
AfxMessageBox("Unable to compress this DIB")
// probably a problem with the color table
::DeleteObject(hBitmap)
delete [] lpBMIH
::SelectPalette(hdc, hOldPalette, FALSE)
return FALSE
}
if (lpBMIH->biSizeImage == 0) {
AfxMessageBox("Driver can't do compression")
::DeleteObject(hBitmap)
delete [] lpBMIH
::SelectPalette(hdc, hOldPalette, FALSE)
return FALSE
}
else {
m_dwSizeImage = lpBMIH->biSizeImage
}
}
else {
lpBMIH->biCompression = BI_RGB// decompress
// figure the image size from the bitmap width and height
DWORD dwBytes = ((DWORD) lpBMIH->biWidth * lpBMIH->biBitCount) / 32
if(((DWORD) lpBMIH->biWidth * lpBMIH->biBitCount) % 32) {
dwBytes++
}
dwBytes *= 4
m_dwSizeImage = dwBytes * lpBMIH->biHeight// no compression
lpBMIH->biSizeImage = m_dwSizeImage
}
// second GetDIBits call to make DIB
LPBYTE lpImage = (LPBYTE) new char[m_dwSizeImage]
VERIFY(::GetDIBits(pDC->GetSafeHdc(), hBitmap, 0, (UINT) lpBMIH->biHeight,
lpImage, (LPBITMAPINFO) lpBMIH, DIB_RGB_COLORS))
TRACE("dib successfully created - height = %d\n", lpBMIH->biHeight)
::DeleteObject(hBitmap)
Empty()
m_nBmihAlloc = m_nImageAlloc = crtAlloc
m_lpBMIH = lpBMIH
m_lpImage = lpImage
ComputeMetrics()
ComputePaletteSize(m_lpBMIH->biBitCount)
MakePalette()
::SelectPalette(hdc, hOldPalette, FALSE)
TRACE("Compress: new palette size = %d\n", m_nColorTableEntries)
return TRUE
}
BOOL CDib::Read(CFile* pFile)
{
// 1. read file header to get size of info hdr + color table
// 2. read info hdr (to get image size) and color table
// 3. read image
// can't use bfSize in file header
Empty()
int nCount, nSize
BITMAPFILEHEADER bmfh
try {
nCount = pFile->Read((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER))
if(nCount != sizeof(BITMAPFILEHEADER)) {
throw new CException
}
if(bmfh.bfType != 0x4d42) {
throw new CException
}
nSize = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER)
m_lpBMIH = (LPBITMAPINFOHEADER) new char[nSize]
m_nBmihAlloc = m_nImageAlloc = crtAlloc
nCount = pFile->Read(m_lpBMIH, nSize)// info hdr &color table
ComputeMetrics()
ComputePaletteSize(m_lpBMIH->biBitCount)
MakePalette()
m_lpImage = (LPBYTE) new char[m_dwSizeImage]
nCount = pFile->Read(m_lpImage, m_dwSizeImage)// image only
}
catch(CException* pe) {
AfxMessageBox("Read error")
pe->Delete()
return FALSE
}
return TRUE
}
BOOL CDib::ReadSection(CFile* pFile, CDC* pDC /* = NULL */)
{
// new function reads BMP from disk and creates a DIB section
//allows modification of bitmaps from disk
// 1. read file header to get size of info hdr + color table
// 2. read info hdr (to get image size) and color table
// 3. create DIB section based on header parms
// 4. read image into memory that CreateDibSection allocates
Empty()
int nCount, nSize
BITMAPFILEHEADER bmfh
try {
nCount = pFile->Read((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER))
if(nCount != sizeof(BITMAPFILEHEADER)) {
throw new CException
}
if(bmfh.bfType != 0x4d42) {
throw new CException
}
nSize = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER)
m_lpBMIH = (LPBITMAPINFOHEADER) new char[nSize]
m_nBmihAlloc = crtAlloc
m_nImageAlloc = noAlloc
nCount = pFile->Read(m_lpBMIH, nSize)// info hdr &color table
if(m_lpBMIH->biCompression != BI_RGB) {
throw new CException
}
ComputeMetrics()
ComputePaletteSize(m_lpBMIH->biBitCount)
MakePalette()
UsePalette(pDC)
m_hBitmap = ::CreateDIBSection(pDC->GetSafeHdc(), (LPBITMAPINFO) m_lpBMIH,
DIB_RGB_COLORS, (LPVOID*) &m_lpImage, NULL, 0)
ASSERT(m_lpImage != NULL)
nCount = pFile->Read(m_lpImage, m_dwSizeImage)// image only
}
catch(CException* pe) {
AfxMessageBox("ReadSection error")
pe->Delete()
return FALSE
}
return TRUE
}
BOOL CDib::Write(CFile* pFile)
{
BITMAPFILEHEADER bmfh
bmfh.bfType = 0x4d42 // 'BM'
int nSizeHdr = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries
bmfh.bfSize = 0
// bmfh.bfSize = sizeof(BITMAPFILEHEADER) + nSizeHdr + m_dwSizeImage
// meaning of bfSize open to interpretation (bytes, words, dwords?) -- we won't use it
bmfh.bfReserved1 = bmfh.bfReserved2 = 0
bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * m_nColorTableEntries
try {
pFile->Write((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER))
pFile->Write((LPVOID) m_lpBMIH, nSizeHdr)
pFile->Write((LPVOID) m_lpImage, m_dwSizeImage)
}
catch(CException* pe) {
pe->Delete()
AfxMessageBox("write error")
return FALSE
}
return TRUE
}
void CDib::Serialize(CArchive&ar)
{
DWORD dwPos
dwPos = ar.GetFile()->GetPosition()
TRACE("CDib::Serialize -- pos = %d\n", dwPos)
ar.Flush()
dwPos = ar.GetFile()->GetPosition()
TRACE("CDib::Serialize -- pos = %d\n", dwPos)
if(ar.IsStoring()) {
Write(ar.GetFile())
}
else {
Read(ar.GetFile())
}
}
// helper functions
void CDib::ComputePaletteSize(int nBitCount)
{
if((m_lpBMIH == NULL) || (m_lpBMIH->biClrUsed == 0)) {
switch(nBitCount) {
case 1:
m_nColorTableEntries = 2
break
case 4:
m_nColorTableEntries = 16
break
case 8:
m_nColorTableEntries = 256
break
case 16:
case 24:
case 32:
m_nColorTableEntries = 0
break
default:
ASSERT(FALSE)
}
}
else {
m_nColorTableEntries = m_lpBMIH->biClrUsed
}
ASSERT((m_nColorTableEntries >= 0) &&(m_nColorTableEntries <= 256))
}
void CDib::ComputeMetrics()
{
if(m_lpBMIH->biSize != sizeof(BITMAPINFOHEADER)) {
TRACE("Not a valid Windows bitmap -- probably an OS/2 bitmap\n")
throw new CException
}
m_dwSizeImage = m_lpBMIH->biSizeImage
if(m_dwSizeImage == 0) {
DWORD dwBytes = ((DWORD) m_lpBMIH->biWidth * m_lpBMIH->biBitCount) / 32
if(((DWORD) m_lpBMIH->biWidth * m_lpBMIH->biBitCount) % 32) {
dwBytes++
}
dwBytes *= 4
m_dwSizeImage = dwBytes * m_lpBMIH->biHeight// no compression
}
m_lpvColorTable = (LPBYTE) m_lpBMIH + sizeof(BITMAPINFOHEADER)
}
void CDib::Empty()
{
// this is supposed to clean up whatever is in the DIB
DetachMapFile()
if(m_nBmihAlloc == crtAlloc) {
delete [] m_lpBMIH
}
else if(m_nBmihAlloc == heapAlloc) {
::GlobalUnlock(m_hGlobal)
::GlobalFree(m_hGlobal)
}
if(m_nImageAlloc == crtAlloc) delete [] m_lpImage
if(m_hPalette != NULL) ::DeleteObject(m_hPalette)
if(m_hBitmap != NULL) ::DeleteObject(m_hBitmap)
m_nBmihAlloc = m_nImageAlloc = noAlloc
m_hGlobal = NULL
m_lpBMIH = NULL
m_lpImage = NULL
m_lpvColorTable = NULL
m_nColorTableEntries = 0
m_dwSizeImage = 0
m_lpvFile = NULL
m_hMap = NULL
m_hFile = NULL
m_hBitmap = NULL
m_hPalette = NULL
}
void CDib::DetachMapFile()
{
if(m_hFile == NULL) return
::UnmapViewOfFile(m_lpvFile)
::CloseHandle(m_hMap)
::CloseHandle(m_hFile)
m_hFile = NULL
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)