gpt4 book ai didi

vb.net - 将图像保存到 Access 数据库为 "Bitmap Image"

转载 作者:行者123 更新时间:2023-12-02 20:59:56 25 4
gpt4 key购买 nike

我能够使用内存流成功将图像保存到 Access 数据库表。我保存图像的列的数据类型为“OLEObject”。当我打开表时,我在此图像列中看到“长二进制数据”值。问题是,当我在此数据库中创建任何报告时,我无法看到图像。

而当我在MSPaint中打开图像文件,然后按Ctrl+A,然后按Ctrl+C复制所有图形,然后将其粘贴到Access数据库栏中时,则粘贴成功。现在将值显示为“位图图像”。当我双击图像列值时,它会在 MSPaint 中打开图像。并且也可以在报告中使用。我想知道如何将图像直接保存为“位图图像”类型?我使用的是 VB .Net Framework 4.0、Visual Studio 2012。

Image added thru VB .Net

Manually pasted from MSPaint

最佳答案

我能找到的任何文献中都没有记录 MS Access OLE 字段结构。

下面显示的 AccessOLEBitmapConverter 类是基于 How To Retrieve Bitmap from Access and Display It in Web Page 源代码中引用的文章 ( System.Drawing.ImageConverter Class ) 进行取证攻击的结果。对于方法GetBitmapStream

基于一些黑客攻击,我发现该字段包含两种结构:1) header 结构,2)EmbeddedObject结构。经过一番黑客攻击后,我发现 EmbeddedObject 结构的 Presentation 字段可以替换为 12 个字节的序列,只要 name header 结构中的 > 字段填充有六个字节的序列 ({33, 0, 255, 255, 255, 255})。请参阅代码以获取更多信息。

Public Class AccessOLEBitmapConverter
Const nullByte As Byte = 0
Const OLEVersion As Int32 = 1281
Private Shared arrayInvalid As String = "Source array is invalid"

Public Shared Function ToByteArray(sourceBitmap As Bitmap) As Byte()

Dim ret As Byte() = Nothing
Using ms As New IO.MemoryStream(5000)
EmbeddedObjectHeader.Write(ms)
EmbeddedObject.Write(ms, sourceBitmap)
ret = ms.ToArray()
End Using

Return ret
End Function

Public Shared Function ToBitmap(bytes As Byte()) As Bitmap
Dim ret As Bitmap = Nothing

If bytes Is Nothing Then Throw New ArgumentNullException("Argument ""bytes"" cannot be null")
If bytes.Length < 14 Then Throw New ArgumentOutOfRangeException(arrayInvalid)
Using ms As New IO.MemoryStream(bytes, False),
br As New IO.BinaryReader(ms, System.Text.Encoding.ASCII)
Dim signature As Int16 = br.ReadInt16()
If signature <> &H1C15 Then Throw New ArgumentOutOfRangeException(arrayInvalid)

Dim headersize As Int16 = br.ReadInt16() ' 47
If bytes.Length < headersize Then Throw New ArgumentOutOfRangeException(arrayInvalid)

ms.Position = headersize

' Start ObjectHeader
If ms.Position = bytes.Length Then Throw New ArgumentOutOfRangeException(arrayInvalid)
Dim OLEVersion As UInt32 = br.ReadUInt32
If ms.Position = bytes.Length Then Throw New ArgumentOutOfRangeException(arrayInvalid)
Dim FormatID As UInt32 = br.ReadUInt32

If ms.Position = bytes.Length Then Throw New ArgumentOutOfRangeException(arrayInvalid)
Dim ClassName As String = LengthPrefixedAnsiString.Read(br)

If ms.Position = bytes.Length Then Throw New ArgumentOutOfRangeException(arrayInvalid)
Dim TopicName As String = LengthPrefixedAnsiString.Read(br)

If ms.Position = bytes.Length Then Throw New ArgumentOutOfRangeException(arrayInvalid)
Dim ItemName As String = LengthPrefixedAnsiString.Read(br)
' End ObjectHeader

If ms.Position = bytes.Length Then Throw New ArgumentOutOfRangeException(arrayInvalid)
Dim NativeDataSize As Int32 = br.ReadInt32

If (ms.Position + NativeDataSize) > bytes.Length Then Throw New ArgumentOutOfRangeException(arrayInvalid)
Dim NativeData As Byte() = br.ReadBytes(NativeDataSize)

Dim msImage As New IO.MemoryStream(NativeData)

ret = CType(Image.FromStream(msImage), Bitmap)
End Using


Return ret
End Function

Private Class EmbeddedObjectHeader
' ref: How To Retrieve Bitmap from Access and Display It in Web Page
' https://support.microsoft.com/en-us/kb/175261

Friend Shared Sub Write(ms As System.IO.MemoryStream)
Const signature As Int16 = &H1C15
Const headersize As Int16 = 47S
Const objectType As Int16 = 2S
Const nameLen As Int16 = 0S
Const classLen As Int16 = 13S
Const nameOffset As Int16 = 14S
Const classOffset As Int16 = 20S
Const classType As String = "Bitmap Image"
Const hdrClassName As String = "Paint.Picture"

Using bw As New IO.BinaryWriter(ms, System.Text.Encoding.ASCII, True)
With bw
.Write(signature)
.Write(headersize)
.Write(objectType)
.Write(nameLen)
.Write(classLen)
.Write(nameOffset)
.Write(classOffset)

