一种在MFC程序上显示jpeg图片的方法(二)曙光乍现

上机环境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图片的流程可以概括为:

  1. 声明CFile变量(文件描述符),打开一个硬盘上的图片
  2. 获取文件的大小(也不妨说是长度)
  3. 声明一个堆句柄(VC类型HGLOBAL)
  4. 根据文件大小(长度)为堆句柄分配空间(GlobalAlloc)
  5. 声明一个LPVOID类型指针,用指针锁定分配的堆空间----GlobalLock
  6. 用文件描述符通过LPVOID类型指针把图片信息写入堆空间(尽管调用的相关函数使用了Read这个词,但我理解是从文件xxxx读取然后写入堆空间),完成后关闭文件描述符。
  7. 释放LPVOID类型指针锁定的堆空间
  8. 调用CreateStreamOnHGlobal把堆空间内容整合成流式信息,给IStream类的变量接收
  9. 调用OleLoadPicture函数把图片流信息加载到IPicture接口
  10. 声明OLE_XSIZE_HIMETRIC 类型的变量用于接收图片文件的宽度像素信息
  11. 声明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())

原文地址:https://www.cnblogs.com/saintdingspage/p/12425813.html