上机环境vs2015 win7 64位
先上图,是不是扑面就感受到一股浓浓的俄罗斯风情,hehehehe~
截图是基于MFC实现的带有插图的对话框窗口,就这么一个小破功能,折腾我一礼拜,问题集中在两方面:
1.如何加载jpeg图片?加载bmp的案例汗牛充栋,但加载jpeg的确实不多
2.在窗口的指定区域显示加载的jpeg图片,图中的控件布局力求表达这种意思,当然也会根据需要显示在窗口的右上角等各种场景
- 关于问题1:
其实,早在用vc++6.0的时代,就已经有了用IPicture接口从堆区接收图片流数据的方案,一些案例丰富的书 诸如《vc++ 开发实战》就提供了这样的案例,当然,在vs2008以后的IDE上运行,由于C++标准的演进,代码需要微调
所以市面上大多vc++书籍,仍显得鸡肋。大多数以vc++6.0为平台的书籍弃之可惜(案例丰富),用起来对于初学者而言又是一场噩梦(在新的vs IDE运行案例代码需要微调,这需要一定C++和至少vs2008以后版本的VC基础)
无论如何,这种加载jpeg图片的流程可以概括为:
- 声明CFile变量(文件描述符),打开一个硬盘上的图片
- 获取文件的大小(也不妨说是长度)
- 声明一个堆句柄(VC类型HGLOBAL)
- 根据文件大小(长度)为堆句柄分配空间(GlobalAlloc)
- 声明一个LPVOID类型指针,用指针锁定分配的堆空间----GlobalLock
- 用文件描述符通过LPVOID类型指针把图片信息写入堆空间(尽管调用的相关函数使用了Read这个词,但我理解是从文件xxxx读取然后写入堆空间),完成后关闭文件描述符。
- 释放LPVOID类型指针锁定的堆空间
- 调用CreateStreamOnHGlobal把堆空间内容整合成流式信息,给IStream类的变量接收
- 调用OleLoadPicture函数把图片流信息加载到IPicture接口
- 声明OLE_XSIZE_HIMETRIC 类型的变量用于接收图片文件的宽度像素信息
- 声明OLE_YSIZE_HIMETRIC类型变量用于接收图片文件高度的像素信息
CDC *pdc = NULL; pdc = GetDlgItem(IDC_STATIC)->GetDC(); this->file.Open(_T("E:\f575becf4c96.jpg"), CFile::modeReadWrite);//在vc6.0的实现中,没有用到可变宽度字符处理函数_T() this->len = this->file.GetLength(); this->pdata = NULL; this->hMem=GlobalAlloc(GMEM_MOVEABLE, this->len); this->pdata = GlobalLock(this->hMem); this->file.Read(this->pdata, this->len);//vc6.0的实现为ReadHuge this->file.Close(); GlobalUnlock(this->hMem); CreateStreamOnHGlobal(this->hMem, TRUE, &(this->picstream)); OleLoadPicture(this->picstream, this->len, TRUE, IID_IPicture, (LPVOID*)&(this->mypic)); this->mypic->get_Height(&this->picheight); this->mypic->get_Width(&this->picwidth); CRect zrect; pdc->GetWindow()->GetWindowRect(&zrect); int iWndWidth = zrect.right - zrect.left; int iWndHeight = zrect.bottom - zrect.top; this->mypic->Render(GetDlgItem(IDC_STATIC)->GetDC()->m_hDC,0,0, iWndWidth, iWndHeight,0, this->picheight, this->picwidth,-(this->picheight),NULL );
- 关于问题2
大多数资料介绍的CDC设备都用于画图,尽管jpeg图像也是画出来的,但我还是想做出区分,多数资料介绍的方法是,声明一个矩形的区域,声明一个有颜色的画刷,然后声明一个DC设备上下文,通过FillRect方法,用DC拿起画刷在矩形区域填充
而在这个问题的处理上其流程大致可以梳理为
1.声明设备类型指针
2.用设备类型指针获取窗口上的控件(picture control) ID,用来生成一个渲染图像的设备(画图的画布) 。
3.声明一个CRect类的变量,声明的设备指针变量,通过调用GetWindow(),GetWidowRect(&zrect)把picture Control控件的宽高信息传递给CRect类的实例zrect
4.通过rect计算控件的高和宽,因为rect可能相对于窗口位置发生偏移,所以可靠的算法是rect的右边坐标减去左边坐标,得出宽,底边坐标减去上边坐标得到高
5.渲染图片,Render()参数列表中的第4个,第5个参数就是算出的控件的宽和高。
//...... CDC *pdc = NULL; //........ CRect zrect; pdc->GetWindow()->GetWindowRect(&zrect); //........... int iWndWidth = zrect.right - zrect.left; int iWndHeight = zrect.bottom - zrect.top; this->mypic->Render(GetDlgItem(IDC_STATIC)->GetDC()->m_hDC,0,0, iWndWidth, iWndHeight,0, this->picheight, this->picwidth,-(this->picheight),NULL );
当然,上述代码还需要及时释放堆内存 GlobalFree(hMem),以及IPicture指针(通过mypic->Release())