我思路
1.拷贝当前窗口,对话框以图片形式保存起来。
(1)拷贝当前对话框
HBITMAP CYouDlg::CopyScreenToBitmap(LPRECT lpRect)
{
HDC hScrDC, hMemDC;
// 屏幕和内存设备描述表
HBITMAP hBitmap,hOldBitmap;
// 位图句柄
int nX, nY, nX2, nY2;
// 选定区域坐标
int nWidth, nHeight;
// 位图宽度和高度
int xScrn, yScrn;
// 屏幕分辨率
// 确保选定区域不为空矩形
if (IsRectEmpty(lpRect))
return NULL;
//为屏幕创建设备描述表
hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL);
//为屏幕设备描述表创建兼容的内存设备描述表
hMemDC = CreateCompatibleDC(hScrDC);
// 获得选定区域坐标
nX = lpRect->left;
nY = lpRect->top;
nX2 = lpRect->right;
nY2 = lpRect->bottom;
// 获得屏幕分辨率
xScrn = GetDeviceCaps(hScrDC, HORZRES);
yScrn = GetDeviceCaps(hScrDC, VERTRES);
//确保选定区域是可见的
if (nX < 0)
nX = 0;
if (nY < 0)
nY = 0;
if (nX2 > xScrn)
nX2 = xScrn;
if (nY2 > yScrn)
nY2 = yScrn;
nWidth = nX2 - nX;
nHeight = nY2 - nY;
// 创建一个与屏幕设备描述表兼容的位图
hBitmap=CreateCompatibleBitmap(hScrDC,nWidth,nHeight);
// 把新位图选到内存设备描述表中
hOldBitmap=(HBITMAP)SelectObject(hMemDC,hBitmap);
// 把屏幕设备描述表拷贝到内存设备描述表中
BitBlt(hMemDC,0,0, nWidth,nHeight,hScrDC, nX, nY, SRCCOPY);
//得到屏幕位图的句柄
hBitmap=(HBITMAP)SelectObject(hMemDC,hOldBitmap);
//清除
DeleteDC(hScrDC);
DeleteDC(hMemDC);
// 返回位图句柄
return hBitmap;
}
(2)保存窗口
int CYouDlg::SaveBitmapToFile(HBITMAP hBitmap, LPSTR lpFileName)
{
HDC hDC;
//设备描述表
int iBits;
//当前显示分辨率下每个像素所占字节数
WORD wBitCount;
//位图中每个像素所占字节数
//定义调色板大小, 位图中像素字节大小 , 位图文件大小 , 写入文件字节数
DWORD dwPaletteSize=0,dwBmBitsSize,dwDIBSize, dwWritten;
BITMAP Bitmap;
//位图属性结构
BITMAPFILEHEADER bmfHdr;
//位图文件头结构
BITMAPINFOHEADER bi;
//位图信息头结构
LPBITMAPINFOHEADER lpbi;
//指向位图信息头结构
HANDLE fh, hDib, hPal;
HPALETTE hOldPal=NULL;
//定义文件,分配内存句柄,调色板句柄
//计算位图文件每个像素所占字节数
hDC = CreateDC("DISPLAY",NULL,NULL,NULL);
iBits = GetDeviceCaps(hDC, BITSPIXEL) *
GetDeviceCaps(hDC, PLANES);
DeleteDC(hDC);
if (iBits <= 1)
wBitCount = 1;
else if (iBits <= 4)
wBitCount = 4;
else if (iBits <= 8)
wBitCount = 8;
else if (iBits <= 24)
wBitCount = 24;
else
wBitCount = 32;
//计算调色板大小
if (wBitCount <= 8)
dwPaletteSize=(1<<wBitCount)*sizeof(RGBQUAD);
//设置位图信息头结构
GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap);
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = Bitmap.bmWidth;
bi.biHeight = Bitmap.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = wBitCount;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
dwBmBitsSize = ((Bitmap.bmWidth*wBitCount+31)/32)*4*Bitmap.bmHeight;
//为位图内容分配内存
/*xxxxxxxx计算位图大小分解一下(解释一下上面的语句)xxxxxxxxxxxxxxxxxxxx
//每个扫描行所占的字节数应该为4的整数倍,具体算法为:
int biWidth = (Bitmap.bmWidth*wBitCount) / 32;
if((Bitmap.bmWidth*wBitCount) % 32)
biWidth++; //不是整数倍的加1
biWidth *= 4;//到这里,计算得到的为每个扫描行的字节数。
dwBmBitsSize = biWidth * Bitmap.bmHeight;//得到大小
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
hDib = GlobalAlloc(GHND,dwBmBitsSize+dwPaletteSize+sizeof(BITMAPINFOHEADER));
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
*lpbi = bi;
// 处理调色板
hPal = GetStockObject(DEFAULT_PALETTE);
if (hPal)
{
hDC = ::GetDC(NULL);
hOldPal=SelectPalette(hDC,(HPALETTE)hPal,FALSE);
RealizePalette(hDC);
}
// 获取该调色板下新的像素值
GetDIBits(hDC,hBitmap,0,(UINT)Bitmap.bmHeight,(LPSTR)lpbi+sizeof(BITMAPINFOHEADER)+dwPaletteSize, (BITMAPINFO *)lpbi,DIB_RGB_COLORS);
//恢复调色板
if (hOldPal)
{
SelectPalette(hDC, hOldPal, TRUE);
RealizePalette(hDC);
::ReleaseDC(NULL, hDC);
}
//创建位图文件
fh=CreateFile(lpFileName, GENERIC_WRITE,0, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (fh==INVALID_HANDLE_VALUE)
return FALSE;
// 设置位图文件头
bmfHdr.bfType = 0x4D42; // "BM"
dwDIBSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+dwPaletteSize+dwBmBitsSize;
bmfHdr.bfSize = dwDIBSize;
bmfHdr.bfReserved1 = 0;
bmfHdr.bfReserved2 = 0;
bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER)+(DWORD)sizeof(BITMAPINFOHEADER)+dwPaletteSize;
// 写入位图文件头
WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);
// 写入位图文件其余内容
WriteFile(fh, (LPSTR)lpbi, sizeof(BITMAPINFOHEADER)+dwPaletteSize+dwBmBitsSize , &dwWritten, NULL);
//清除
GlobalUnlock(hDib);
GlobalFree(hDib);
CloseHandle(fh);
return TRUE;
}
如果只保存当前彩色图片。那么可以添加一个CButton按钮。ID:IDC_SAVEBMP Caption :保存当前图片 为其添加消息映射
void CYouDlg::OnSavebmp()
{
CRect rect;
GetWindowRect(&rect);
HBITMAP hMap = CopyScreenToBitmap(rect);
SaveBitmapToFile(hMap,"C://mydlg.bmp");
}
2.把当前窗口的图片转换为黑白的。
void CYouDlg::OnChangebmp()
{
CFile BmpFile,GrayBmp;
BITMAPFILEHEADER bf,Dstbf;
BITMAPINFOHEADER bi,Dstbi;
DWORD dwLineBytes;
BYTE *pData;
BYTE *pGrayData;
LPSTR lpPtr;
LPSTR lpTempPtr;
int x,y;
float Y;//YUV中存Y的值,就是灰度值
DWORD i;//临时变量
BYTE Red,Green,Blue,Gray;
DWORD SrcBuf,DstBuf;
BmpFile.Open("C://mydlg.bmp",CFile::modeRead|CFile::typeBinary);
BmpFile.Read(&bf,sizeof(BITMAPFILEHEADER));
BmpFile.Read(&bi,sizeof(BITMAPINFOHEADER));
dwLineBytes=(DWORD)WIDTHBYTES(bi.biWidth*bi.biBitCount);
SrcBuf=dwLineBytes*bi.biHeight;
pData=(BYTE *)new BYTE[SrcBuf];
BmpFile.Read(pData,SrcBuf);
BmpFile.Close();
memcpy((char *)&Dstbf,(char *)&bf,sizeof(BITMAPFILEHEADER)); //做必要的改变
Dstbf.bfSize=(DWORD)(sizeof(BITMAPFILEHEADER)
+sizeof(BITMAPINFOHEADER)
+256*sizeof(RGBQUAD)
+WIDTHBYTES(bi.biWidth*8)*bi.biHeight);//文件大小
Dstbf.bfOffBits=(DWORD)(sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD));//文件头到存放图像数据的偏移量
memcpy((char *)&Dstbi,(char *)&bi,sizeof(BITMAPINFOHEADER));
Dstbi.biClrUsed=0;
Dstbi.biBitCount=8;//256级灰度图是8位的
Dstbi.biSizeImage=(DWORD)WIDTHBYTES(Dstbi.biWidth*8)*Dstbi.biHeight;
pGrayData=(BYTE *)new BYTE[Dstbi.biSizeImage+256*sizeof(RGBQUAD)];
lpPtr=(char *)pData;
lpTempPtr=(char *)pGrayData;
for (i = 0; i < 256; i++)
{ //灰度从(0,0,0)到(255,255,255),灰度调色板
*(lpTempPtr++)=(unsigned char)i;
*(lpTempPtr++)=(unsigned char)i;
*(lpTempPtr++)=(unsigned char)i;
*(lpTempPtr++)=0;
}
for(y=0;y<bi.biHeight;y++)
{
lpPtr=(char *)pData+SrcBuf-dwLineBytes-y*dwLineBytes;
lpTempPtr=(char*)pGrayData+Dstbi.biSizeImage+256*sizeof(RGBQUAD)-WIDTHBYTES(bi.biWidth*8)-y*WIDTHBYTES(bi.biWidth*8);
for(x=0;x<bi.biWidth;x++)
{
Blue=(BYTE)(*lpPtr++);
Green=(BYTE)(*lpPtr++);
Red=(BYTE)(*lpPtr++);
// Y=(float)(Red*0.299+Green*0.587+Blue*0.114);
//Y=(float)(Red*0.28965+Green*0.60581+Blue*0.10454); //灰白
Y=(float)(Red+Green+Blue)/3;
//Y=max(Blue,max(Green,Red));
if(Y<128)
{
Y=0; //RGB(0,0,0)
}
else
Y=765; //RGB(255,255,255)
//从位图数据计算得到Y值,写入新图中
Gray=(BYTE)Y;
*(lpTempPtr++)=(unsigned char)Gray;
}
}
GrayBmp.Open("C://mydlg1.bmp",CFile::modeCreate|CFile::modeWrite|CFile::typeBinary);
GrayBmp.Write(&Dstbf,sizeof(BITMAPFILEHEADER));
GrayBmp.Write(&Dstbi,sizeof(BITMAPINFOHEADER));
GrayBmp.Write(pGrayData,256*sizeof(RGBQUAD)+Dstbi.biSizeImage);
GrayBmp.Close();
delete[] pData;
delete[] pGrayData;
}
3.打印转换后的黑白对话框。
void CYouDlg::PrintBmp()
{
CDC memDC;
CClientDC dc(this);
int bmpWidth = 1600;
int bmpHeight = 500;
memDC.CreateCompatibleDC( &dc );
CBitmap * bitmap = new CBitmap();
HBITMAP hBitmap = NULL;
hBitmap = (HBITMAP)LoadImage(NULL, "C://mydlg1.bmp", IMAGE_BITMAP, 0, 0,
LR_LOADFROMFILE | LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
bitmap->Attach(hBitmap);
CBitmap * pOldBitmap = (CBitmap *) memDC.SelectObject( bitmap );
if (pOldBitmap == NULL) // if bitmap is very big, better check this !
{
memDC.DeleteDC();
delete bitmap;
return;
}
CDC prtDC;
CPrintInfo printInfo;
CSize size;
DOCINFO di;
CString szPortName, szAppName, szPrintError;
szAppName.LoadString(AFX_IDS_APP_TITLE);
szPrintError = "";
CSize paper_size; //printer paper size in mm
int xLogPPI = 0;
int yLogPPI = 0;
if( AfxGetApp()->GetPrinterDeviceDefaults(&printInfo.m_pPD->m_pd) )
{
HDC hDC = printInfo.m_pPD->m_pd.hDC;
if (hDC == NULL)
hDC = printInfo.m_pPD->CreatePrinterDC();
if(hDC !=NULL)
{
prtDC.Attach(hDC);
paper_size.cx = prtDC.GetDeviceCaps(HORZSIZE);
paper_size.cy = prtDC.GetDeviceCaps(VERTSIZE);
xLogPPI = prtDC.GetDeviceCaps(LOGPIXELSX);
yLogPPI = prtDC.GetDeviceCaps(LOGPIXELSY);
}
else
{
AfxMessageBox("Can not find printer. Please check installed/default printers.");
return;
}
}
int scr_xLogPPI = dc.GetDeviceCaps(LOGPIXELSX);
int scr_yLogPPI = dc.GetDeviceCaps(LOGPIXELSY);
int paper_width = (int) ((double) paper_size.cx * (double) xLogPPI / 25.4); //width of a printed page in pixels
int paper_height = (int) ((double) paper_size.cy * (double) yLogPPI / 25.4);
double ratio_x = (double) xLogPPI / (double) scr_xLogPPI;
double ratio_y = (double) yLogPPI / (double) scr_yLogPPI;
CString strPageNumber = "";
int page_info_left = (int) ( (double) paper_width * 0.9 );
int page_info_right = paper_width;
int page_info_top = (int) ( (double) paper_height * 0.99);
int page_info_bottom = paper_height;
CRect page_info_rect = CRect(page_info_left, page_info_top,
page_info_right,page_info_bottom );
int printed_pages = 0;
int total_print_pages = 0;
BOOL bAbort_print = FALSE;
// calculate pages
int total_pages = (bmpWidth * ratio_x + paper_width - 1 ) / paper_width;
//pop up printer dialog
CPrintDialog prtDlg(FALSE, PD_PAGENUMS);
prtDlg.m_pd.nMinPage = 1;
//total_pages=1;
prtDlg.m_pd.nMaxPage = total_pages; //等于3
prtDlg.m_pd.nFromPage = 1;
//total_pages=1;
prtDlg.m_pd.nToPage = total_pages; //等于3
if(prtDlg.DoModal() == IDOK )
{
memset(&di, 0, sizeof(DOCINFO));
di.cbSize = sizeof(DOCINFO);
di.lpszDocName = szAppName;
szPortName = prtDlg.GetPortName();
di.lpszOutput = szPortName;
prtDC.m_bPrinting = TRUE;
}
else
return; //Cancel button pressed, don't forget this!
if(prtDC.StartDoc(&di) == -1)
{
AfxMessageBox("Printing error occured. Unable to find printer.");
prtDC.Detach();
prtDC.DeleteDC();
return;
}
prtDC.SetMapMode(MM_TEXT);
int i = 0;
for(i = 0; i < 1; i++)
{
prtDC.StartPage();
strPageNumber.Format("Page:%d of %d", ++printed_pages, total_print_pages );
if ( i == (total_pages - 1) && total_pages > 1 ) //last page
{
int last_bmpWidth = bmpWidth - paper_width / ratio_x * i;
prtDC.StretchBlt(0, 0, last_bmpWidth * ratio_x, bmpHeight* ratio_y, &memDC,
paper_width * i / ratio_x, 0, last_bmpWidth, bmpHeight, SRCCOPY);
}
else
prtDC.StretchBlt(0, 0, paper_width, bmpHeight* ratio_y, &memDC,
paper_width * i / ratio_x, 0, paper_width / ratio_x , bmpHeight, SRCCOPY);
prtDC.TextOut(page_info_rect.left, page_info_rect.top, strPageNumber );
prtDC.EndPage();
}
memDC.SelectObject(pOldBitmap);
delete bitmap;
memDC.DeleteDC();
prtDC.EndDoc();
prtDC.Detach();
prtDC.DeleteDC();
return;
}
如果打印成黑白,那么可以添加一个CButton按钮。ID:IDC_PRINTBMP Caption :打印 为其添加消息映射
void CYouDlg::OnPrint()
{
CRect rect;
GetWindowRect(&rect);
HBITMAP hMap = CopyScreenToBitmap(rect);
SaveBitmapToFile(hMap,"C://mydlg.bmp");
OnChangebmp();
PrintBmp();
}