在处理网格应用传输图像时,接收方收到的将是数据流,如何能够将图像数据显示在窗口中呢?Windows系统提供了StretchDIBits函数,通过它能够根据位图的数据流将图像显示在窗口中。
函数原型:
int StretchDIBits(HDC hdc, int XDest , int YDest , int nDestWidth, int nDestHeight, int XSrc, int Ysrc, int nSrcWidth, int nSrcHeight, CONST VOID *lpBits, CONST BITMAPINFO * lpBitsInfo, UINT iUsage, DWORD dwRop);
参数含义:
hdc:指向目标设备环境的句柄。
XDest:指定目标矩形左上角位置的X轴坐标,按逻辑单位来表示坐标。
YDest:指定目标矩形左上角的Y轴坐标,按逻辑单位表示坐标。
nDestWidth:指定目标矩形的宽度。
nDestHeight:指定目标矩形的高度。
XSrc:指定DIB中源矩形(左上角)的X轴坐标,坐标以像素点表示。
YSrc:指定DIB中源矩形(左上角)的Y轴坐标,坐标以像素点表示。
nSrcWidth:按像素点指定DIB中源矩形的宽度。
nSrcHeight:按像素点指定DIB中源矩形的高度。
lpBits:指向DIB位的指针,这些位的值按字节类型数组存储。
lpBitsInfo:指向BITMAPINFO结构的指针,该结构包含有关DIB方面的信息。
iUsage:表示是否提供了BITMAPINFO结构中的成员bmiColors,如果提供了,那么该bmiColors是否包含了明确的RGB值或索引。参数iUsage必须取下列值,这些值的含义如下:
DIB_PAL_COLORS:表示该数组包含对源设备环境的逻辑调色板进行索引的16位索引值。
DIB_RGB_COLORS:表示该颜色表包含原义的RGB值。
dwRop:指定源像素点、目标设备环境的当前刷子和目标像素点是如何组合形成新的图像。
返回值:
如果函数执行成功,那么返回值是拷贝的扫描线数目,如果函数执行失败,那么返回值是GDI_ERROR。
(一)示例:使用StretchDIBits根据数据流绘制图像——BMP
步骤如下:
(1)创建一个SDI APP,工程名为 OutPutStream
(2)在View类中定义一个Buffer,用于存储数据流
char* m_pBmpData; //定义一个缓冲区
(3)在View类的构造函数中读取位图文件到数据流中,代码如下:
COutPutStreamView::COutPutStreamView() { // TODO: 在此处添加构造代码 TCHAR szPath[MAX_PATH]; GetModuleFileName(NULL, szPath, MAX_PATH); CString PathName(szPath); CString PROGRAM_PATH2= PathName.Left(PathName.ReverseFind(_T('Debug')) ); PROGRAM_PATH2+=_T("OutPutStream\\Res\\QQ截图20140403232339.bmp"); CFile file;//定义一个文件对象 file.Open(PROGRAM_PATH2,CFile::modeReadWrite);//打开文件 int len=file.GetLength();//获取文件长度 file.Seek(14,CFile::begin);//略过文件头 m_pBmpData = new char[len-14];//为缓冲区分配空间 file.Read(m_pBmpData,len-14);//读取文件数据到缓冲区 file.Close();//关闭文件 }
(4)在视图类的析构函数中释放缓冲区,代码如下:
delete [] m_pBmpData;//释放缓冲区
(5)向View类中添加一个成员函数,根据数据流输出图像。代码如下:
void COutputStreamView::OutputStream(char *pStream) { char* pHeader = pStream;//定义一个临时缓冲区 BITMAPINFO BitInfo;//定义位图信息对象 memset(&BitInfo,0,sizeof(BITMAPINFO));//初始化位图信息对象 memcpy(&BitInfo,pHeader,sizeof(BITMAPINFO));//为位图信息对象赋值 int x= BitInfo.bmiHeader.biWidth;//指向位图宽度 int y= BitInfo.bmiHeader.biHeight;//指向位图高度 pHeader+=40;//指向位图数据 //输出位图信息 StretchDIBits(GetDC()->m_hDC,0,0,x,y,0,0,x,y,pHeader,&BitInfo,DIB_RGB_COLORS,SRCCOPY); }
(6)在View类的OnDraw方法中调用OutputStream方法绘制图像,代码如下:
OutputStream(m_pBmpData);//调用OutputStream 方法输出位图
(7)运行程序,结果如图7-1所示
instruction:由于BMP文件中数据的存储就是以位图文件格式存储的,所以通过BMP文件中的数据可以直接绘制图形。
(二)示例:使用StretchDIBits根据数据流绘制图像——JPEG
位图文件最大缺点就是压缩比较小,占用空间大,因此网页均不采用位图的格式显示,而是以JPEG或GIF格式显示。
在Visual C++中,显示JPEG图像并不像显示BMP图像那么简单,它需要通过流操作来实现。
具体思路是将JPEG文件加载到堆中然后在堆中创建一个数据流,接着调用OleLoadPicture 函数加载流中的数据到IPictrue接口中,最后调用IPicture接口的Reader方法输出图像信息。
下面介绍在窗口中显示JPEG图像的具体实现方法。
在窗口中显示JPEG图像
步骤如下
(1)创建一个SDI APP ,工程名为 ShowJPEG
(2)向视图类中添加成员变量,代码如下:
IStream *m_pStream;//定义流对象
IPicture *m_pPucture;//定义接口对象
OLE_XSIZE_HIMETRIC m_JPGWidth;//图像宽度
OLE_XSIZE_HIMETRIC m_JPGHeight;//图像高度
HGLOBAL hMem;//堆句柄
(3)在View类的构造函数中从磁盘中加载JPEG图像到流中,代码如下:
CFile file;//定义一个文件对象
file.Open(_T("angle.jpg"),CFile::modeReadWrite);//打开文件
DWORD len=file.GetLength();//获取文件长度
hMem = GlobalAlloc(GMEM_MOVEABLE,len);//在堆中分配内存
LPVOID pData = NULL;//定义一个指针对象
pData = GloballLock(hMem);//锁定内存区域
file.ReadHuge(pData,len);//读取图像数据到堆中
file.Close();
GlobalUnlock(hMem);
CreateStreamOnHGlobal(hMem,TRUE,&m_pStream);
OleLoadPicture(m_pStream,len,TRUE,IID_IPicture,(LPVOID*)&m_pPicture);//
(4)在View类的OnDraw方法中绘制JPEG图像,代码如下:
//绘制JPEG图像
m_pPicture->Render(pDC->MDM_HDLCPPP_AUTH_CHAP,0,0,(int)(m_JPGWidth/26.45),(int)(m_JPGHeight/26.45),0,m_JPGHeight,m_JPGWidth,-m_JPGHeight,NULL);
(5)运行程序
Instruction:本实例是通过IPcture接口来绘制IPEG图像的,同样只要修改一下文件扩展名就可以直接绘制GIF的图像。