MFC 视图-OpenGL场景-CDialogBar三个界面保存为图片
问题:如图所示的OpenGL场景、View、CDialogBar三个界面的内容保存成图片然后拼合成一张图
思路:
分四步
一、View视图界面保存
利用BitBlt函数将界面拷贝到内存DC中
// 将MFC的某个view保存为图片
BOOL CImageIO::saveAsImage(CString imageFormat, CString savePath)
{if (hdc != NULL && destRect != NULL){HDC hmemDC = ::CreateCompatibleDC(hdc);hBmp = ::CreateCompatibleBitmap(hdc, destRect.Width(), destRect.Height());HANDLE hOld = ::SelectObject(hmemDC, hBmp);Graphics graphic(hmemDC);SelectObject(hmemDC, hBmp);// CDC类的BitBlt就是MFC下专门用来操作位图的,将两张位图分别导入到CBitmap做成内存DC后,一次BitBlt到设备DC上,就完成了图片的叠加,叠加效果,由BitBlt函数的光栅代码参数决定,详细看这个函数的帮助(内容不少),可以熟悉不同的叠加方式BitBlt(hmemDC, 0, 0, destRect.right, destRect.bottom, hdc, 0, 0, SRCCOPY); //下面进行各种文字、图形、图片的绘制Bitmap bitmap(hBmp, NULL);CLSID clsID;//保存不同格式的(.jpg,bmp,png)的图片需要不同的CLSID, imageFormat为用户期望保存的图片格式if (_T("jpg") == imageFormat.MakeLower()){GetEncoderClsid(L"image/jpeg", &clsID);}else if (_T("bmp") == imageFormat.MakeLower()){GetEncoderClsid(L"image/bmp", &clsID);}else if (_T("png") == imageFormat.MakeLower()){GetEncoderClsid(L"image/png", &clsID);}// char*转WCHAR*char *p = (LPSTR)(LPCSTR)savePath;wstringstream wss;wss << p;bitmap.Save(wss.str().c_str(), &clsID, NULL);//bitmap.Save(L"D:\\ggg.jpg", &clsID, NULL);::SelectObject(hmemDC, hOld);::DeleteObject(hBmp);::DeleteDC(hmemDC);return TRUE;}else{return FALSE;}
}
其中用到的GetEncoderClsid函数为
int CImageIO::GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{UINT num = 0; // number of image encodersUINT size = 0; // size of the image encoder array in bytesImageCodecInfo* pImageCodecInfo = NULL;Gdiplus::GetImageEncodersSize(&num, &size);if (size == 0){return -1;}pImageCodecInfo = (ImageCodecInfo*)(malloc(size));if (pImageCodecInfo == NULL){return -1;}Gdiplus::GetImageEncoders(num, size, pImageCodecInfo);for (UINT j = 0; j< num; ++j){//if (_tcscmp(pImageCodecInfo[j].MimeType, format1.str().c_str) == 0)//if (pImageCodecInfo[j].MimeType == format)if (wcscmp(pImageCodecInfo[j].MimeType, format)) // char*用strcmp作对比,而WCHAR*用wcscmp函数,这个是strcmp对应的UNICODE版本{*pClsid = pImageCodecInfo[j].Clsid;free(pImageCodecInfo);return j;}}free(pImageCodecInfo);return -1;
}
二、CDialogBar界面用同View的方法调用saveAsImage函数即可
三、OpenGL场景
若用上面的方法得到的是白板,这里要用glReadPixels函数来保存图片
#define BITMAP_ID 0x4D42
// 将opengl场景保存为图片
bool CImageIO::SnapScreen(int width, int height, const char *file)
{byte *image; //接受图像数据FILE *fp; //文件指针BITMAPFILEHEADER FileHeader; //接受位图文件头BITMAPINFOHEADER InfoHeader; //接受位图信息头FileHeader.bfType = BITMAP_ID; //ID设置为位图的id号FileHeader.bfOffBits = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER); //实际图像数据的位置在文件头和信息头之后FileHeader.bfReserved1 = 0; //必须设置为0FileHeader.bfReserved2 = 0; //必须设置为0FileHeader.bfSize = height*width * 24 + FileHeader.bfOffBits; //BMP图像文件大小InfoHeader.biXPelsPerMeter = 0; //水平分辨率,这里暂时设为0就是InfoHeader.biYPelsPerMeter = 0; //垂直分辨率,这里暂时设为0就是InfoHeader.biClrUsed = 0; //图像使用的颜色,这里暂时设为0就是InfoHeader.biClrImportant = 0; //重要的颜色数,这里暂时设为0就是 //垂直分辨率,这里暂时设为0就是InfoHeader.biPlanes = 1; //必须设置为1InfoHeader.biCompression = BI_RGB; //设置为BI_RGB时,表示图像并没有彩色表InfoHeader.biBitCount = 24; //图像的位数InfoHeader.biSize = sizeof(BITMAPINFOHEADER); //结构体的大小InfoHeader.biHeight = height;InfoHeader.biWidth = width;InfoHeader.biSizeImage = height*width * 4;image = (byte *)malloc(sizeof(byte)*InfoHeader.biSizeImage);if (image == NULL){free(image);printf("Exception: No enough space!\n");return false;}//像素格式设置4字节对齐glPixelStorei(GL_UNPACK_ALIGNMENT, 4);//接收出像素的数据glReadPixels(0, 0, width, height, GL_BGR_EXT, GL_UNSIGNED_BYTE, image);fp = fopen(file, "wb");if (fp == NULL){printf("Exception: Fail to open file!\n");return false;}fwrite(&FileHeader, sizeof(BITMAPFILEHEADER), 1, fp);fwrite(&InfoHeader, sizeof(BITMAPINFOHEADER), 1, fp);fwrite(image, InfoHeader.biSizeImage, 1, fp);free(image);fclose(fp);return true;
}
四、最终如何实现开始提到的问题呢?
1)利用SnapScreen保存opengl场景为panorama.bmp
2)利用BitBlt创建内存DC来获取View和CDialogbar的界面图片,然后加载panorama.bmp进行拼合。
// 将三张bmp图片拼接成一个
BOOL CImageIO::stitchBMP(CString imageFormat, CString savePath, int width, int height, HDC skylineHdc, HDC infoHdc, CRect skylineRect, CRect infoRect)
{HDC hmemDC = ::CreateCompatibleDC(skylineHdc);hBmp = ::CreateCompatibleBitmap(skylineHdc, skylineRect.Width() + infoRect.Width(), infoRect.Height());HANDLE hOld = ::SelectObject(hmemDC, hBmp);Graphics graphic(hmemDC);SelectObject(hmemDC, hBmp);//下面进行各种文字、图形、图片的绘制// CDC类的BitBlt就是MFC下专门用来操作位图的,将两张位图分别导入到CBitmap做成内存DC后,一次BitBlt到设备DC上,就完成了图片的叠加,叠加效果,由BitBlt函数的光栅代码参数决定,详细看这个函数的帮助(内容不少),可以熟悉不同的叠加方式BitBlt(hmemDC, 0, 0, skylineRect.right, skylineRect.bottom, skylineHdc, 0, 0, SRCCOPY); // 将hdc拷贝到内存DCBitBlt(hmemDC, skylineRect.Width(), 0, infoRect.right, infoRect.bottom, infoHdc, 0, 0, SRCCOPY); // 将hdc拷贝到内存DC//HDC hmemDC2 = ::CreateCompatibleDC(skylineHdc);//CBitmap m_bitmap; //对象//m_bitmap.LoadBitmap(IDB_BITMAP_TREESTATE);//加载//HBITMAP hbm = (HBITMAP)m_bitmap;//SelectObject(hmemDC2, hbm);//BitBlt(hmemDC, 0, skylineRect.Height(), 200, 200, hmemDC2, 0, 0, SRCCOPY); // 将hdc拷贝到内存DCHDC hmemDC2 = ::CreateCompatibleDC(skylineHdc);HBITMAP hPanoBmp = (HBITMAP)LoadImageA(NULL, "D:\\panorama.bmp", IMAGE_BITMAP, 0,0, LR_LOADFROMFILE);// 获取HBITMAP图片信息BITMAP bitbmpInfo;GetObject(hBmp, sizeof(BITMAP), (LPBYTE)&bitbmpInfo);SelectObject(hmemDC2, hPanoBmp);BitBlt(hmemDC, 0, skylineRect.Height(), bitbmpInfo.bmWidth, bitbmpInfo.bmHeight, hmemDC2, 0, 0, SRCCOPY); // 将hdc拷贝到内存DC//StretchBlt(hmemDC, 0, skylineRect.Height(), skylineRect.Width(), infoRect.Height() -skylineRect.Height(), hmemDC2, 0, 0, bitbmpInfo.bmWidth, bitbmpInfo.bmHeight, SRCCOPY); // 将hdc拷贝到内存DC//CMainFrame * mainframe = (CMainFrame *)AfxGetMainWnd();//HDC pHdc = mainframe->pParonamaView->GetDC()->GetSafeHdc();//CRect prc;//mainframe->pParonamaView->GetClientRect(&prc);//BitBlt(hmemDC, 0, skylineRect.Height(), prc.right, prc.bottom, pHdc, 0, 0, SRCCOPY); // 将hdc拷贝到内存DC//CBitmap m_bitmap; //对象//m_bitmap.LoadBitmap(IDB_BITMAP_TREESTATE);//加载//HBITMAP hbm = (HBITMAP)m_bitmap;//HDC memDC;////SelectObject(memDC, hbm);//BitBlt(hmemDC, 0, skylineRect.Height(), 200, 200, memDC, 0, 0, SRCCOPY); // 将hdc拷贝到内存DC//HANDLE hf = CreateFile(// "temp\panorama.bmp", GENERIC_WRITE, FILE_SHARE_READ, NULL,// CREATE_ALWAYS, NULL, NULL);Bitmap bitmap(hBmp, NULL);CLSID clsID;//保存不同格式的(.jpg,bmp,png)的图片需要不同的CLSID, imageFormat为用户期望保存的图片格式if (_T("jpg") == imageFormat.MakeLower()){GetEncoderClsid(L"image/jpeg", &clsID);}else if (_T("bmp") == imageFormat.MakeLower()){GetEncoderClsid(L"image/bmp", &clsID);}else if (_T("png") == imageFormat.MakeLower()){GetEncoderClsid(L"image/png", &clsID);}// char*转WCHAR*char *p = (LPSTR)(LPCSTR)savePath;wstringstream wss;wss << p;bitmap.Save(wss.str().c_str(), &clsID, NULL);//bitmap.Save(L"D:\\ggg.jpg", &clsID, NULL);::SelectObject(hmemDC, hOld);::DeleteObject(hBmp);::DeleteDC(hmemDC);return TRUE;
}
输出结果如下图:
MFC 视图-OpenGL场景-CDialogBar三个界面保存为图片相关推荐
- OpenGL入门学习[三]
OpenGL入门学习[三] http://xiaxveliang.blog.163.com/blog/static/2970803420126246501930/ OpenGL入门学习[十一] 我们在 ...
- MFC视图切换大全总结
单纯视图之间的切换 单文档多视图切换是我在学习MFC中遇到的一个老大难问题,在今天总算是一一破解了.我觉得视图切换分为三个等级,第一是在未切分窗格的情况下切换视图类:第二是在分割窗格的一个窗格内实行视 ...
- 《MFC游戏开发》笔记三 游戏贴图与透明特效的实现
本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/9313239 作者:七十一雾央 新浪微博:http:// ...
- OpenGL纹理本质(三)
几个月前调试3D纹理时发现一个有趣的问题:同样的3D HW lib库在android2.2系统上可以正常工作,但在2.3系统上却不能工作,显示的图像白屏,调试了几天才将问题定位并解决,解决方法很简单: ...
- Android 仿PhotoShop调色板应用(三) 主体界面绘制
版权声明:本文为博主原创文章,未经博主允许不得转载. Android 仿PhotoShop调色板应用(三) 主体界面绘制 关于PhotoShop调色板应用的实现我总结了两个最核心的部分: 1 ...
- OpenGL Cubic Bezier三次贝塞尔曲线修补实例
OpenGL Cubic Bezier三次贝塞尔曲线修补 先上图,再解答. 正常显示 按下C键 按下W键 按下X键 完整主要的源代码 源代码剖析 先上图,再解答. 正常显示 按下C键 按下W键
- 计算机图形学 opengl版本 第三版------胡事民 第四章 图形学中的向量工具
计算机图形学 opengl版本 第三版------胡事民 第四章 图形学中的向量工具 一 基础 1:向量分析和变换 两个工具 可以设计出各种几何对象 点和向量基于坐标系定义 拇指指向z轴正 ...
- Android4.2.2 Gallery2源码分析(9)——三个界面的跳转
Gallery浏览图片除开编辑界面,主要有三个界面:即起始页,相册簿集合页面(AlbumSetPage):点击某个相册进入该相册的所有图片页面(AlbumPage)和再点击某张具体图片之后的图片浏览页 ...
- MFC绘制二次、三次准均匀B样条曲线
MFC绘制二次.三次准均匀B样条曲线 二次准均匀B样条曲线 三次准均匀B样条曲线 节点矢量在两端K+1次重复,即可以使得B样条的端点具有Bezier曲线端点的性质.参考之前的文章,将控制点与节点分别修 ...
最新文章
- jQuery MD5加密
- 1.FPGA开发软件安装——Vivado
- 如何使用Proxy模式及Java内建的动态代理机制
- JSF JQUERY 使用datepicker
- Extract Subclass(提炼子类)
- 【OpenCV 例程200篇】61. 导向滤波(Guided filter)
- php中的CURL库
- 诺基亚手机新品发布定档 6 月 11 日!Nokia C20 Plus 即将到来
- Activity生命周期方法的调用顺序project与測试日志
- IntelliJ IDEA、Kotlin、PyCharm 背后公司 JetBrains 遭美国调查!
- php判断浏览器和语言
- 招聘网站数百万条敏感数据泄露,简历、×××扫描件统统曝光
- Hive编程指南(含目录,高清,免费)
- Zookeeper四字监控命令使用总结
- Linux下通用打印系统CUPS使用教程
- 6个usb口服务器无响应,USB接口不能用(没反应)修复方法
- python评价回归模型指标:决定系数R2,相关系数R,均方误差MSE,均方根误差RMSE
- 名帖07 赵宧光 篆书《篆书四箴册》
- iphone ios 视频特效,视频合成
- 教务(选课)管理系统
热门文章
- 爱可信携手Marvell展示爱可信Linux平台
- 关于excel导入带图片
- 简单js模仿浏览器crtl+f功能
- 达梦数据库-国产的荣光
- 手术麻醉信息管理系统源码,生成规范麻醉文书,自动信息采集
- string大小写转换
- iPhone7黔驴技穷,Moto Z另辟蹊径,谁才能引领行业创新?
- 塞班微信登录显示服务器繁忙,塞班系统彻底告别 已无法登陆QQ/微信
- 第五人格服务器维修中怎么进,第五人格怎么进不去_进不去游戏原因汇总及解决办法_软吧...
- 深度长文:Power Automation 帮助企业实现数字化转型