您的位置:首页 > 数据库

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

2017-09-14 10:57 871 查看

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

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 ;

        

    }

    

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: