MFC/VC++中怎样将一个位图添加到数据库中并且将其读出来到指定的Picture控件上

MFC 专栏收录该内容
60 篇文章 0 订阅

看这篇文章之前建议先看一下下面这篇文章:

VC下显示位图的几种方法   http://blog.chinaunix.net/uid-607545-id-2088102.html或  http://blog.csdn.net/ply421600/article/details/6692967 和http://hi.baidu.com/vbcs003/item/efffa6e775cdf80d8d3ea89a或http://blog.csdn.net/eryadabendan/article/details/6749939

修改了一下-----VC下显示位图的几种方法 中 的/*******************通过读取位图文件来显示位图**********************/


既然是向数据库中添加位图信息,那么有必须明白我们的数据是以什么形式存放在数据库的,当然没有别的方法,只能是二进制了,所以在创建数据库的时候,一定要注意选择的字段的类型,不然是添加下进去的。(刚开始的时候,我就遇到了这个问题,费了好长时间才搞定的。Access中的字段定义为” OLE 对象”,sql2000中字义为image就行了。

void CTestDlg::OnButton2() //读取位图文件并显示在picture控件上
{
    // TODO: Add your control notification handler code here
//    CStatic *pStatic=(CStatic*)GetDlgItem(IDC_PHOTO);
    //CClientDC dc(this);
    CFileDialog fileDlg(TRUE,"bmp",NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,"(*.bmp)|*.bmp||");
        if (fileDlg.DoModal()!=IDOK)
        {
            return;
        }
        
    CString filePath=fileDlg.GetPathName();


    CString strFileName=filePath;
    
    //成位图信息BITMAPINFO
    BITMAPINFO *bitmapinfo=NULL;
    BYTE *BmpData=NULL;
    CFile file;//读取位图信息
    //设置文件的打开方式
    if(!file.Open(strFileName,CFile::modeRead|CFile::typeBinary))
    {
        return;
    }
    //BITMAP文件头结构体
    BITMAPFILEHEADER BitmapHead;
    //读取位图文件头
    if(file.Read(&BitmapHead,sizeof(BITMAPFILEHEADER))!=sizeof(BITMAPFILEHEADER))
    {
        MessageBox("读取文件头失败!");
        return;
    }
    if(BitmapHead.bfType!=0x4d42)
    {
        MessageBox("对不起,您读取的不是位图文件!");
        return;
    }
    //位图信息
    BITMAPINFOHEADER BitmapInfo;
    if(file.Read(&BitmapInfo,sizeof(BITMAPINFOHEADER))!=sizeof(BITMAPINFOHEADER))
    {
        MessageBox("读取位图信息失败!");
        return;
    }
    if(BitmapInfo.biBitCount!=24)
    {
        MessageBox("对不起,当前程序只支持24位位图信息!");
        return;
    }
    bitmapinfo=(BITMAPINFO*)new char[sizeof(BITMAPINFOHEADER)];
    if(!bitmapinfo)
    {
        MessageBox("内存分配失败!");
        return;
    }
    /*把BMP位图信息头中的数据读取到位图信息结构中去.*/
    memcpy(bitmapinfo,&BitmapInfo,sizeof(BITMAPINFOHEADER));
    /*用来得到位图文件的大小*/
    DWORD dataByte=BitmapHead.bfSize-BitmapHead.bfOffBits;
    BmpData=(BYTE*)new char[dataByte];
    if(!BmpData)
    {
        MessageBox("内存分配失败!");
        delete bitmapinfo;
        delete BmpData;
        return;
    }
    if(file.Read(BmpData,dataByte)!=dataByte)
    {
        MessageBox("读取位图数据失败!");
        return;
    }
    file.Close();
    CClientDC *pDC=new CClientDC(this);
    pDC->SetStretchBltMode(COLORONCOLOR);
StretchDIBits(pDC->GetSafeHdc(),200,0,BitmapInfo.biWidth,BitmapInfo.biHeight, 0,0,BitmapInfo.biWidth,BitmapInfo.biHeight,BmpData,bitmapinfo,DIB_RGB_COLORS,SRCCOPY);

}

///

void CTestDlg::OnButton1() //将通过文件读出来的位图信息存储到数据库中
{
    // TODO: Add your control notification handler code here
    char *pBuffer=m_pbufferBMP;
    VARIANT varPic;
    SAFEARRAY *pArray;
    SAFEARRAYBOUND rgsabound[1];
    if (pBuffer)
    {
        rgsabound[0].lLbound=0;
        rgsabound[0].cElements=size;
        pArray=SafeArrayCreate(VT_UI1,1,rgsabound);
        char *byte;

        SafeArrayAccessData(pArray,(void**)&byte);
        for (long index=0;index<=size;++index)
        {
            byte=m_pbufferBMP;
        }
        SafeArrayUnaccessData(pArray);
        varPic.vt=VT_ARRAY | VT_UI1;
        varPic.parray=pArray;

    }

    try
    {
     m_pRecordset->AddNew();
     m_pRecordset->PutCollect("id",_variant_t("1001"));
     m_pRecordset->GetFields()->GetItem("photo")->AppendChunk(varPic);
     MessageBox("add ok");
      
    }
    catch (_com_error e)
    {
        MessageBox("Add picture to database is failed!");
    }
    m_pRecordset->Update();
    MessageBox("save ok");
    
}


http://blog.csdn.net/ply421600/article/details/6725763




既然是向数据库中添加位图信息,那么有必须明白我们的数据是以什么形式存放在数据库的,当然没有别的方法,只能是二进制了,所以在创建数据库的时候,一定要注意选择的字段的类型,不然是添加下进去的。(刚开始的时候,我就遇到了这个问题,费了好长时间才搞定的。Access中的字段定义为” OLE 对象”,sql2000中字义为image就行了。)

1>     读取一个位图,

CFile FilePic;//用来读取位图文件

DWORD FileLen=0;//位图的长度

char* FileBuff;//用于存放位图信息

if(!FilePic.Open(FilePath,CFile::modeRead))//打开位图文件

{

        MessageBox("打开图片信息失败!");

        return false;

}

FileLen=FilePic.GetLength();//得到位图的长度

FileBuff=new char[FileLen+1];//给位图文件申请内在空间

memset(FileBuff,0,FileLen+1);//初始化位图文件的空间

if(!FileBuff)//判断位图空间是否申请成功

{

        MessageBox("给图片分配空间失败!");

        return false;

}

if(FilePic.Read(FileBuff,FileLen)!=FileLen)//读取位图信息,存入到FileBuff中去

{

        MessageBox("读取图片信息失败!");

        return false;

}


对此的改进:

CFile file;
    
    CFileDialog fileDlg(TRUE,"bmp",NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,"(*.bmp)|*.bmp||");
    if (fileDlg.DoModal()!=IDOK)
    {
        return;
    }

    CString filePath=fileDlg.GetPathName();
    if (!file.Open(filePath,CFile::modeRead))
    {return;
    }
    DWORD fileSize=file.GetLength();
    
    
    m_pbufferBMP=new char[fileSize+1];
    memset(m_pbufferBMP,'\0',fileSize+1);
   size=file.Read(m_pbufferBMP,fileSize);

2>     把位图信息存放到VARIANT对象中,存入数据库中

char* pBuff= FileBuff;

VARIANT varPic;//该对象用于存放位图信息

SAFEARRAY *safeArray;//定义一个SAFEARRAY结构对象(对于这个东西,会有专门的文档大家可以看一下,网上很多,不过都差不多,最好去MSDN上找一下)

SAFEARRAYBOUND rgsabound[1];//此结构体用来定义SAFEARRAY的边界,详情见MSDN

if(pBuff)//判断位图文件是否为空

{

        rgsabound[0].lLbound=0;//定义下界

        rgsabound[0].cElements=DwPic;//定义上限

              safeArray=SafeArrayCreate(VT_UI1,1,rgsabound);// 使用SafeArrayCreate在堆上创建一维数组

        for(long i=0;i<(long)DwPic;i++)

        {

               SafeArrayPutElement(safeArray,&i,pBuff++);//传值

        }

        varPic.vt=VT_ARRAY|VT_UI1;//把值给VARIANT对象

        varPic.parray=safeArray; //把值给VARIANT对象

}

3>     把数据写到数据库中

ACCESS2003:

::CoInitialize(NULL);

m_pConnection.CreateInstance("ADODB.Connection");
  _bstr_t strSQL="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=企业人事管理系统数据库\\test2.mdb";\\放在当前项目路径下企业人事管理系统数据库中
 HRESULT hrs=m_pConnection->Open(strSQL,"","",adModeUnknown);
    if (SUCCEEDED(hrs))
    {
        AfxMessageBox("link  database ok!");
    }else{
        AfxMessageBox("link failed!");
        
    }
    }catch(_com_error e){
        
        AfxMessageBox(    e.ErrorMessage());
    }

