把图片存/取至数据库
http://blog.chinaunix.net/uid-607545-id-2088102.html
http://blog.csdn.net/eryadabendan/article/details/6749939
关于图片的存储和显示
第一步:首先是要打开一个位图文件,这里使用的控件用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();
ζั͡ޓއ genji - 至此只为原地流浪.......