Categories
blob images MS Access

Reading Images from BLOBS

My first post discussed how to store images into a BLOB (OLEObject) field in a access database. After several months I have decided it time to show how to read those out.

Firstly just remind you that the images are stored as is in the database table. You use a OLE Object field type, even though you are not stored a OLE Object in there.

What we use is this code which utilises some definition from the Edanamo library.


' Global Memory Flags
Const GMEM_MOVEABLE = &H2
Const GMEM_ZEROINIT = &H40
Const GHND = (GMEM_MOVEABLE Or GMEM_ZEROINIT)

Private Declare Function GlobalAlloc Lib "kernel32" (ByVal wFlags As Long, ByVal dwBytes As Long) As Long
Private Declare Function GlobalSize Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long)

Const PictureID = &H746C&

Private Type PictureHeader
Magic As Long
Size As Long
End Type

Public Function Array2Picture(aBytes() As Byte) As StdPicture
Dim oIPS As IPersistStream
Dim oStream As IStream
Dim hGlobal As Long
Dim lPtr As Long
Dim lSize As Long
Dim Hdr As PictureHeader

Set Array2Picture = New StdPicture ' Create a new empty picture object
Set oIPS = Array2Picture ' Get the IPersistStream interface
lSize = UBound(aBytes) - LBound(aBytes) + 1 ' Calculate the array size
hGlobal = GlobalAlloc(GHND, lSize + Len(Hdr)) ' Allocate global memory
If hGlobal Then
lPtr = GlobalLock(hGlobal) ' Get a pointer to the memory
Hdr.Magic = PictureID ' Initialize the header
Hdr.Size = lSize
CopyMemory ByVal lPtr, Hdr, Len(Hdr) ' Write the header
CopyMemory ByVal lPtr + Len(Hdr), aBytes(0), lSize ' Copy the byte array to the global memory
GlobalUnlock hGlobal ' Release the pointer
Set oStream = CreateStreamOnHGlobal(hGlobal, True) ' Create a IStream object with the global memory
oIPS.Load oStream ' Load the picture from the stream
Set oStream = Nothing ' Release the IStream object
End If
End Function

Notice that there is no usage of an intermediate file, as in other solutions. This looks more complex, and it is, but it is soo much faster.

Here is a sample code to read this from the table


dim ImgData as Variant
dim BLOB() as Byte
Dim oPic as StdPicture

set rs = CurrentDB.OpenRecordset("select img from image where id=100")

ImgData = rs(0).FieldSize 'the size of the bitmap
BLOB = rs(0).GetChunk(0,ImgData)
set oPic = Array2Picture(BLOB())

Once you has the StdPicture object you can then put into a ImageList or form control.

And that’s all there is to it. In a future post I will show how GDI+ can be used to good effect.