m_pRecordset.CreateInstance("ADODB.Recordset");
    HRESULT hr = m_pRecordset->Open("SELECT * FROM photo",
        _variant_t((IDispatch *)m_pConnection,true),
        adOpenDynamic,adLockPessimistic,adCmdText);

//m_pRecordset和m_pConnection都是类成员对象

pRecordset->AddNew();

try

{

pRecordset->PutCollect("Name",_variant_t("zhang1"));

pRecordset->GetFields()->GetItem("Picture")->AppendChunk(varPic);

}

catch(_com_error e)

{

        MessageBox("Add pic to access is falied!");

}

pRecordset->Update();

sql2000:



::CoInitialize(NULL);

m_pConnection.CreateInstance("ADODB.Connection");

  _bstr_t strSQL="Driver={SQL Server};Server=ZLQ-PC;DataBase=test2";
    HRESULT hrs=m_pConnection->Open(strSQL,"sa","123",adModeUnknown);

  if (SUCCEEDED(hrs))
    {
        AfxMessageBox("link  database ok!");
    }else{
        AfxMessageBox("link failed!");
        
    }
    }catch(_com_error e){
        
        AfxMessageBox(    e.ErrorMessage());
    }


m_pRecordset.CreateInstance("ADODB.Recordset");
    HRESULT hr = m_pRecordset->Open("SELECT * FROM photo",
        _variant_t((IDispatch *)m_pConnection,true),
        adOpenDynamic,adLockPessimistic,adCmdText);


