1. 程式人生 > >VC用ADO存取顯示jpg/bmp點陣圖檔案

VC用ADO存取顯示jpg/bmp點陣圖檔案

 週六和今天兩天的時間,把資料庫關於圖片的儲存和顯示 實現了,雖然時間有點長,但是還是實現了。以下是網上找到的資料,很有用。

第一步:首先是要開啟一個位圖檔案,這裡使用的控制元件用Picture控制元件,就是控制元件圖示右邊最上面那個,改ID號為IDC_PICTURE,然後定義兩個成員變數
char *m_char;//圖片檔案指標
DWORD m_nFileLen;//圖片長度
然後在函式中寫入:
CFileDialog dlg(TRUE,NULL,NULL,0,"photo Files (*.jpg;*.bmp)|*.jpg;*.bmp|",this);
   if(IDOK==dlg.DoModal())
{
   m_path=dlg.GetPathName();
   m_bool=true;
}
   CWnd *pWnd = GetDlgItem(IDC_PICTURE);
   CRect rect;
   pWnd->GetClientRect(&rect);
   CDC *pDC = pWnd->GetDC();
   CFileStatus fstatus;
   CFile file;
   LONG cb;
   BOOL m_tm=false;
   IPicture *pPic;
   CString m_sPath;
   if (file.Open(m_path,CFile::modeRead)&& file.GetStatus(m_path,fstatus)&&((cb = fstatus.m_size) != -1))  
   {
  
   if(cb>1048576)   //可在此設定圖片大小
   {
     m_tm=false;
     MessageBox("圖片不能大於1M","提示!");
   }
   else
   {
    
     m_nFileLen=(UINT)cb;        
     HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, cb);
     LPVOID pvData = NULL;
     if (hGlobal != NULL)
     {
     if ((pvData = GlobalLock(hGlobal)) != NULL)
     {
       file.ReadHuge(pvData, cb);
       m_char=(char*)pvData;
       GlobalUnlock(hGlobal);
       CreateStreamOnHGlobal(hGlobal, TRUE, &pStm);
       m_tm=true;
       // m_bool=true;
     }
     else
       AfxMessageBox("不是圖片檔案!");
     }
     else
     AfxMessageBox("申請記憶體失敗!");
    
   }
   }  
   else
   AfxMessageBox("不是圖片檔案!");
   if(m_tm)
   {
   SUCCEEDED(OleLoadPicture(pStm,fstatus.m_size,TRUE,IID_IPicture,(LPVOID*)&pPic));
   OLE_XSIZE_HIMETRIC hmWidth;
   OLE_YSIZE_HIMETRIC hmHeight;
   pPic->get_Width(&hmWidth);
   pPic->get_Height(&hmHeight);  
   if(FAILED(pPic->Render(*pDC,0,0,rect.Width(),rect.Height(),0,hmHeight,hmWidth,-hmHeight,NULL)))
     AfxMessageBox("渲染影象失敗!");
   pPic->Release();
   }
這裡還有個小小的問題,就是當窗口出現重畫的時候圖片就會消失,可以把上面的程式碼加入到OnPaint函式中去;
接來就是儲存檔案(怎麼訪問資料庫的可以去看下我空間裡的"用ADO訪問資料庫"):
在Access資料庫中把要放相片欄位的型別改為OLE 型別(在SQL資料庫改成相片型別).
m_RecordSet->AddNew();
char   *pBuf = m_char;//把圖片的指標傳給pBuf
   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;
   m_pRecordset->GetFields()->GetItem("讀者相片")->AppendChunk(varBLOB);      
   }
   m_pRecordset->Update();

接下來就是把圖片從資料庫中取出來,在放圖相的對話方塊中加入Picture控制元件,改ID為IDC_PICTURE,然後 在函式中寫入:
IStream *pStm;
   long lDataSize = m_pRecordset->GetFields()->GetItem("讀者相片")->ActualSize;
   if(lDataSize > 0)
   {
   _variant_t varBLOB;  
   varBLOB = theApp.m_data.m_pRecordset->GetFields()->GetItem("讀者相片")->GetChunk(lDataSize);  
   if(varBLOB.vt == (VT_ARRAY | VT_UI1))
   {
     char *pBuf = NULL;
     SafeArrayAccessData(varBLOB.parray,(void **)&pBuf);
     HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, lDataSize);
     LPVOID pvData = NULL;
     if (hGlobal != NULL)
     {
     if ((pvData = GlobalLock(hGlobal)) != NULL)
     {
       memcpy(pvData,pBuf,lDataSize);
       SafeArrayUnaccessData (varBLOB.parray);
       GlobalUnlock(hGlobal);
       CreateStreamOnHGlobal(hGlobal, TRUE, &pStm);
     }
     else
       AfxMessageBox("載入圖片失敗!");
     }
     else
     AfxMessageBox("申請記憶體失敗!");
    
   }
   CWnd *pWnd = GetDlgItem(IDC_PICTURE);
   CRect rect;
   pWnd->GetClientRect(&rect);
   CDC *pDC = pWnd->GetDC();
   IPicture *pPic;
   if(SUCCEEDED(OleLoadPicture(pStm,lDataSize,TRUE,IID_IPicture,(LPVOID*)&pPic)))
   {
     OLE_XSIZE_HIMETRIC hmWidth;    
     OLE_YSIZE_HIMETRIC hmHeight;
     pPic->get_Width(&hmWidth);
     pPic->get_Height(&hmHeight);    
     if(FAILED(pPic->Render(*pDC,0,0,rect.Width(),rect.Height(),0,hmHeight,hmWidth,-hmHeight,NULL)))
     AfxMessageBox("渲染影象失敗!");
     pPic->Release();
   }
   }
