周六和今天两天的时间,把数据库关于图片的存储和显示 实现了,虽然时间有点长,但是还是实现了。以下是网上找到的资料,很有用。
http://hi.baidu.com/%B0%A2%B3%ACyuch/blog/item/3a0d0845980f0744500ffe5b.html
第一步:首先是要打开一个位图文件,这里使用的控件用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()中.整个显示,存取和访问图片的程序就已经完成了.
http://hi.baidu.com/roufei13/blog/item/6528919e0fb23aa4c9eaf4d8.html
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();