pRecordsetSql->AddNew();

       

       try

       {

              pRecordsetSql->PutCollect("Name",_variant_t("zhang1"));

              pRecordsetSql->GetFields()->GetItem("Pic")->AppendChunk(SavePic(FileBuff,FileLen));

       }

       catch(_com_error e)

       {

              MessageBox("Add picture to sqlserver2000 is failed!");

       }

       pRecordsetSql->Update();

//写入数据库方式二

    char *pBuffer=m_pbufferBMP;
    VARIANT varPic;
    SAFEARRAY *pArray;
    SAFEARRAYBOUND rgsabound[1];
    if (pBuffer)
    {
        rgsabound[0].lLbound=0;
        rgsabound[0].cElements=size;
        pArray=SafeArrayCreate(VT_UI1,1,rgsabound);
        char *byte;

        SafeArrayAccessData(pArray,(void**)&byte);
        for (long index=0;index<=size;++index)
        {
            byte=m_pbufferBMP;//m_pbufferBMP就是通过CFile读出来的位图文件,保存在char *m_pbufferBMP类成员变量中
        }
        SafeArrayUnaccessData(pArray);

        varPic.vt=VT_ARRAY | VT_UI1;
        varPic.parray=pArray;
    }

    try
    {
     m_pRecordset->AddNew();
     m_pRecordset->PutCollect("id",_variant_t("1001"));
     m_pRecordset->GetFields()->GetItem("photo")->AppendChunk(varPic);
     MessageBox("add ok");
      
    }
    catch (_com_error e)
    {
        MessageBox("Add picture to database is failed!");
    }
    m_pRecordset->Update();


下面是测试通过的:

首先:在StdAfx.h:加入:#import "c:\program files\common files\system\ado\msado15.dll" no_namespace rename("EOF","adoEOF")                                            \

然后:在基于对话框上添加两个按钮和Picture控件ID:IDC_PHOTO

其次建表:Access中的字段定义为” OLE 对象”,sql2000中字义为image就行了。

表名:photo

access :id 数字 这里暂时不设主键

               photo  Ole 不为空

Access下的连接字符串:注意当前表放到当前项目:企业人事管理系统数据库文件夹下

    _bstr_t strSQL="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=企业人事管理系统数据库\\test2.mdb";
     HRESULT hrs=m_pConnection->Open(strSQL,"","",adModeUnknown);

Ms  sql:

              id int 不设主键

               photo  image 不为空

ms中的连接字符串:Server=服务器名字;DataBase=你的数据库名字

_bstr_t strSQL="Driver={SQL Server};Server=ZLQ-PC;DataBase=test2";
  HRESULT hrs=m_pConnection->Open(strSQL,"sa","123",adModeUnknown);

在CtestDlg类中添加下面的代码

class CTest1Dlg : public CDialog
{
// Construction
public:
    CTest1Dlg(CWnd* pParent = NULL);    // standard constructor
    
    HBITMAP m_hPhotoBitmap;
     _ConnectionPtr m_pConnection;
     _RecordsetPtr m_pRecordset;
     char * m_pBMPBuffer;
    
     DWORD m_nFileLen;

}


最后:在初始化对话框中,连接数据库