這樣寫也會出現當視窗重繪視窗圖片就會消失的問題,可以把上面的函式寫在OnPaint()中.整個顯示,存取和訪問圖片的程式就已經完成了.

    CoInitialize(NULL);

       _ConnectionPtr m_pConnect;

       try

       {

              // 建立Connection物件

              m_pConnect.CreateInstance("ADODB.Connection");

              // 設定連線字串,必須是BSTR型或者_bstr_t型別

              _bstr_t strConnect = "Provider=SQLOLEDB.1;Password=111111;Persist Security Info=True;User ID=sa;Initial Catalog=Picture;Data Source=SHOWFLY\\SQL2005";

              m_pConnect->Open(strConnect,"","",adModeUnknown);

       }

       // 捕捉異常

       catch(_com_error e)

       {

              // 顯示錯誤資訊

              AfxMessageBox(e.Description());

       }

       CFile   fileAdd;

       if(fileAdd.Open("F:/20087610203.JPG",CFile::modeRead)==0)    //開啟檔案

              return;

       _variant_t   varChunk;

       long   m_nFileLen   =   fileAdd.GetLength();

       BYTE*   m_pBMPBuffer;

       m_pBMPBuffer = new BYTE[m_nFileLen];

       if(m_pBMPBuffer==NULL)

              return;

       fileAdd.Read(m_pBMPBuffer,m_nFileLen);

//向資料庫新增圖片

       _RecordsetPtr m_pRecordset;

       m_pRecordset.CreateInstance(__uuidof(Recordset));

       try{

              m_pRecordset->Open(_variant_t("dbo.userphoto"),_variant_t((IDispatch*)m_pConnect,true),adOpenKeyset,adLockOptimistic,adCmdTable);

       }

       catch(_com_error &e)

       {

              ::MessageBox(NULL,"無法開啟userphoto表!","提示",MB_OK|MB_ICONWARNING);

       }

       char        *pBuf = (char*)m_pBMPBuffer;

       VARIANT              varBLOB;

       SAFEARRAY  *psa;

       SAFEARRAYBOUND    rgsabound[1];

       m_pRecordset->AddNew();                                              ///新增新記錄

       m_pRecordset->PutCollect("username",_variant_t("小李"));             ///為新記錄填充username欄位

       m_pRecordset->PutCollect("old",_variant_t((long)28));                 ///填充old欄位

       if(pBuf)

       {

              rgsabound[0].lLbound = 0;

              rgsabound[0].cElements = m_nFileLen;

              psa = SafeArrayCreate(VT_UI1, 1, rgsabound);                      ///建立SAFEARRAY物件

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

                     SafeArrayPutElement (psa, &i, pBuf++);                         ///pBuf指向的二進位制資料儲存到SAFEARRAY物件psa

              varBLOB.vt = VT_ARRAY | VT_UI1;                                   ///varBLOB的型別設定為BYTE型別的陣列

              varBLOB.parray = psa;                                             ///varBLOB變數賦值

              m_pRecordset->GetFields()->GetItem("photo")->AppendChunk(varBLOB);///加入BLOB型別的資料

       }

       m_pRecordset->Update();                                              ///儲存我們的資料到庫中

//從資料庫讀出圖片

       long   lDataLength = m_pRecordset->GetFields()->GetItem(_variant_t("photo"))->ActualSize;

       if (lDataLength>0)

       {

              _variant_t   varBLOB;

              varBLOB=m_pRecordset->GetFields()->GetItem(_variant_t("photo"))->GetChunk(lDataLength);

              if(varBLOB.vt== (VT_ARRAY|VT_UI1) && varBLOB.vt!=VT_EMPTY && varBLOB.vt!=VT_NULL )

              {

                     BYTE *pBuf = NULL;

                     pBuf = (BYTE*)GlobalAlloc(GMEM_FIXED,lDataLength);

                     SafeArrayAccessData(varBLOB.parray,(void   **)&pBuf);

                     CFile   outFile("D:/20087610203.bmp",CFile::modeCreate|CFile::modeWrite); //構造新檔案,如果檔案存在,則長度變為0

                     outFile.Write(pBuf,lDataLength);

                     outFile.Close();

                     SafeArrayUnaccessData (varBLOB.parray);

              }

       }

       m_pRecordset->Close();

       m_pConnect->Close();

       ::CoUninitialize();