第四節 在BLOB中尋找JPEG的開端
OLE對象類型格式—思路三(OLE object type format - take three!)
現在所有我們需要做的是存儲圖片到磁盤(存為普通的二進制文件)并了解它里門的內容是什么。
所有的圖片文件(格式)都有用來唯一的標識圖像的文件頭。JPG圖片文件以所謂的SOI標記開始,該標記的十六進制值是$FFD8。
下面一行代碼存儲圖片字段值到工作目錄的相關文件(BlobImage.dat)。在表單的OnCreate事件中放置這條代碼,開始工程以后再移除該代碼。
ADOTable1Picture.SaveToFile('BlobImage.dat');
一旦我們有了這個文件。我們就可以使用Hex editor看它的內容。
你相信嗎?MS access把連接的OLE對象的路徑作為對象定義的一部分存儲在OLE對象字段中。因為OLE對象的存儲定義沒有被文檔化(???這直接來自于MS),所以沒有辦法知道真正的圖像數據被寫之前能得到什么。
分兩個部分考慮這個問題。第一:我們需要找到'FFD8'并從那兒開始讀取圖像。第二:'FFD8'不可能總在文件的同一個位置。結論:我們需要一個函數,返回Access數據庫中存儲為OLE對象的JPG文件的SOI標記的位置。
正確的方法—思路四(The correct way - take four!)
提供了Blob類型字段后,我們的函數應返回ADOBlobStream中'FFD8'字符串的位置。ReadBuffer(讀緩沖區)從流中一個字節一個字節的讀取數據。對ReadBuffer的每個調用都會一個字節一個字節的移動流的位置。當兩個字節一起引出SOI標記時,函數返回流的位置。這是這個函數:
function JpegStartsInBlob(PicField:TBlobField):integer;
var
bS : TADOBlobStream;
buffer : Word;
hx : string;
begin
Result := -1;
bS := TADOBlobStream.Create(PicField, bmRead);
try
while (Result = -1) and (bS.Position + 1 < bS.Size) do
begin
bS.ReadBuffer(buffer, 1);
hx:=IntToHex(buffer, 2);
if hx = 'FF' then begin
bS.ReadBuffer(buffer, 1);
hx:=IntToHex(buffer, 2);
if hx = 'D8' then Result := bS.Position - 2
else if hx = 'FF' then
bS.Position := bS.Position-1;
end; //if
end; //while
finally
bS.Free
end; //try
end;
一旦我們有了SOI標記的位置,我們就能使用它在ADOBlob流中找到圖片的位置。
uses jpeg;
...
PRocedure TForm1.btnShowImageClick(Sender: TObject);
var
bS : TADOBlobStream;
Pic : TJpegImage;
begin
bS := TADOBlobStream.Create(AdoTable1Picture, bmRead);
try
bS.Seek(JpegStartsInBlob(AdoTable1Picture),soFromBeginning);
Pic:=TJpegImage.Create;
try
Pic.LoadFromStream(bS);
ADOImage.Picture.Graphic:=Pic;
finally
Pic.Free;
end;
finally
bS.Free
end;
end;
運行工程,OK!

現在誰會說編程沒有趣味?
注:在真正的代碼程序中,我們會在TDataSet的AfterScroll事件中加入代碼用于從當前行中讀取和顯示圖像(它在ADOTable1AfterScroll事件過程中)。當應用程序從一個記錄滾到另一個時,AfterScroll事件發生。
思路五!
這就是本章的主要內容?,F在你可以存儲和顯示所有你感興趣的JPG圖片。在這篇文章的最后一頁,我會提供完整的代碼(form1單元);所有的數據安排都放在表單的OnCreate事件中。這確保了所有的三個組件被正確連接—在設計時你不需要使用Object Inspector(對象檢視器)。
我承認,這一章不適合初學者,但世界是殘酷的!另一件事:你注意到最后你都不知道怎樣改變(或增加一些新的)表中的圖片!是的,那又是另一個完整的故事了!
新聞熱點
疑難解答
圖片精選