zoukankan      html  css  js  c++  java
  • 【VS开发】IPicture在指定窗口绘制图

    1、利用IPicture接口加载、显示图片

    IPicture接口管理一个图片对象和它的属性。图片对象提供对Bitmap Icon Metafile的语言不相关的抽象支持。图像对象的主要接口是IPicture和IPictureDisp。IPictureDisp从IDispatch继承,提供了通过自动化访问图片属性的能力。图片对象可通过OleCreatePictureIndirect创建。关于IPicture支持的其他接口和方法可以看MSDN,一般创建图片对象可以用OleLoadPicture函数,它简化了基于流内容创建图片对象。

    IPicture接口管理一个图片对象和它的属性。图片对象提供对Bitmap Icon Metafile的语言不相关的抽象支持。图像对象的主要接口是IPicture和IPictureDisp。IPictureDisp从IDispatch继承,提供了通过自动化访问图片属性的能力。图片对象可通过OleCreatePictureIndirect创建。关于IPicture支持的其他接口和方法可以看MSDN,一般创建图片对象可以用OleLoadPicture函数,它简化了基于流内容创建图片对象。下面的代码中有两个未定义的变量是FilePath和hDC。
    //FilePath是从外部传入的图片路径
    //打开文件
    HANDLE hFile = CreateFile(FilePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
    _ASSERTE(INVALID_HANDLE_VALUE != hFile);
    //取文件大小
    DWORD dwFileSize = GetFileSize(hFile, NULL);
    _ASSERTE(-1 != dwFileSize);
    LPVOID pvData = NULL;
    //分配内存,准备读入图片文件的数据
    //GlobalAlloc从堆分配指定字节的内存区域
    HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, dwFileSize);
    _ASSERTE(NULL != hGlobal);
    //GlobalLock函数锁住一个全局的内存对象同时返回一个指向对象首字节的指针
    pvData = GlobalLock(hGlobal);
    _ASSERTE(NULL != pvData);
    DWORD dwBytesRead = 0;
    //读取文件的数据到分配的全局内存
    BOOL bRead = ReadFile(hFile, pvData, dwFileSize, &dwBytesRead, NULL);
    _ASSERTE(FALSE != bRead);
    GlobalUnlock(hGlobal);
    CloseHandle(hFile);

    //到此,我们已经把文件的数据读到了内存当中

    LPSTREAM pstm = NULL;
    //从全局内存创建IStream接口指针
    HRESULT hr = CreateStreamOnHGlobal(hGlobal, TRUE, &pstm);
    _ASSERTE(SUCCEEDED(hr) && pstm);
    //根据图片文件创建IPicture接口指针
    hr = ::OleLoadPicture(pstm, dwFileSize, FALSE, IID_IPicture, (LPVOID *)&gpPicture);
    _ASSERTE(SUCCEEDED(hr) && gpPicture); 
    pstm->Release();

    //至此,IPicture接口建立好,下面开始画图片
    //hDC是外部传入的画图设备
    long hmWidth;
    long hmHeight;
    gpPicture->get_Width(&hmWidth);
    gpPicture->get_Height(&hmHeight);
    //转换himetric距离为pixels距离,1英寸=25.4毫米
    int nWidth = MulDiv(hmWidth, GetDeviceCaps(hDC, LOGPIXELSX), 2540);
    int nHeight = MulDiv(hmHeight, GetDeviceCaps(hDC, LOGPIXELSY), 2540);
    RECT rc;
    GetClientRect(hWnd, &rc);
    //IPicture::Render显示图片
    gpPicture->Render(hDC, 0, 0, nWidth, nHeight, 0, hmHeight, hmWidth, -hmHeight, &rc);

    2、C++如何调用图片
    有很多办法 ,比如用IPicture,用CBitmap //MFC,更直接的是,用File进行文件操作,用BitBlt显示,具体代码你用以上关键字Google下 
    这里给你推荐几个,末尾给你附一个网上可以找到的CPicture类(需MFC支持): 
    -------IPicture 
    // pDoc为文档对象指针 
    // pDC为设备描述表指针 

    ::CoInitialize(NULL); // COM 初始化 
    HRESULT hr; 
    CFile file; 

    file.Open(pDoc->GetPathName(), CFile::modeRead | CFile::shareDenyNone ); // 读入文件内容 
    DWORD dwSize = file.GetLength(); 
    HGLOBAL hMem = ::GlobalAlloc( GMEM_MOVEABLE, dwSize ); 
    LPVOID lpBuf = ::GlobalLock( hMem ); 
    file.ReadHuge( lpBuf, dwSize ); 
    file.Close(); 
    ::GlobalUnlock( hMem ); 

    IStream * pStream = NULL; 
    IPicture * pPicture = NULL; 

    // 由 HGLOBAL 得到 IStream,参数 TRUE 表示释放 IStream 的同时,释放内存 
    hr = ::CreateStreamOnHGlobal( hMem, TRUE, &pStream ); 
    ASSERT ( SUCCEEDED(hr) ); 

    hr = ::OleLoadPicture( pStream, dwSize, TRUE, IID_IPicture, ( LPVOID * )&pPicture ); 
    ASSERT(hr==S_OK); 

    long nWidth,nHeight; // 宽高,MM_HIMETRIC 模式,单位是0.01毫米 
    pPicture->get_Width( &nWidth ); // 宽 
    pPicture->get_Height( &nHeight ); // 高 

    CRect rect; 
    GetClientRect(&rect); 

    CSize sz( nWidth, nHeight ); 
    pDC->HIMETRICtoDP( &sz ); // 转换 MM_HIMETRIC 模式单位为 MM_TEXT 像素单位 
    long x, y, cx, cy; 

    // 原始大小 
    /* 
    cx = sz.cx; 
    cy = sz.cy; 
    x = rect.Width() / 2 - cx / 2; 
    y = rect.Height() / 2 - cy / 2; 
    */ 

    // 自动适应窗口 
    double fRatePic, fRateWnd; 
    fRatePic = (double)sz.cx / (double)sz.cy; 
    fRateWnd = (double)rect.Width() / (double)rect.Height(); 
    if (fRatePic > fRateWnd) 

    cx = rect.Width(); 
    cy = (long)(rect.Width() / fRatePic); 

    else 

    cx = (long)(rect.Height() * fRatePic); 
    cy = rect.Height(); 

    if (cx == rect.Width()) 

    x = 0; 
    y = rect.Height() / 2 - cy / 2; 

    if (cy == rect.Height()) 

    x = rect.Width() / 2 - cx / 2; 
    y = 0; 


    pPicture->Render(pDC->m_hDC, x, y, cx, cy, 
    0, nHeight, nWidth, -nHeight, NULL); 

    if ( pPicture ) pPicture->Release();// 释放 IPicture 指针 
    if ( pStream ) pStream->Release(); // 释放 IStream 指针,同时释放了 hMem 

    ::CoUninitialize(); 

    --------------------------------CBitmap: 
    HBITMAP bitmap; 
    bitmap=(HBITMAP)LoadImage(AfxGetInstanceHandle(),strFileName,IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
    m_backBitmap.DeleteObject(); 
    if(!m_backBitmap.Attach(bitmap)) 

    MessageBox("导入背景图失败!","提示",MB_OK); 
    return; 


    ----------------------File:略 
    前提是你要知道图片的编码格式 
    一般比较简单的是BMP,包括 
    BITMAPFILEHEADER,BITMAPINFO,BITMAPINFOHEADER 
    如果图片采用了压缩算法可能会麻烦一点, 
    关于详细情况你也以Google一下 

    附CPicture(引用自网上) 

    // Picture.h: interface for the CPicture 
    #ifndef PICTURE_H 
    #ifndef picture_h 

    #define PICTURE_H 
    #define picture_h 


    #if _MSC_VER > 1000 
    #pragma once 
    #endif // _MSC_VER > 1000 


    class CPicture 

    public: 
    CPicture(); 
    virtual ~CPicture(); 

    public: 
    BOOL LoadPicture(UINT nResource, LPCTSTR lpszResType) 
    {return LoadPicture(MAKEINTRESOURCE(nResource), lpszResType);} 
    BOOL LoadPictureFromFile(LPCTSTR lpszFileName); 
    BOOL LoadPicture(LPCTSTR lpszResource,LPCTSTR lpszResType); 
    BOOL IsValid(){ return m_pPic!=NULL;} 
    CSize GetSize(){return m_size;} 
    void Draw(CDC* pDC, LPCRECT lprcDest, LPCRECT lprcSrc); 
    void Draw(CDC* pDC, int xDest,int yDest, int cxDest, int cyDest , 
    int xSrc ,int ySrc ,int cxSrc ,int cySrc); 

    void Release(); 

    protected: 
    IPicture* m_pPic; 

    OLE_XSIZE_HIMETRIC _w_him; 
    OLE_YSIZE_HIMETRIC _h_him; 

    CSize m_size; 

    protected: 
    void CalcSize(); 
    }; 


    #endif // define picture_h 
    #endif // define PICTURE_H 



    ////////////////////////////////////////////////////////////////////// 
    // Picture.cpp: implementation of the CPicture class. 
    // Lounge Stdio 2003 
    // 作者:边城浪子(QQ:16168666) 
    // E-mail: krh2001.lpfdiyvbb@163.com 
    ////////////////////////////////////////////////////////////////////// 

    #include "stdafx.h" 
    #include "Picture.h" 


    #ifdef _DEBUG 
    #undef THIS_FILE 
    static char THIS_FILE[]=__FILE__; 
    #define new DEBUG_NEW 
    #endif 


    ////////////////////////////////////////////////////////////////////// 
    // Construction/Destruction 
    ////////////////////////////////////////////////////////////////////// 

    CPicture::CPicture() 
    :m_pPic(NULL), _h_him(0), _w_him(0), m_size(0,0) 



    CPicture::~CPicture() 

    Release(); 


    void CPicture::Release() 

    if(m_pPic != NULL) 

    m_pPic->Release(); 
    m_pPic = NULL; 
    _h_him = _w_him = 0; 
    m_size.cx = m_size.cy = 0; 



    BOOL CPicture::LoadPicture(LPCTSTR lpszResource, LPCTSTR lpszResType) 

    Release(); 

    HINSTANCE hInst = AfxFindResourceHandle(lpszResource, lpszResType); 
    HRSRC hRsrc = ::FindResource(hInst, lpszResource, lpszResType); 
    if(hRsrc == NULL) return FALSE; 
    HGLOBAL hGlobal = LoadResource(hInst, hRsrc); 

    if(hGlobal == NULL) return FALSE; 


    DWORD dwSize = SizeofResource(hInst, hRsrc); 

    HGLOBAL hMem = ::GlobalAlloc(GMEM_MOVEABLE, dwSize); 
    if(hMem == NULL) return FALSE; 

    LPVOID pSrc = ::LockResource(hGlobal); 
    if(pSrc == NULL) { 
    ::GlobalFree(hMem); 
    return FALSE; 


    LPVOID pDes = ::GlobalLock(hMem); 
    if(pDes == NULL){ 
    //::GlobalUnlock(hGlobal); 
    ::GlobalFree(hMem); 
    return FALSE; 


    memcpy(pDes, pSrc, dwSize); 

    //GlobalUnlock(hGlobal); 
    GlobalUnlock(hMem); 

    ::FreeResource(hGlobal); 

    IStream* pStm = NULL; 
    CreateStreamOnHGlobal(hMem, TRUE, &pStm); 

    if(!SUCCEEDED(OleLoadPicture(pStm,dwSize,TRUE,IID_IPicture,(LPVOID*)&m_pPic))) 

    pStm -> Release(); 
    ::GlobalFree(hMem); 
    pStm = NULL; 
    return FALSE; 


    pStm->Release(); 
    ::GlobalFree(hMem); 

    CalcSize(); 
    return TRUE; 



    BOOL CPicture::LoadPictureFromFile(LPCTSTR lpszFileName) 

    Release(); 

    CFile file; 
    if(!file.Open(lpszFileName, CFile::modeRead)) 
    return FALSE; 

    DWORD dwSize = file.GetLength(); 

    HGLOBAL hMem = ::GlobalAlloc(GMEM_MOVEABLE, dwSize); 
    if(hMem == NULL) return FALSE; 

    LPVOID pDes = ::GlobalLock(hMem); 
    if(pDes == NULL){ 
    ::GlobalFree(hMem); 
    return FALSE; 


    file.ReadHuge(pDes, dwSize); 

    file.Close(); 

    GlobalUnlock(hMem); 

    IStream* pStm = NULL; 
    CreateStreamOnHGlobal(hMem, TRUE, &pStm); 

    if(!SUCCEEDED(OleLoadPicture(pStm,dwSize,TRUE,IID_IPicture,(LPVOID*)&m_pPic))) 

    pStm -> Release(); 
    ::GlobalFree(hMem); 
    pStm = NULL; 
    return FALSE; 


    pStm->Release(); 
    ::GlobalFree(hMem); 

    CalcSize(); 
    return TRUE; 




    void CPicture::CalcSize() 

    if(m_pPic == NULL) return; 

    m_pPic->get_Width(&_w_him); 
    m_pPic->get_Height(&_h_him); 

    CDC* pDC = CWnd::GetDesktopWindow()->GetDC(); 
    m_size.cx = _w_him; 
    m_size.cy = _h_him; 

    pDC->HIMETRICtoDP(&m_size); 

    CWnd::GetDesktopWindow()->ReleaseDC(pDC); 



    void CPicture::Draw(CDC* pDC, LPCRECT lprcDest, LPCRECT lprcSrc) 

    if(m_pPic) 

    CSize szOrig(lprcSrc->left, lprcSrc->top); 
    CSize szSrc(lprcSrc->right - lprcSrc->left, lprcSrc->bottom - lprcSrc->top); 
    pDC->DPtoHIMETRIC(&szOrig); 
    pDC->DPtoHIMETRIC(&szSrc); 

    m_pPic->Render(*pDC, lprcDest->left,lprcDest->top,lprcDest->right-lprcDest->left, 
    lprcDest->bottom-lprcDest->top, szOrig.cx, _h_him-szOrig.cy, szSrc.cx, 
    -szSrc.cy, NULL); 



    void CPicture::Draw(CDC* pDC, int xDest,int yDest, int cxDest, int cyDest , 
    int xSrc ,int ySrc ,int cxSrc ,int cySrc) 

    Draw(pDC, CRect(xDest, yDest, xDest+cxDest, yDest+cyDest), CRect(xSrc, ySrc, xSrc+cxSrc, ySrc+cySrc)); 

    }


    --------------------------------------------------------------------------------------------------------------

    实际上就是下面几句话就可以在指定的窗口中绘制gif,jpg和bmp图

    // CImageNetView 绘制


    void CImageNetView::OnDraw(CDC* /*pDC*/)
    {
    CImageNetDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    if (!pDoc)
    return;

    m_pDC = GetDC();
    DisplayImage(m_pDC->m_hDC,"E:\Images\rain.jpg");
    }


    void CImageNetView::DisplayImage(HDC hDC, LPCTSTR szImagePath)
    {     
    HANDLE hFile=CreateFile(szImagePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); //从指定的路径szImagePath中读取文件句柄
    DWORD dwFileSize=GetFileSize(hFile, NULL); //获得图片文件的大小,用来分配全局内存
    HGLOBAL hImageMemory=GlobalAlloc(GMEM_MOVEABLE, dwFileSize); //给图片分配全局内存
    void *pImageMemory=GlobalLock(hImageMemory); //锁定内存
    DWORD dwReadedSize; //保存实际读取的文件大小
    ReadFile(hFile, pImageMemory, dwFileSize, &dwReadedSize, NULL); //读取图片到全局内存当中
    GlobalUnlock(hImageMemory); //解锁内存
    CloseHandle(hFile); //关闭文件句柄
    IStream *pIStream;//创建一个IStream接口指针,用来保存图片流
    IPicture *pIPicture;//创建一个IPicture接口指针,表示图片对象
    CreateStreamOnHGlobal(hImageMemory, false, &pIStream); //用全局内存初使化IStream接口指针
    OleLoadPicture(pIStream, 0, false, IID_IPicture, (LPVOID*)&(pIPicture));//用OleLoadPicture获得IPicture接口指针
    //得到IPicture COM接口对象后,你就可以进行获得图片信息、显示图片等操作
    OLE_XSIZE_HIMETRIC hmWidth;
    OLE_YSIZE_HIMETRIC hmHeight;
    pIPicture->get_Width(&hmWidth); //用接口方法获得图片的宽和高
    pIPicture->get_Height(&hmHeight);
    pIPicture->Render(hDC,0,0,320,240,0,hmHeight,hmWidth,-hmHeight,NULL); //在指定的DC上绘出图片





    GlobalFree(hImageMemory); //释放全局内存
    pIStream->Release(); //释放pIStream
    pIPicture->Release(); //释放pIPicture


    }

    注:似乎好像大概不能获得图像的rgb像素吧,这一点还有待确认


    用API OleLoadPicture来加载JPG、GIF格式的图片(注:不支持PNG格式,另外GIF只能加载第一帧,且不支持透明) OleLoadPicture 函数实际上创建了一个IPicture类型的COM接口对象,然后我们可以通过这个COM接口来操作图片(实际上你也可以用API OleCreatePictureIndirect来加载图片,不过相比而言OleLoadPicture函数简化了基于流的IPicture对象的创 建)

    第一个参数pStream指向包含有图像数据的流的指针,第二个参数lSize为从流中读取的字节数,第三个参数fRunmode为图像属性对应的初值,第四个参数riid为涉及到的接口标识描述要返回的接口指针的类型,第五个参数ppvObj为在rrid中用到的接口指针变量的地址。






  • 相关阅读:
    教你一个vue小技巧,一般人我不说的
    分享一个好用的函数吧,将js中的对象转成url参数
    Vue源码探究-源码文件组织
    后端分布式系列:分布式存储-HDFS DataNode 设计实现解析
    Android Animation动画详解(二): 组合动画特效
    后端分布式系列:分布式存储-HDFS NameNode 设计实现解析
    Android开源框架ViewPageIndicator和ViewPager实现Tab导航
    解决某些手机RadioGroup中的RadioButton不居中(右移)问题
    Android Animation动画详解(一): 补间动画
    后端分布式系列:分布式存储-HDFS 架构解析
  • 原文地址:https://www.cnblogs.com/huty/p/8518886.html
Copyright © 2011-2022 走看看