📄 bmpproc.cpp
字号:
HBITMAP hBmp = (HBITMAP)CGdiObject::Detach();
ASSERT(hBmp);
if (!hBmp)
return NULL;
m_hObject = NULL;
switch(m_type)
{
case IT_NULL:
ASSERT(FALSE); // 此时m_type不应该是IT_NULL
break;
case IT_DISKFILE:
ASSERT(!m_cFileName.IsEmpty()); // 文件来源的位图应该有文件名
case IT_RESOURCE:
case IT_MEMORY:
case IT_CLIP:
case IT_CREATE:
m_cFileName.Empty();
ASSERT(m_pInfo);
::free((void*)m_pInfo);
m_pInfo = NULL;
m_addInfo = 0;
m_type = IT_NULL;
m_mark = FALSE;
break;
default:
ASSERT(FALSE);
break;
}
return hBmp;
}
/*************************************************************************
*
* Save()
*
* 参数说明:
*
* LPCTSTR lpszNewFileName - 指定的新文件名(可以是NULL)
* WORD nBitsPerPixel - 指定的新颜色格式(即每像素多少位,可以是0)
*
* 返回值:
*
* BOOL - 如果成功返回TRUE,否则返回FALSE
*
* 描述:
*
* 将本身类中的位图以新的格式或新的名称保存到文件中
*
* 注:
*
* # 如果没有指定新的文件名(入口参数lpszNewFileName被指定为NULL),函数
* 就使用类中原来的文件名,如果类中原来没有文件名则函数失败,返回FALSE
* # 如果没有指定新的位数(入口参数nBitsPerPixel被指定为0),函数就使用类
* 中原来的位数值。如果新指定的位数值非法则函数失败,返回FALSE。合法的
* 位数值是1,4,8,16,24,32 其中之一
* # 如果本身类中原来没有位图(空类),函数返回FALSE
* # 如果文件没有打开或是写文件时出错,函数返回FALSE
* # 函数执行成功之后,本身类中的文件名或位数将改为新值
* # 无论函数成功与否,本身类中的位图不会改变
*
************************************************************************/
BOOL CBmpProc::Save(LPCTSTR lpszNewFileName, WORD nBitsPerPixel)
{
// 如果本身类中原来没有位图,函数返回FALSE
if (!IsValid())
return FALSE;
ASSERT(m_pInfo);
ASSERT(m_pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER));
LPBITMAPINFO pInfo;
BOOL bRet;
CString cOldFN;
// 以原来的格式保存到原来的文件中
if ((lpszNewFileName==NULL)&&(nBitsPerPixel==0))
{
// 应该有文件名
if (m_cFileName.IsEmpty())
return FALSE;
return SaveBaseSpecifyFileName((LPCTSTR)m_cFileName);
}
// 以原来的格式保存到新的文件中
if ((lpszNewFileName!=NULL)&&(nBitsPerPixel==0))
{
bRet = SaveBaseSpecifyFileName((LPCTSTR)lpszNewFileName);
if (bRet)
m_cFileName = lpszNewFileName;
return bRet;
}
// 以新的格式保存到原来的文件中
if ((lpszNewFileName==NULL)&&(nBitsPerPixel!=0))
{
// 检测位数合法性
if (!IsValidDibFormat(nBitsPerPixel))
return FALSE;
// 应该有文件名
if (m_cFileName.IsEmpty())
return FALSE;
bRet = SaveBaseSpecifyFormat(nBitsPerPixel);
if (bRet)
{
pInfo = GetSpecifyFormatInfo(nBitsPerPixel);
if (!pInfo)
return FALSE;
::free((void*)m_pInfo);
m_pInfo = pInfo;
}
return bRet;
}
// 以新的格式保存到新的文件中
if ((lpszNewFileName!=NULL)&&(nBitsPerPixel!=0))
{
// 检测位数合法性
if (!IsValidDibFormat(nBitsPerPixel))
return FALSE;
cOldFN = m_cFileName;
m_cFileName = lpszNewFileName;
bRet = SaveBaseSpecifyFormat(nBitsPerPixel);
if (bRet)
{ // 获取指定格式的信息块
pInfo = GetSpecifyFormatInfo(nBitsPerPixel);
if (!pInfo)
{
m_cFileName = cOldFN;
return FALSE;
}
::free((void*)m_pInfo);
m_pInfo = pInfo;
}
else
m_cFileName = cOldFN;
return bRet;
}
return FALSE;
}
/*************************************************************************
*
* SaveToClipboard()
*
* 参数说明:无
*
*
* 返回值:
*
* BOOL - 如果成功返回TRUE,否则返回FALSE
*
* 描述:
*
* 保存本身类中的位图到剪贴板
*
* 注:
*
* # 如果本身类中原来没有位图,函数返回FALSE
* # 如果在打开或写入剪贴板时出错,函数返回FALSE
* # 无论函数成功与否,本身类中的内容都不会改变
*
************************************************************************/
BOOL CBmpProc::SaveToClipboard()
{
// 如果本身类中原来没有位图,函数返回FALSE
if (!IsValid())
return FALSE;
ASSERT(m_pInfo);
ASSERT(m_pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER));
// 打开剪贴板
if (::OpenClipboard(NULL))
{
// 清空剪贴板
if (::EmptyClipboard())
{
DWORD DibSize = CalculateDIBSize((LPBITMAPINFOHEADER)m_pInfo);
DWORD infosize =CalculateDIBInfoSize((LPBITMAPINFOHEADER)m_pInfo);
// 分配DIB内部格式内存块
HANDLE hDib = ::GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, DibSize);
if (hDib)
{
LPSTR lpDib = (LPSTR)::GlobalLock(hDib);
if (lpDib)
{
::memcpy((void*)lpDib, (const void*)m_pInfo, infosize);
// 获取DIB位数据
HWND hWnd = ::GetDesktopWindow();
ASSERT(hWnd);
HDC hDC = ::GetDC(hWnd);
if (!::GetDIBits(hDC,(HBITMAP)m_hObject,0,m_pInfo->bmiHeader.biHeight,\
(LPVOID)((DWORD)lpDib+infosize),(LPBITMAPINFO)lpDib,DIB_RGB_COLORS))
{
::GlobalUnlock(hDib);
::GlobalFree(hDib);
::CloseClipboard();
::ReleaseDC(hWnd, hDC);
return FALSE;
}
::ReleaseDC(hWnd, hDC);
::GlobalUnlock(hDib);
// 将DIB数据贴入剪贴板
if (::SetClipboardData(CF_DIB, hDib))
{
// 如果成功,DIB句柄不应释放
::CloseClipboard();
return TRUE; // 成功
}
else
{
::GlobalFree(hDib);
::CloseClipboard();
return FALSE; // 失败
}
}
::GlobalFree(hDib);
}
}
::CloseClipboard();
}
return FALSE; // 失败
}
/*************************************************************************
*
* SaveBaseSpecifyFileName()
*
* 参数说明:
*
* LPCTSTR fn - 指定的文件名称
*
* 返回值:
*
* BOOL - 如果成功返回TRUE,否则返回FALSE
*
* 描述:
*
* 保存本身类中的位图到指定的文件中
*
* 注:
*
* # 如果指定的文件已经存在,则函数将覆盖该文件
* # 如果本身类中原来没有位图,函数返回FALSE
* # 如果文件没有打开或是写文件时出错,函数返回FALSE
* # 函数并不修改类中文件名
*
************************************************************************/
BOOL CBmpProc::SaveBaseSpecifyFileName(LPCTSTR fn)
{
// 如果本身类中原来没有位图,函数返回FALSE
if (!IsValid())
return FALSE;
ASSERT(m_pInfo);
// 如果没有指定文件名,返回FALSE
if (!fn)
return FALSE;
FILE *file;
// 用创建方式打开文件(二进制)
file = ::fopen(fn, "w+b");
if (!file)
return FALSE;
::fseek(file, 0, SEEK_SET);
BITMAPFILEHEADER bmf;
bmf.bfType = DIB_HEADER_MARKER; //((WORD) ('M' << 8) | 'B')
bmf.bfSize = CalculateDIBFileSize((LPBITMAPINFOHEADER)m_pInfo);
bmf.bfReserved1 = 0;
bmf.bfReserved2 = 0;
bmf.bfOffBits = CalculateDIBitsOff((LPBITMAPINFOHEADER)m_pInfo);
// 写入文件头信息
if (!::fwrite((const void *)&bmf, sizeof(BITMAPFILEHEADER), 1, file))
{
::fclose(file);
return FALSE;
}
// 复制信息块内容,之所以复制信息块而不直接使用m_pInfo,是因为
// GetDIBits()函数有可能改变信息块颜色表的内容
int infosize = CalculateDIBInfoSize((LPBITMAPINFOHEADER)m_pInfo);
ASSERT(infosize == (int)::_msize((void*)m_pInfo));
LPBITMAPINFO pInfo = (LPBITMAPINFO)CreateMemoryBlockFromAddress(
(LPVOID)m_pInfo);
if (!pInfo)
{
::fclose(file);
return FALSE;
}
// 写入信息块内容
if (!::fwrite((const void *)pInfo, infosize, 1, file))
{
::free((void*)pInfo);
::fclose(file);
return FALSE;
}
LPSTR pBits = (LPSTR)CreateMemoryBlockFromAddress((LPVOID)NULL,
CalculateDIBitsSize((LPBITMAPINFOHEADER)pInfo));
if (!pBits)
{
::free((void*)pInfo);
::fclose(file);
return FALSE;
}
// 获取DIB位数据
HWND hWnd = ::GetDesktopWindow();
ASSERT(hWnd);
HDC hDC = ::GetDC(hWnd);
if (!::GetDIBits(hDC,(HBITMAP)m_hObject,0,pInfo->bmiHeader.biHeight,\
(LPVOID)pBits,pInfo,DIB_RGB_COLORS))
{
::free((void*)pInfo);
::free((void*)pBits);
::fclose(file);
::ReleaseDC(hWnd, hDC);
return FALSE;
}
::ReleaseDC(hWnd, hDC);
// 信息块已无用,释放
::free((void*)pInfo);
DWORD dwA, dwB, dwC;
LPSTR lp = pBits;
// 以分段方式写入位数据,每个段长度为32KB。
dwA = CalculateDIBitsSize((LPBITMAPINFOHEADER)m_pInfo); // 总长度
dwB = dwA/32768; // 段数(32768)
dwC = dwA - (dwB*32768); // 余数
for (;dwB!=0;dwB--)
{
if (!::fwrite((const void *)lp, 32768, 1, file))
{
::free((void*)pBits);
::fclose(file);
return FALSE;
}
lp = (LPSTR)((DWORD)lp+32768UL);
}
// 写入剩余的位数据
if (!::fwrite((const void *)lp, dwC, 1, file))
{
::free((void*)pBits);
::fclose(file);
return FALSE;
}
// 位数据已无用,释放
::free((void*)pBits);
// 关闭文件
::fclose(file);
return TRUE;
}
/*************************************************************************
*
* SaveBaseSpecifyFormat()
*
* 参数说明:
*
* WORD nBitsPerPixel - 指定的格式(即每像素占多少位)
*
* 返回值:
*
* BOOL - 如果成功返回TRUE,否则返回FALSE
*
* 描述:
*
* 以指定的颜色格式保存本身类中的位图到原来的文件中
*
* 注:
*
* # 如果指定的文件已经存在,则函数将覆盖该文件
* # 如果本身类中原来没有位图,函数返回FALSE
* # 如果文件没有打开或是写文件时出错,函数返回FALSE
* # 如果指定的位数是非法值(1,4,8,16,24,32是合法值),函数返回FALSE
* # 函数并不修改类中信息块的内容
*
************************************************************************/
BOOL CBmpProc::SaveBaseSpecifyFormat(WORD nBitsPerPixel)
{
// 如果本身类中原来没有位图,函数返回FALSE
if (!IsValid())
return FALSE;
ASSERT(m_pInfo);
// 应该有文件名
if (m_cFileName.IsEmpty())
return FALSE;
// 检测位数合法性
if (!IsValidDibFormat(nBitsPerPixel))
return FALSE;
LPBITMAPINFO pTempInfo;
BOOL bRet;
// 获取指定格式DIB的信息块
LPBITMAPINFO pInfo = GetSpecifyFormatInfo(nBitsPerPixel);
if (!pInfo)
return FALSE;
// 保存原始信息块
pTempInfo = m_pInfo;
m_pInfo = pInfo; // 以原文件名存储
bRet = SaveBaseSpecifyFileName((LPCTSTR)m_cFileName);
m_pInfo = pTempInfo;
::free((void*)pInfo);
return bRet;
}
/*************************************************************************
*
* Create()
*
* 参数说明:
*
* int width - 创建位图的宽度
* int height - 创建位图的高度
* WORD nBitCount - 创建位图中每个像素所占的位数
* const void *lpBits - 新位图的初始化位数据(可以是NULL)
*
* 返回值:
*
* BOOL - 如果成功返回TRUE,否则返回FALSE
*
* 描述:
*
* 根据指定的数据创建一个位图,并贴入本身类中
*
* 注:
*
* # 入口参数width和height不能是0,如果指定了0,函数返回FALSE
* # 入口参数nBitCount的有效值可以是1,4,8,16,24,32,其它的值将视为非法
* # 如果本身类中原来存在图像,则调用函数成功之后,原来的图像将被删除
* # 如果入口参数lpBits是NULL,则新创建的位不被初始化
*
************************************************************************/
BOOL CBmpProc::Create(CSize size,
WORD nBitCount,
const void *lpBits)
{
return Create(size.cx, size.cy, nBitCount, lpBits);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -