| ADOExpress Step-by-Step-from-Scratch Tech Note |
Delphi 5, ADOExpress, Access and Images
Using MS Office Access Sample Database "Northwind"
Summary: Many PCs with Microsoft Office have a sample Access database called "Northwind," which is useful for database experiments. This project shows that while the "normal" data can be manipulated in Northwind using Delphi and ADOExpress, there is no easy way (without yet-another-third-party-add-on) to display the images in this Access database using only Delphi 5 and ADOExpress. However, a crude "hack" is shown that does extract a TBitmap from the Photo TBlobField. More must be understood about this "hack" before the technique can be considered reliable and used in a "real" application.| A. Verify Access File Exists |
| B. Accessing the Northwind Database Using ADO |
| C. Attempts to Display Photo BLOB as Image - Using DBImage (doesn't work) - The "Hack" Job (works) |


Note that the "Photo" field is an "OLE Object" according to the design
view but is a "Bitmap Image" in the Photo data column.





Be sure to spell everything correctly in the SQL query. Otherwise, you may later see a terse and cryptic error messages.



What are the special characters showing in the Address field? The string, such as "Apt. 2A" for Nancy Davolio above, does not display in the Access database when these data are displayed. Apparently the special characters shown as the vertical bars are a carriage return ($0D) followed by a line feed ($0A). The Address field should correctly be viewed only in a multi-line display component, such as a Memo box.

How can the BLOB Photo field be displayed as a bitmap?
C. Attempts to Display Photo BLOB as Image
The DBImage component isn't "smart enough" to display a BLOB (for now).

Loading Bitmap from BlobField Stream. The following works, but isn't very general.
procedure TFormADOBLOB.Button1Click(Sender:
TObject);
begin
DataModuleNorthwind.ADOQueryNorthwindPhoto.SaveToFile('BLOB.DAT')
end;
| 1
151C2F00020000000D000E0014002100 ../...........!. 2 FFFFFFFF4269746D617020496D616765 ....Bitmap Image 3 005061696E742E506963747572650001 .Paint.Picture.. 4 05000002000000070000005042727573 ...........PBrus 5 6800000000000000000020540000424D h......... T..BM 6 16540000000000007600000028000000 .T......v...(... 7 C0000000DF0000000100040000000000 ................ 8 A0530000CE0E0000D80E000000000000 .S.............. 9 00000000000000000000800000800000 ................ 10 00808000800000008000800080800000 ................ 11 C0C0C000808080000000FF0000FF0000 ................ 12 00FFFF00FF000000FF00FF00FFFF0000 ................ 13 FFFFFF00FF0CB0C9000B090900000A00 ................ 14 9009000000000909A09A900B09000A90 ................ 15 A00000000FFFEFFFFFFFFFFFFFFFFFCB ................ 16 9CFCFEFAFFFFFFFFEDFFFEDEFFDEFEFC ................ 17 FFFFDADA00D900009009009000000000 ................ 18 090A00090BC0000900900000000A00AC ................ 19 A0E0E0E0F0E9CA9000A9CB0C00009090 ................ 20 E0000009090B0000D009009000000900 ................ 21 009A000FFFFFFFFFFFFEFFFFFFFFFCAD ................ 22 EBDBDFDFDFFFFFFFFFEFEDFFFEFFFFFF ................ 23 FEFCAF0C9A0A0D00009A000000000000 ................ 24 0009090A000B009A9000090000900C09 ................ 25 00900900FA90ADA00090B00B00000000 ................ ... |
Obviously line 2 says the data stream is a "Bitmap Image." I assume in Lines 4-5 that PBrush ("Paintbrush") is the program that should be used to open the file.
The "repeating pattern" in the above hex dump is likely the same portion of a scanline. This suggests dumping the ADOQueryNorthwindPhoto TBlobField to a stream, and loading a Bitmap using this stream.
The first two bytes of BMP files normally are "BM", so that it appears that the BMP file starts in line 5, at byte 14 above -- byte 78 within the file.
Who knows how to interpret the information in the first 78 bytes of this "OLE Object" (Access) / TBlobFIeld (ADOExpress)?
procedure
TFormADOBLOB.ButtonShowImageClick(Sender: TObject);
VAR
Bitmap : TBitmap;
MemoryStream: TMemoryStream;
begin
MemoryStream := TMemoryStream.Create;
TRY
DataModuleNorthwind.ADOQueryNorthwindPhoto.SaveToStream(MemoryStream);
// Who can explain why 78 bytes should be skipped here?
MemoryStream.Seek(78, soFromBeginning);
Bitmap := TBitmap.Create;
TRY
Bitmap.LoadFromStream(MemoryStream);
Image.Picture.Graphic := Bitmap
FINALLY
Bitmap.Free
END
FINALLY
MemoryStream.Free
END
end;
Francisco Leong suggests a slightly different approach:
VAR
P: TADOBlobStream;
...
BEGIN
P := TADOBlobStream.Create(BlobImageField, bmRead);
P.Seek(78, soFromBeginning);
TRY
Bitmap1.LoadFromStream(P);
FINALLY
P.Free
END
END;

I don't understand why Borland doesn't make using bitmaps in Access databases a little easier than this using ADOExpress. I started a thread in borland.public.delphi.database.ado about "ADOExpress with Access: Not Ready for Prime Time?" The response by Mark Edington from Borland at least acknowledged that this should be addressed and eventually will be.
Also see: Pictures inside a database -- Working with BLOBs. Storing pictures in Access
Links Verified 24 Jan 2000
Updated 18 Feb 2002
since 24 Jan 2000