BOOL CTest1Dlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    // Add "About..." menu item to system menu.

    // IDM_ABOUTBOX must be in the system command range.
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    {
        CString strAboutMenu;
        strAboutMenu.LoadString(IDS_ABOUTBOX);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }

    // Set the icon for this dialog.  The framework does this automatically
    //  when the application's main window is not a dialog
    SetIcon(m_hIcon, TRUE);            // Set big icon
    SetIcon(m_hIcon, FALSE);        // Set small icon
    
    // TODO: Add extra initialization here
    ::CoInitialize(NULL);
    try{    m_pConnection.CreateInstance("ADODB.Connection");
    _bstr_t strSQL="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=企业人事管理系统数据库\\test2.mdb";
     HRESULT hrs=m_pConnection->Open(strSQL,"","",adModeUnknown);
    //_bstr_t strSQL="Driver={SQL Server};Server=ZLQ-PC;DataBase=test2";
    //HRESULT hrs=m_pConnection->Open(strSQL,"sa","123",adModeUnknown);
    if (SUCCEEDED(hrs))
    {
        AfxMessageBox("连接数据库成功!");
        m_pRecordset.CreateInstance("ADODB.Recordset");
        HRESULT hr = m_pRecordset->Open("SELECT * FROM photo",
            _variant_t((IDispatch *)m_pConnection,true),
            adOpenDynamic,adLockPessimistic,adCmdText);
    }else{
        AfxMessageBox("连接数据库失败!");
        
    }
    }catch(_com_error e){
        
        AfxMessageBox(    e.ErrorMessage());
    }

    return TRUE;  // return TRUE  unless you set the focus to a control
}

//把位图保存到数据库中

void CTest1Dlg::OnButton1()
{
    // TODO: Add your control notification handler code here


    CFileDialog FileDlg(TRUE, "BMP", NULL,        //定义文件对话框
        OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "位图文件(*.BMP)|*.BMP||");
    if(FileDlg.DoModal() != IDOK)            //打开文件对话框
        return ;
    CString pathname = FileDlg.GetPathName();//获取选中文件的路径
    CFile file;                        //定义一个文件变量
    if(!file.Open(pathname, CFile::modeRead) )//以制度的方式打开文件
        return ;
    m_nFileLen = file.GetLength();//获取文件的长度
    m_pBMPBuffer = new char[m_nFileLen + 1];//开辟符数组
    if(!m_pBMPBuffer)            //如果控件不够大
        return ;
    if(file.Read(m_pBMPBuffer,m_nFileLen) != m_nFileLen)//读取文件保存在字符数组中
            return ;
    char            *pBuf = m_pBMPBuffer;
    VARIANT            varBLOB;
    SAFEARRAY        *psa;
    SAFEARRAYBOUND    rgsabound[1];
    if(pBuf)
    {    
        rgsabound[0].lLbound = 0;
        rgsabound[0].cElements = m_nFileLen;
        psa = SafeArrayCreate(VT_UI1, 1, rgsabound);
        for (long i = 0; i < (long)m_nFileLen; i++)
            SafeArrayPutElement (psa, &i, pBuf++);
        varBLOB.vt = VT_ARRAY | VT_UI1;
        varBLOB.parray = psa;
        
    }
    try
    {   m_pRecordset->AddNew();
        m_pRecordset->PutCollect("id","1001");
        m_pRecordset->GetFields()->GetItem("photo")->AppendChunk(varBLOB);
        m_pRecordset->Update();
    }
    catch (_com_error e)
    {    CString str;
         str.Format("错误信息:%s",e.ErrorMessage());
        MessageBox("Add picture to database is failed!,reason:"+str);
        return;
    }

    
    MessageBox("保存成功!");
}



//把位图从数据库中读出来

