對於涉及圖像數據的數據庫應用程序,圖像數據的存取技術是一個關鍵。由於缺少技術文檔及DEMO例程演示,為此筆者在網上搜索了相關資料,有的根本不能用,有的過於繁雜,有的應用范圍太窄(如只能適用於BMP圖像),有的寫得過於簡單理解起來十分困難。。。而且在網上這也是大家比較關心的一個問題。筆者對這個問題進行了反復實作和探索,下邊筆者將通過一個完整的簡單例子來說明如何保存和顯示SQL數據庫中的圖像數據(同時包括BMP和JPEG兩種格式)。
一、 創建演示數據庫
在SQL SERVER中新建一演示數據庫:Demo,並創建一數據表Picture1,結構如下:
字段名 | Dtata Type | Identity |
Id | Int | Yes |
Isbmp | Tinyint | |
Myimage | Image |
字段Isbmp是用來記錄在Myimage中存入的圖像的類型(0表JPEG,1表BMP,其它值表無圖像),Isbmp數據類型選用整型Tinyint而末選用邏輯bit型主要是考慮到如下方法仍適用於ACCESS數據庫。在SQL中打開表Picture1,添入幾條記錄,Myimage圖像字段值暫不管,字段Isbmp值隨便輸入0和1之外的其它數。
二、 窗口設計
在DELPHI中新建一個工程,在FORM1上放置如表所示控件(考慮到TDBImage型控件不能正確顯示JPEG型圖像,所以選用Timage型控件顯示所有類型圖像)。
組件類別 | 組件屬性名 | 屬性值 | 用途說明 |
Timage | caption | Image1 | 顯示圖像 |
name | Image1 | ||
Stretch | True | ||
Tbutton | caption | 選擇圖像 | 選擇圖像 |
name | selectimage | ||
Tbutton | caption | 保存圖像 | 保存圖像到數據庫 |
name | savetodb | ||
TADOConnection | caption | Adoconnection1 | 創建與數據庫demo的連接 |
name | Adoconnection1 | ||
Connectionstring | 見備注 | ||
Connected | True | ||
Loginprompt | False | ||
Tadotable | Caption | Adotable1 | 建立與表Picture1的連接 |
name | Adotable1 | ||
Connection | Adoconnection1 | ||
Tablename | Picture1 | ||
Active | True | ||
Tdatasource | Name | Datasource1 | 建立數據源 |
Dataset | Adotable1 | ||
Topenpicturedialog | Caption | Openpicturedialog1 | 選擇圖像文件 |
Name | Openpicturedialog1 | ||
Tdbgrid | Caption | Dbgrid1 | 顯示記錄 |
Name | Dbgrid1 | ||
Datasource | Datasource1 |
備注:
adoconnection1.connectstring :=
'Provider=SQLOLEDB.1;Persist Security Info=False;User ID=sa;Initial Catalog=demo;
Data Source=Mysqlserver'
Mysqlserver為SQL服務器的名稱請據實際情況更改。
三、 程序代碼(首先在單元文件接口部分的uses語句中添入JPEG單元引用)
1. 圖像數據的選擇及保存
procedure TForm1.selectimageClick(Sender: TObject); //選擇圖像
begin
if openpicturedialog1.Execute then
image1.Picture.LoadFromFile(openpicturedialog1.FileName );
end;
procedure TForm1.savetodbClick(Sender: TObject); //保存圖像
var
strm:tmemorystream;
ext:string;
begin
if image1.picture.Graphic <> nil then //避免image1中無圖像保存出錯
begin
ext:=extractfileext(openpicturedialog1.FileName ); //取出文件的擴展名
strm := tmemorystream.Create ;
try
image1.Picture.Graphic.SaveToStream(strm);
adotable1.Edit ;
strm.Position :=0;
tblobfield(adotable1.FieldByName('myimage')).LoadFromStream(strm);
//如需直接由文件保存可采用如下注釋行
//TBlobField(adotable1.FieldByName('myimage')).LoadFromFile(OpenPictureDialog1.FileName);
//以下記錄保存到數據庫的圖像格式
if uppercase(ext) = '.BMP' then
adotable1.FieldByName('isbmp').Value := 1 //BMP型圖像數據
else if (uppercase(ext) = '.JPG') OR ( uppercase(ext) = '.JPEG') Then
adotable1.FieldByName('isbmp').Value := 0; //JPEG型圖像數據
adotable1.Post ;
finally
strm.Free ; //筆者發現如strm采用tblobstream類,程序運行到該語句會出現問題
end;
end;
end;
2. 圖像數據的讀取及顯示
從數據庫圖像字段中讀取數據然后在Image1中把圖像顯示出來的程序代碼,筆者先嘗試在Datasource1的OnDataChange事件中來完成,但會出錯,后改寫在adotable1的afterscroll事件中順利完成。
procedure TForm1.adoTable1AfterScroll(DataSet: TDataSet); //顯示圖像
var
strm:tadoblobstream;
jpegimage:tjpegimage;
bitmap:tbitmap;
begin
strm := tadoblobstream.Create(tblobfield(adotable1.fieldbyname('MYIMAGE')),bmread);
try //try1
strm.position :=0;
image1.Picture.Graphic := nil; //清除圖像
// BMP、JPEG兩種圖像數據必需分別處理
if adotable1.fieldbyname('isbmp').asstring ='1' then //BMP型圖像數據
begin //begin11
bitmap := tbitmap.Create ;
try //try11
bitmap.LoadFromStream(strm);
image1.Picture.Graphic := bitmap;
finally
bitmap.Free;
end; //end try11
end //end begin11
else if adotable1.fieldbyname('isbmp').asstring ='0' then //JPEG型圖像數據
begin //begin12
jpegimage := tjpegimage.Create ;
try //try12
jpegimage.LoadFromStream(strm);
image1.Picture.Graphic := jpegimage;
finally
jpegimage.Free ;
end; //end try12
end; //end begin12
finally
strm.Free ;
end; //end try1
end;
如果你想將數據庫中的圖像導出到外部文件中可采用如下關鍵語句:
image1.Picture.SaveToFile(FileName );
以上程序代碼不但適用於SQL數據庫,而且完全適用於ACCESS數據庫,但創建ACCESS數據庫時應注意圖像字段的數據類型應為OLE型,數據庫創建完成之后再將Adoconnection1連接到該ACCESS數據庫即可運行。欲知詳細情況,請索取源程序。以上提供了DELPHI利用Tsteam類存取JPEG、BMP圖像到數據庫的一種解決方案,筆者爭取下文介紹DELPHI利用ASSIGN方法存取JPEG、BMP圖像到數據庫的另一解決方案。
以上程序代碼在DELPHI6.0+SQL(或ACCESS)數據庫下運行通過。
Delphi圖像存取另類解決方案
在前文中,提供了一種DELPHI存取JPEG、BMP圖像到數據庫的解決方案,雖然它適用於ACCESS和SQL數據庫,但它並不適用於所有數據庫(比如PARADOX數據庫中的GRAPHIC圖像字段就不能采用該方法存取圖像數據),下文將介紹DELPHI利用ASSIGN方法存取JPEG、BMP圖像到數據庫的另一解決方案來進行補充完善。演示數據庫結構和窗口界面設計同前文,不再重述,將單元的相應程序代碼作如下更換:
1. 圖像數據的選擇及保存
procedure Tform1.selectimageClick(Sender: TObject); //選擇圖像
begin
if openpicturedialog1.Execute then
image1.Picture.LoadFromFile(openpicturedialog1.FileName );
end;
procedure Tform1.savetodbClick(Sender: TObject); //保存圖像到數據庫
var
ext:string;
begin
if image1.picture.Graphic <> nil then //避免image1中無圖像保存出錯
begin
adotable1.Edit ;
adotable1.FieldByName('myimage').Assign(image1.Picture.Graphic);
//以下記錄保存到數據庫的圖像格式
ext:=extractfileext(openpicturedialog1.FileName ); //取出文件擴展名
if uppercase(ext) = '.BMP' THEN
adotable1.FieldByName('isbmp').VALUE := 1 //BMP型圖像數據
ELSE IF (UPPERCASE(EXT) = '.JPEG') OR (UPPERCASE(EXT) = '.JPG') THEN
adotable1.FieldByName('isbmp').VALUE := 0; //JPEG型圖像數據
ADOTABLE1.Post ;
end;
end;
2. 圖像數據的讀取及顯示
procedure Tform1.ADOTable1AfterScroll(DataSet: TDataSet); //ADOTable1的AfterScroll事件方法程序
var
jpegimage:tjpegimage;
begin
image1.Picture.Graphic :=nil;
//下邊BMP、JPEG兩種圖像數據必需分別處理
if adotable1.fieldbyname('isbmp').Asstring = '1' then //BMP型圖像數據
image1.Picture.bitmap.Assign(adotable1.fieldbyname('myimage'))
//上邊語句中的bitmap不能為graphic,否則會出錯
else if adotable1.fieldbyname('isbmp').asstring = '0' then //JPEG型圖像數據
begin //begin2
jpegimage := tjpegimage.Create ; //通過jpegimage將圖像顯示在image1,否則會出錯
try
jpegimage.Assign(adotable1.fieldbyname('myimage'));
image1.Picture.Graphic :=jpegimage;
finally
jpegimage.Free ;
end; //end try
end; //end begin2
end;
注:別忘了在單元文件接口部分的uses語句中添入JPEG單元引用。
以上程序代碼在DELPHI6.0+SQL(或ACCESS或PARADOX)數據庫下運行通過。