' Even though this offset is declared as being for the 'name' field and
' the 'name' field always has a zero length, these six bytes must be present
' to allow the resultant byte array to be identified as a BitMap Image by Access
ms.Position = nameOffset
.Write(New Byte() {33, 0, 255, 255, 255, 255})

ms.Position = classOffset
.Write(classType.ToCharArray())
.Write(nullByte)
.Write(hdrClassName.ToCharArray())
.Write(nullByte)
End With
End Using
End Sub
End Class ' EmbeddedObjectHeader

Private Class EmbeddedObject
' ref: https://msdn.microsoft.com/en-us/library/dd942053.aspx
'Header (variable): This MUST be an ObjectHeader (section 2.2.4).
' The FormatID field of the Header MUST be set to 0x00000002.

'NativeDataSize (4 bytes): This MUST be set to the size of the NativeData field, in bytes.

'NativeData (variable): This must be an array of bytes that contains the native data.

'Presentation (variable): This MUST be a MetaFilePresentationObject (section 2.2.2.1),
' a BitmapPresentationObject (section 2.2.2.2), a DIBPresentationObject (section 2.2.2.3),
' a StandardClipboardFormatPresentationObject (section 2.2.3.2), or
' a RegisteredClipboardFormatPresentationObject (section 2.2.3.3).

Friend Shared Sub Write(ms As System.IO.Stream, sourceBitmap As Bitmap)

Using bw As New IO.BinaryWriter(ms, System.Text.Encoding.ASCII, True)
With bw
ObjectHeader.Write(ms)

' Determine and write the NativeDataSize and NativeData fields
Using imgStream As New IO.MemoryStream(20000)
sourceBitmap.Save(imgStream, System.Drawing.Imaging.ImageFormat.Bmp)
Dim NativeDataSize As Int32 = CInt(imgStream.Length)
.Write(NativeDataSize)
.Write(imgStream.ToArray)
End Using

' At this point the 'Presentation' variable should be written.
' However, Bitmap files copied from Windows Explorer and pasted into
' the MS Access OLE field have only 12 bytes written and this allows for
' a much smaller size to be stored as the 'Presentation' variable appears to
' duplicate the NativeData field. Adding the Bitmap via the 'Insert Object'
' dialog creates a storage nearly twice that of this method.

' The first 4 bytes correspond to the integer value for OLEVersion.
.Write(OLEVersion)
' The next 4 bytes are always zero.
.Write(0I)
' The next byte (position 8) appears variable and its value does not appear
' to impact using the 'BitMap Image' in Access. So write a zero.
.Write(nullByte)
' The final three bytes appear to be constant {173, 5, 254}
.Write(New Byte() {173, 5, 254})
.Flush()
End With
End Using
End Sub

End Class 'EmbeddedObject

Private Class ObjectHeader
Friend Shared Sub Write(ms As System.IO.Stream)
Const FormatID As Int32 = 2
Const ClassName As String = "PBrush"
Const TopicName As String = ""
Const ItemName As String = ""

Using bw As New IO.BinaryWriter(ms, System.Text.Encoding.ASCII, True)
With bw
.Write(OLEVersion)
.Write(FormatID)
LengthPrefixedAnsiString.Write(bw, ClassName)
LengthPrefixedAnsiString.Write(bw, TopicName)
LengthPrefixedAnsiString.Write(bw, ItemName)
End With
End Using
End Sub

End Class ' ObjectHeader

Private Class LengthPrefixedAnsiString
' ref : https://msdn.microsoft.com/en-us/library/dd942554.aspx
' This structure specifies a null-terminated American National Standards Institute (ANSI) character set string.
' Length (4 bytes): This MUST be set to the number of ANSI characters in the String field,
' including the terminating null character. Length MUST be set to 0x00000000 to indicate an empty string.
' String (variable): This MUST be a null-terminated ANSI string.

Const nullChar As Byte = 0

Friend Shared Function Read(br As IO.BinaryReader) As String
Dim ret As String = String.Empty
Dim length As Int32 = br.ReadInt32
If length > 0 Then
Dim chars As Char() = br.ReadChars(length)
ret = New String(chars)
End If
Return ret
End Function

Friend Shared Sub Write(bw As IO.BinaryWriter, val As String)
If val.Length = 0 Then
bw.Write(0I)
Else
bw.Write(val.Length + 1)
bw.Write(val.ToCharArray)
bw.Write(nullChar)
End If
End Sub
End Class 'LengthPrefixedAnsiString
End Class

使用示例:

' To obtain a Byte() to store a Bitmap to MS Access
Dim bm As Bitmap = CType(Image.FromFile("SomeBitmapFile.bmp"), Bitmap)
Dim bytesToStoreInAccess As Byte() = AccessOLEBitmapConverter.ToByteArray(bm)

' To retrieve a Bitmap from an Access Bitmap Image field.
Dim bytesFromBitmapImageField As Byte() ' set this equal to the field data
Dim bmRetrieved As Bitmap = AccessOLEBitmapConverter.ToBitmap(bytesFromBitmapImageField)

此代码已在 Windows 10 计算机上使用 MS Access 2007 成功测试,将位图存储到 Access OLE 字段,以生成可在 Access 报告中显示的 MS Access 位图图像。

关于vb.net - 将图像保存到 Access 数据库为 "Bitmap Image",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38875177/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com