📄 ddb.cpp
字号:
{
(pCQBox + i)->byFlag = 1; // not discard
pdwFrequency[i] = (pCQBox + i)->dwPixelCount;
}
//找出出现频率最少的16种颜色, 并标记为0
for(i = 0; i < 16; i++)
{
//最小值
DWORD dwMin = pdwFrequency[0];
int nIndexMin = 0;
for(j = 1; j < 252; j++)
{
if( pdwFrequency[j] < dwMin)
{
dwMin = pdwFrequency[j];
nIndexMin = j;
}
}
pdwFrequency[nIndexMin] = 100000000L;
(pCQBox + nIndexMin)->byFlag = 0; //discard
}
delete[] pdwFrequency;
//第三步, 为LOGOALETTE分配内存, 并对其进行填充:
HDC hDC = ::GetDC(NULL); //If this value is NULL, GetDC retrieves the device context for the entire screen.
BYTE* pbyLogPalette = new BYTE[sizeof(LOGPALETTE) + 256 * sizeof(PALETTEENTRY)];
if(pbyLogPalette == NULL)return;
memset(pbyLogPalette, 0 , (sizeof(LOGPALETTE) + 256 * sizeof(PALETTEENTRY)));
LOGPALETTE* pLogPalette = (LOGPALETTE*)pbyLogPalette;
pLogPalette->palVersion = 0x300;
pLogPalette->palNumEntries = 256;
//获取系统调色盘的信息.//
::GetSystemPaletteEntries(hDC, 0, 256, pLogPalette->palPalEntry);
::ReleaseDC(NULL, hDC);
//第四步, 采用颜色量化结果改写位于中间的236项, 并建立映射表
//将填入236项的顺序号
int nIndexMid = 10;
//记录被抛弃的顺序
int nIndexThrow = 0;
//保存被抛弃的项
BYTE abyDiscard[16];
//映射表
int anMap[252];
//从252种入选颜色中顺序填入236种颜色:
for(i = 0; i < 252; i++)
{
if((pCQBox + i)->byFlag != 0)
{
DWORD dwNum = (pCQBox + i)->dwPixelCount;
if(dwNum == 0)dwNum = 1;
(pLogPalette->palPalEntry + nIndexMid)->peBlue = (BYTE)(((pCQBox + i)->dwBlueSum) / dwNum);
(pLogPalette->palPalEntry + nIndexMid)->peGreen = (BYTE)(((pCQBox + i)->dwGreenSum) / dwNum);
(pLogPalette->palPalEntry + nIndexMid)->peRed = (BYTE)(((pCQBox + i)->dwRedSum) / dwNum);
(pLogPalette->palPalEntry + nIndexMid)->peFlags = PC_NOCOLLAPSE;
anMap[i] = nIndexMid;
nIndexMid++;
}
else
{
abyDiscard[nIndexThrow] = i;
nIndexThrow++;
}
}
//第五步, 创建逻辑调色盘, 对于16种被抛弃的颜色向邻近颜色映射
pPalette->CreatePalette(pLogPalette);
for(i = 0; i < 16; i++)
{
DWORD dwNum = (pCQBox + i)->dwPixelCount;
if(dwNum == 0)dwNum = 1;
BYTE byRed = (BYTE)(((pCQBox + abyDiscard[i])->dwRedSum) / dwNum);
BYTE byGreen = (BYTE)(((pCQBox + abyDiscard[i])->dwGreenSum) / dwNum);
BYTE byBlue = (BYTE)(((pCQBox + abyDiscard[i])->dwBlueSum) / dwNum);
anMap[abyDiscard[i]] = (BYTE)pPalette->GetNearestPaletteIndex(RGB(byRed, byGreen, byBlue));
}
//第六步, 对8位数据重新进行映射
DWORD dwSize = dwWidthBytes8 * nScanHeight;
BYTE* pbyBits8 = lpbyDdbBits8;
while(dwSize--)
{
*pbyBits8 = anMap[*pbyBits8];
pbyBits8++;
}
delete[] pbyColorBox;
delete[] pbyLogPalette;
}
void CDdb::Save(const char *pszDibFileName, int x, int y, int nWidth, int nHeight)
{
ASSERT(pszDibFileName);
//首先进行参数合法性检测
if((x > m_nWidth - 1) || (y > nHeight - 1))
{
AfxMessageBox("Cross the border!");
return;
}
AfxGetApp()->BeginWaitCursor();
//被保存的最后有效宽度和高度:w , h.
LONG w = (LONG)min(nWidth, m_nWidth - x);
LONG h = (LONG)min(nHeight, m_nHeight - y);
//被保存位图每行的字节数
DWORD dwSaveWidthBytes = CalcDibWidthBytes(w, m_nBitCount);
//DIB位图数据大小, 以字节为单位
DWORD dwDibBitsSize = dwSaveWidthBytes * m_nHeight;
//计算整个Dib文件的大小dwFileSize
DWORD dwFileSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwDibBitsSize;
if(m_nBitCount == 8) dwFileSize += (256 * sizeof(RGBQUAD));
//计算位图信息到位图数据间的偏移量(字节)
DWORD dwOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
if(m_nBitCount == 8) dwOffBits += (256 * sizeof(RGBQUAD));
//位图文件头结构和位图信息结构
BITMAPFILEHEADER bmFileHeader;
BITMAPINFOHEADER bmInfo;
//填充BITMAPFILEHEADER结构
bmFileHeader.bfType=0x4d42;
bmFileHeader.bfSize = dwFileSize;
bmFileHeader.bfReserved1 = 0;
bmFileHeader.bfReserved2 = 0;
bmFileHeader.bfOffBits = dwOffBits;
//填充BITMAPINFOHEADER结构:8位仍然保存为8位, 其它均被保存为24位.最低显示模式为8位.
WORD wBitsPixel = (WORD)m_nBitCount;
if(m_nBitCount != 8)wBitsPixel = 24;
bmInfo.biSize = sizeof(BITMAPINFOHEADER);
bmInfo.biWidth = w;
bmInfo.biHeight = h;
bmInfo.biPlanes = 1;
bmInfo.biBitCount = wBitsPixel;
bmInfo.biCompression = 0;
bmInfo.biSizeImage = 0;
bmInfo.biXPelsPerMeter = 0;
bmInfo.biYPelsPerMeter = 0;
bmInfo.biClrUsed = 0;
bmInfo.biClrImportant = 0;
try
{
// 请创建自己的目录或获取当前目录:
CFile file((LPCTSTR )pszDibFileName, CFile::modeCreate |
CFile::modeReadWrite | CFile::shareExclusive);
//写入文件头和位图信息
file.Write((LPSTR)&bmFileHeader, sizeof(BITMAPFILEHEADER));
file.Write((LPSTR)&bmInfo, sizeof(BITMAPINFOHEADER));
//如果是8位显示模式, 还需要写入调色盘表项
if(m_nBitCount == 8)
{
//为8位显示模式准备调色盘
RGBQUAD* pRGBQuad = new RGBQUAD[256];
if(pRGBQuad == NULL)return;
//初始化为0
memset(pRGBQuad, 0, 256 * sizeof(RGBQUAD));
//创建表项:可能丢失颜色
GetSystemPaletteEntries(pRGBQuad);
//写入数据
file.Write((LPSTR)pRGBQuad, 256 * sizeof(RGBQUAD));
delete[] pRGBQuad;
}
switch(m_nBitCount)
{
case 8:
case 24:
{
//每行需要补0的个数
DWORD dwLength = (m_nBitCount == 8) ? w : (3 * w);
UINT nZero = dwSaveWidthBytes - dwLength;
BYTE abyZero[] = {0, 0, 0};
//数据索引基数, 从下往上读
DWORD dwBaseIndex = (y + h - 1) * m_nDdbWidthBytes + ((m_nBitCount == 8) ? x : (3 * x));
for(LONG i = 0; i < h ; i++)
{
LPSTR lpsRaw = (LPSTR)(m_pDdbData + dwBaseIndex);
//写入子数据, 注意数据量小于64k, 位图宽度可达22767个像素单位或更高
file.Write(lpsRaw, dwLength); //
//结尾补0
if(nZero > 0) file.Write((LPSTR)abyZero, nZero);
dwBaseIndex -= m_nDdbWidthBytes;
}
}
break;
case 16:
case 32:
{
//对于16位和32位位图, 由于数据需要重组, 所以需要重新分配内存
//指向Dib实际像素数据的指针,
BYTE* pbyDibBits = new BYTE[dwDibBitsSize];
if (pbyDibBits == NULL) return;
//数据索引基数
DWORD dwBaseIndex = y * m_nDdbWidthBytes + ((m_nBitCount == 16) ? (x + x) : (4 * x));
DWORD dwIndexDib = (h - 1) * dwSaveWidthBytes;
//离析像素数据, 并将其写入内存, 从上往下读
for(LONG i = 0; i < h; i++)
{
//指向Ddb内存数据的指针(行)
BYTE* pbyDdbData = m_pDdbData + dwBaseIndex;
//指向Dib内存数据的指针(行)
BYTE* pbyDibData = pbyDibBits + dwIndexDib;
for(LONG j = 0; j < w; j++)
{
//处理16位
if(m_nBitCount == 16)
{
//记录一个像素点的24位颜色值(16位和32位模式均被转化为24位)
BYTE* pbyRGB = new BYTE[3];
WORD* pwDdbData_16 = (WORD*)(pbyDdbData++);
GetRGB16(pbyRGB, pwDdbData_16);
pbyDdbData++;
*pbyDibData++ = pbyRGB[0]; //b
*pbyDibData++ = pbyRGB[1]; //g
*pbyDibData++ = pbyRGB[2]; //r
delete[] pbyRGB;
}
//处理32位
if(m_nBitCount == 32)
{
*pbyDibData++ = *pbyDdbData++; //蓝色
*pbyDibData++ = *pbyDdbData++; //绿色
*pbyDibData++ = *pbyDdbData++; //红色
pbyDdbData++;
}
}//end j
dwBaseIndex += m_nDdbWidthBytes;
dwIndexDib -= dwSaveWidthBytes;
}//end i
//将内存数据写入文件
file.WriteHuge((LPSTR)pbyDibBits, dwDibBitsSize);
delete[] pbyDibBits;
}
break;
}
file.Close();
}//end try
catch(CFileException* e)
{
e->Delete();
}
AfxGetApp()->EndWaitCursor();
}
void CDdb::Save256(const char *pszDibFileName, int x, int y, int nWidth, int nHeight)
{
ASSERT(pszDibFileName);
if(m_nBitCount <= 8)
{
Save(pszDibFileName, x, y, nWidth, nHeight);
return;
}
//首先进行参数合法性检测
if((x > m_nWidth - 1) || (y > nHeight - 1))
{
AfxMessageBox("Cross the border!");
return;
}
AfxGetApp()->BeginWaitCursor();
//被保存的最后有效宽度和高度:w , h.
LONG w = (LONG)min(nWidth, m_nWidth - x);
LONG h = (LONG)min(nHeight, m_nHeight - y);
//////////////////////////////////////////////////////
//第一步:将数据转化为24位DDB数据
//原DDB数据转换成24位后, 每行的大小和总的数据量
DWORD dwWidthBytes24 = ((w * 24 + 15) / 16) * 2;
DWORD dwBitsSize24 = dwWidthBytes24 * h;
//分配全局内存, 以存放经格式转换后的像素数据
//指向24位数据的指针
BYTE* pbyDdbBits24 = new BYTE[dwBitsSize24];
if(pbyDdbBits24 == NULL) return;
memset(pbyDdbBits24, 0, dwBitsSize24);
//指向24位像素数据的指针, 这些数据是由16, 24, 32位模式转化而来的.
GetDdbDataTo24(x, y, w, h, pbyDdbBits24);
//////////////////////////////////////////////////////
//第二步, 获取量化后的数据
//分配存储8位数据的内存
DWORD dwWidthBytes8 = ((w * 8 + 15) / 16) * 2;
DWORD dwBitsSize8 = dwWidthBytes8 * h;
//指向8位数据的指针
BYTE* pbyDdbBits8 = new BYTE[dwBitsSize8];
if (pbyDdbBits8 == NULL)return ;
memset(pbyDdbBits8, 0 , dwBitsSize8);
//////////////////////////////////////////////////////
//获取量化数据
CPalette* pPalette = new CPalette();
QuantizeColor(pbyDdbBits24, w, h, pbyDdbBits8, pPalette);
//////////////////////////////////////////////////////
//获取调色数据
RGBQUAD* pRGBQuad = new RGBQUAD[256];
if(pRGBQuad == NULL)return;
//初始化为0
memset(pRGBQuad, 0, 256 * sizeof(RGBQUAD));
PALETTEENTRY* pPE = new PALETTEENTRY[256];
if(pPE == NULL)return;
pPalette->GetPaletteEntries(0, 256, pPE);
for(int j = 0; j < 256; j++)
{
pRGBQuad[j].rgbRed = pPE[j].peRed;
pRGBQuad[j].rgbGreen = pPE[j].peGreen;
pRGBQuad[j].rgbBlue = pPE[j].peBlue;
}
delete[] pPE;
delete pPalette;
//////////////////////////////////////////////////////
//第三步, 填充与位图相关的结构
//宽度字节数
DWORD dwDibWidthBytes = ((w * 8 + 31) / 32) * 4;
//位图数据大小
DWORD dwDibBitsSize = dwDibWidthBytes * h;
//计算整个Dib文件的大小dwFileSize
DWORD dwFileSize = sizeof(BITMAPFILEHEADER)
+ sizeof(BITMAPINFOHEADER)
+ 256 * sizeof(RGBQUAD)
+ dwDibBitsSize;
//计算位图信息到位图数据间的偏移量(字节)
DWORD dwOffBits = sizeof(BITMAPFILEHEADER)
+ sizeof(BITMAPINFOHEADER)
+ 256 * sizeof(RGBQUAD);
//位图文件头结构和位图信息结构
BITMAPFILEHEADER bmFileHeader;
BITMAPINFOHEADER bmInfo;
//填充BITMAPFILEHEADER结构
bmFileHeader.bfType=0x4d42;
bmFileHeader.bfSize = dwFileSize;
bmFileHeader.bfReserved1 = 0;
bmFileHeader.bfReserved2 = 0;
bmFileHeader.bfOffBits = dwOffBits;
//填充BITMAPINFOHEADER结构
bmInfo.biSize = sizeof(BITMAPINFOHEADER);
bmInfo.biWidth = w;
bmInfo.biHeight = h;
bmInfo.biPlanes = 1;
bmInfo.biBitCount = 8;
bmInfo.biCompression = 0;
bmInfo.biSizeImage = 0;
bmInfo.biXPelsPerMeter = 0;
bmInfo.biYPelsPerMeter = 0;
bmInfo.biClrUsed = 0;
bmInfo.biClrImportant = 0;
//第四步, 写数据
//////////////////////////////////////////////////////
try
{
// 请创建自己的目录或获取当前目录:
CFile file((LPCTSTR )pszDibFileName, CFile::modeCreate |
CFile::modeReadWrite | CFile::shareExclusive);
//写入文件头和位图信息
file.Write((LPSTR)&bmFileHeader, sizeof(BITMAPFILEHEADER));
file.Write((LPSTR)&bmInfo, sizeof(BITMAPINFOHEADER));
//写入数据
file.Write((LPSTR)pRGBQuad, 256 * sizeof(RGBQUAD));
delete[] pRGBQuad;
pRGBQuad = NULL;
//数据索引(行头)
DWORD dwBaseIndex = (DWORD)(h - 1) * dwWidthBytes8;
UINT nZero = dwDibWidthBytes - dwWidthBytes8;
BYTE abyZero[] = {0, 0};
for(int i = 0; i < h ; i++)
{
BYTE* pDibBits8 = pbyDdbBits8 + dwBaseIndex;
file.Write((LPSTR)pDibBits8, dwWidthBytes8);
if(nZero > 0)file.Write((LPSTR)abyZero, 2);
dwBaseIndex -= dwWidthBytes8;
}//end i
file.Close();
}//end try
catch(CFileException* e)
{
e->Delete();
}
if(pRGBQuad)delete[] pRGBQuad;
delete[] pbyDdbBits24;
delete[] pbyDdbBits8;
AfxGetApp()->EndWaitCursor();
}
BOOL CDdb::Draw(CDC *pDstDC, int x, int y, int nWidth, int nHeight, int xSrc,
int ySrc, int nSrcWidth, int nSrcHeight, DWORD dwRop)
{
CDC memoryDC;
memoryDC.CreateCompatibleDC(pDstDC);
CBitmap* pOldBitmap = memoryDC.SelectObject(m_pDdb);
BOOL bDraw = (pDstDC->StretchBlt(x, y, nWidth, nHeight, &memoryDC, xSrc, ySrc, nSrcWidth, nSrcHeight, dwRop ));
memoryDC.SelectObject(pOldBitmap);
return (bDraw);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -