資料庫儲存影像是常見需求,但 TDBImage 僅支援 BMP,無法正確顯示 JPEG。本文提供完整方案:使用 TImage 搭配 TJPEGImage 實現 BMP/JPEG 雙格式顯示,透過 TMemoryStream 讀寫 Blob 欄位,並以輔助欄位記錄影像格式,支援 SQL Server / Access 等主流資料庫。
-- SQL Server 範例
CREATE TABLE Picture1 (
ID INT IDENTITY(1,1) PRIMARY KEY,
IsBMP TINYINT NOT NULL DEFAULT 2, -- 0=JPEG, 1=BMP, 2=無圖片
MyImage IMAGE NULL -- Blob 欄位
);
TINYINT而非BIT,因 Access 不支援BIT型別,通用性更佳。
| 元件 | 名稱 | 關鍵屬性 | 用途 |
|---|---|---|---|
| TImage | Image1 | Stretch=True | 顯示 BMP/JPEG 影像 |
| TButton | btnSelect | Caption='選擇影像' | 開啟檔案對話框 |
| TButton | btnSave | Caption='儲存至資料庫' | 寫入 Blob |
| TOpenPictureDialog | OpenPicDlg | Filter='影像檔|*.bmp;*.jpg;*.jpeg' | 選擇影像檔 |
| TADOConnection | AdoConn | ConnectionString=...; Connected=True | 資料庫連線 |
| TADOTable | AdoTable | TableName='Picture1'; Active=True | 資料集 |
| TDataSource | DataSrc | DataSet=AdoTable | 資料綁定 |
| TDBGrid | DBGrid1 | DataSource=DataSrc | 顯示記錄列表 |
uses
..., JPEG; { 必須引用 JPEG 單元,才能使用 TJPEGImage }
procedure TForm1.btnSelectClick(Sender: TObject);
begin
if OpenPicDlg.Execute then
Image1.Picture.LoadFromFile(OpenPicDlg.FileName);
end;
procedure TForm1.btnSaveClick(Sender: TObject);
var
MS: TMemoryStream;
Ext: string;
begin
if Image1.Picture.Graphic = nil then begin
ShowMessage('請先選擇影像');
Exit;
end;
Ext := UpperCase(ExtractFileExt(OpenPicDlg.FileName)); // .BMP / .JPG / .JPEG
MS := TMemoryStream.Create;
try
// 1. 將 Picture 內容存入記憶體串流
Image1.Picture.Graphic.SaveToStream(MS);
MS.Position := 0;
// 2. 寫入 Blob 欄位
AdoTable.Edit;
TBlobField(AdoTable.FieldByName('MyImage')).LoadFromStream(MS);
// 替代寫法:直接從檔案 LoadFromFile(OpenPicDlg.FileName)
// 3. 記錄格式標記
if Ext = '.BMP' then
AdoTable.FieldByName('IsBMP').Value := 1
else if (Ext = '.JPG') or (Ext = '.JPEG') then
AdoTable.FieldByName('IsBMP').Value := 0
else
AdoTable.FieldByName('IsBMP').Value := 2; // 未知格式
AdoTable.Post;
ShowMessage('儲存成功');
finally
MS.Free; // 釋放串流
end;
end;
procedure TForm1.AdoTableAfterScroll(DataSet: TDataSet);
var
MS: TMemoryStream;
IsBMP: Integer;
begin
Image1.Picture := nil; // 清空舊圖
IsBMP := AdoTable.FieldByName('IsBMP').AsInteger;
if IsBMP = 2 then Exit; // 無圖片
MS := TMemoryStream.Create;
try
TBlobField(AdoTable.FieldByName('MyImage')).SaveToStream(MS);
MS.Position := 0;
if IsBMP = 1 then
Image1.Picture.Bitmap.LoadFromStream(MS) // BMP
else
Image1.Picture.Graphic.LoadFromStream(MS); // JPEG (透過 TJPEGImage 自動識別)
// 或明確: TJPEGImage(Image1.Picture.Graphic).LoadFromStream(MS);
finally
MS.Free;
end;
end;
| 項目 | 說明 |
|---|---|
| TImage vs TDBImage | TDBImage 綁定資料集但**僅支援 BMP**;TImage 需手動讀寫,但支援所有 TPicture 註冊的格式 (BMP/JPEG/GIF/PNG/ICO/WMF/EMF)。 |
| 格式識別策略 | 資料庫 Blob 本身**不含格式資訊**,必須額外欄位 (IsBMP) 記錄,或檢測檔案標頭 (Magic Bytes: BMP=42 4D, JPEG=FF D8 FF)。 |
| MemoryStream 釋放 | 務必在 try..finally 中 Free,避免記憶體洩漏。切勿使用 TBlobStream 當作區域變數,其行為在某些 Delphi 版本異常。 |
| 大圖片效能 | 超過 10MB 影像建議: • 分塊讀寫 ( TBlobStream Seek/Read)• 資料庫啟用 Filestream (SQL Server 2008+) • 僅存路徑,檔案放磁碟。 |
| Access 相容性 | Access 使用 OLE Object 型別儲存影像,實際為包裝過的 Blob,LoadFromStream/SaveToStream 同樣適用。 |
GraphicEx、PngComponents)。uses 中引入對應單元 (PngImage, GIFImg 等)。TPicture 會自動註冊新格式,Image1.Picture.LoadFromFile/Stream 即可支援,無需修改核心邏輯。ImgFormat: string[10]) 存儲 'BMP'/'JPG'/'PNG'/'GIF',讀取時依格式建立對應 TGraphic 子類實例。「TImage + TMemoryStream + 格式標記欄位」是 Delphi 資料庫影像存取的黃金組合:支援多格式、不依賴 TDBImage、相容主流資料庫、代碼簡潔可維護。掌握 SaveToStream/LoadFromStream、TBlobField 操作、JPEG 單元引用三大關鍵,即可構建穩健的影像管理模組。