void CTest1Dlg::OnButton2()
{
    // TODO: Add your control notification handler code here

    if(m_hPhotoBitmap)
    {
        DeleteObject(m_hPhotoBitmap);
        m_hPhotoBitmap = NULL;
    }
    if(m_pBMPBuffer)
    {
        delete m_pBMPBuffer;
        m_pBMPBuffer = NULL;
    }
    //上面代码是为了清除以前的图像

    char *pBuff=NULL;//用于存放位图的内存空间
    
    try
        
    {

        if (m_pRecordset!=NULL)
        {m_pRecordset->Close();
        }
        //m_pRecordset->Open(bstrRecordset,m_pConnection.GetInterfacePtr(),adOpenDynamic,adLockOptimistic,adCmdText);
        m_pRecordset.CreateInstance("ADODB.Recordset");
        m_pRecordset->Open("SELECT * FROM photo",
            _variant_t((IDispatch *)m_pConnection,true),
            adOpenDynamic,adLockPessimistic,adCmdText);
        long DataSize;//在数据库中读取出来的位图的大小
        m_pRecordset->MoveLast();//移动到记录最后,保证最新数据
        DataSize=m_pRecordset->Fields->GetItem("photo")->ActualSize;//得到位图字段的大小
        
        if(DataSize>0)//判断那个位图字段是否为空
            
        {   
           
            _variant_t TheValue;//存储读出来的数据
        
            TheValue=m_pRecordset->GetFields()->GetItem("photo")->GetChunk(DataSize);//读取字段一
            //TheValue=m_pRecordset->GetCollect("photo");
            if(TheValue.vt==(VT_ARRAY|VT_UI1))
            {  
                pBuff=new char[DataSize+1];
                if(pBuff)
                {   
                    
                
                    char *buff=NULL;
                    
                    
                    /***********************主要也就下面这几句画,其它的和显示位图相似**************************/
                    
                    SafeArrayAccessData(TheValue.parray,(void**)&buff);//把位图数据放到buff中去
                    memcpy(pBuff,buff,DataSize);//把位图数据放到pBuff中
                
                    SafeArrayUnaccessData(TheValue.parray);//释放
                    
                

                    m_pBMPBuffer = new char[DataSize + 1];//开辟符数组
                    memcpy(m_pBMPBuffer,pBuff,DataSize);
    
                    
                  
                    //AfxMessageBox(m_pBMPBuffer);
                
                    //将位图内存数据PBuff转为HBITMAP
                    
                    
                    HBITMAP hBitmap=NULL;//定义一个HBITMAP对象,用于显示位图用
                    LPSTR                hDIB,lpBuffer = m_pBMPBuffer;
                    LPVOID                lpDIBBits;
                    BITMAPFILEHEADER    bmfHeader;
                    DWORD                bmfHeaderLen;
                    
                    //获得位图的头信息
                    bmfHeaderLen = sizeof(bmfHeader);
                    //strncpy((LPSTR)&bmfHeader,(LPSTR)lpBuffer,bmfHeaderLen);
                    memcpy(&bmfHeader,lpBuffer,bmfHeaderLen);
                    //根据获得的信息头判断是否是位图
                    if (bmfHeader.bfType != (*(WORD*)"BM"))
                    {   AfxMessageBox("this is not bitmap!");
                        return ;
                    }
                    //获取位图数据
                    hDIB = lpBuffer + bmfHeaderLen;//将指针移动到文件头的后面
                    BITMAPINFOHEADER &bmiHeader = *(LPBITMAPINFOHEADER)hDIB ;
                    BITMAPINFO &bmInfo = *(LPBITMAPINFO)hDIB ;
                    lpDIBBits=(lpBuffer)+((BITMAPFILEHEADER *)lpBuffer)->bfOffBits;  //偏移字节数
                    
                    //创建位图
                    CClientDC dc(this);
                    hBitmap = CreateDIBitmap(dc.m_hDC,&bmiHeader,
                        CBM_INIT,lpDIBBits,&bmInfo,DIB_RGB_COLORS);

                    
                    //显示位图
                    CBitmap bmp;                            //定义位图变量
                    bmp.Attach(hBitmap);    
                    BITMAP bm;                                //定义一个位图结构
                    bmp.GetBitmap(&bm);        
                    CDC dcMem;
                    dcMem.CreateCompatibleDC(GetDC());        //创建一个兼容的DC
                    CBitmap *poldBitmap=(CBitmap*)dcMem.SelectObject(bmp); //将位图选入设备环境类
                    CRect lRect;                            //定义一个区域
                    CStatic *pstatic=(CStatic*)GetDlgItem(IDC_PHOTO);
                    pstatic->GetClientRect(&lRect);            //获取控件的客户区域
                    lRect.NormalizeRect();
                
                    pstatic->GetDC()->StretchBlt(lRect.left ,lRect.top ,lRect.Width(),lRect.Height(),
                        &dcMem,0 ,0,bm.bmWidth,bm.bmHeight,SRCCOPY); //显示位图
                    dcMem.SelectObject(&poldBitmap); //将原有的句柄选入设备环境
                    bmp.DeleteObject();
                    
            
                    
                }
                
            }
            
        }
    
    }
    
    catch(_com_error e)
        
    {
        
        MessageBox("打开数据表失败!");
        
        return ;
        
    }




    
}



  • 2
    点赞
  • 2
    评论
  • 5
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值