修改了一下-----VC下显示位图的几种方法 中 的/*******************通过读取位图文件来显示位图**********************/
既然是向数据库中添加位图信息,那么有必须明白我们的数据是以什么形式存放在数据库的,当然没有别的方法,只能是二进制了,所以在创建数据库的时候,一定要注意选择的字段的类型,不然是添加下进去的。(刚开始的时候,我就遇到了这个问题,费了好长时间才搞定的。Access中的字段定义为” OLE 对象”,sql2000中字义为image就行了。
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");
}
既然是向数据库中添加位图信息,那么有必须明白我们的数据是以什么形式存放在数据库的,当然没有别的方法,只能是二进制了,所以在创建数据库的时候,一定要注意选择的字段的类型,不然是添加下进去的。(刚开始的时候,我就遇到了这个问题,费了好长时间才搞定的。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();
其次建表: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=你的数据库名字
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 ;
}
}