Re: Bitmap aus Zwischenablage lesen
From: Arne Janning (spam.me-here.arnolo_at_msn.com)
Date: 06/13/04
- Next message: Karsten Sosna: "Re: Datensatz ändern mit ADO.NET"
- Previous message: Markus Schuhmacher: "Re: Zufallsgenerator"
- In reply to: Christoph Redl: "Bitmap aus Zwischenablage lesen"
- Messages sorted by: [ date ] [ thread ]
Date: Sun, 13 Jun 2004 06:15:39 +0200
Christoph Redl wrote:
> Ich will ein Bitmap aus der System-Zwischenablage in mein
> Programm kopieren. Letztendlich will ich ein Bitmap-Objekt
> in meinem Programm haben.
> Um festzustellen ob ein Bitmap in der Zwischenablage ist
> benutze ich folgenden Code:
>
> Clipboard.GetDataObject().GetDataPresent
> (System.Windows.Forms.DataFormats.Dib, True)
>
> Unter WinXP funktioniert es auch, wenn ich das Format
> System.Windows.Forms.DataFormats.Bitmap überprüfe.
> Unter Win98 und WinME erkennt er mir das Bitmap aber nur
> als System.Windows.Forms.DataFormats.Dib.
>
> Daher wollte ich wissen, wie ich als Dib gespeicherte
> Daten in ein Bitmap-Objekt bekomme.
> Wenn ich versuche es ganz normal als Bitmap einzulesen
> erhalte ich einen Fehler.
> Wenn ich versuche es als Dib einzulesen und einem Bitmap-
> Objekt zuzuweisen erhalte ich ebenfalls einen Fehler.
Hallo Christoph,
das Problem ist, dass es in .NET zwar einen Wrapper für die
GDI+-Bitmap-Funktion GdipCreateBitmapFromHBITMAP gibt (das ist
Image.FromHbitmap(IntPtr hbitmap)), es aber tatsächlich keinen Wrapper
für GdipCreateBitmapFromGdiDib gibt. Scheinbar ist das einfach vergessen
worden. Referenz der GDI+-Bitmap-Funktionen ist hier:
http://msdn.microsoft.com/library/?url=/library/en-us/gdicpp/GDIPlus/GDIPlusReference/FlatBitmap.asp
Thomas Scheidegger hat einen einen Workaround dafür geschrieben:
http://dnetmaster.net/source/dibtoimage.zip
Du kannst seinen Code (C#) verwenden oder nur den, der für Dich relevant
ist und den ich nach VB.NET portiert habe und unten anhänge.
Die Benutzung ist in beiden Fällen dieselbe:
Imports System.Runtime.InteropServices
'Clipboard-Daten holen
Dim obj As Object =
Clipboard.GetDataObject().GetDataPresent(DataFormats.Dib)
'In einen MemoryStream casten
Dim stream As System.IO.MemoryStream = CType(obj, System.IO.MemoryStream)
Dim img As Byte() = stream.ToArray()
'Reserviert einen Speicherblock
Dim p As IntPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(img(0)) *
img.Length)
'Kopiert die Daten in einen nicht verwalteten Speicherzeiger
Marshal.Copy(img, 0, p, img.Length)
Try
'DibToImage.WithStream(p) liefert ein Bitmap-Objekt
pictureBox1.Image = DibToImage.WithStream(p)
Catch ex As Exception
'Fehlerbehandlung
Finally
'Speicherblock wieder freigeben
Marshal.FreeCoTaskMem(p)
End Try
Hier der DibToImage-Quelltext:
'DibToImage.vb
Imports System
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.IO
Imports System.Runtime.InteropServices
Public Class DibToImage
Public Shared Function WithStream( _
ByVal dibPtr As IntPtr) As Bitmap
Dim fh As BITMAPFILEHEADER = New BITMAPFILEHEADER
Dim bmiTyp As Type = GetType(BITMAPINFOHEADER)
Dim bmi As BITMAPINFOHEADER = _
CType(Marshal.PtrToStructure( _
dibPtr, bmiTyp), BITMAPINFOHEADER)
If bmi.biSizeImage = 0 Then
bmi.biSizeImage = _
((((bmi.biWidth * bmi.biBitCount) + 31) _
And -32) >> 3) * Math.Abs(bmi.biHeight)
End If
If bmi.biClrUsed = 0 AndAlso bmi.biBitCount < 16 Then
bmi.biClrUsed = 1 << bmi.biBitCount
End If
Dim fhSize As Int32 = _
Marshal.SizeOf(GetType(BITMAPFILEHEADER))
Dim dibSize As Int32 = _
bmi.biSize + (bmi.biClrUsed * 4) + bmi.biSizeImage
fh.Type = New Char() {CChar("B"), CChar("M")}
fh.Size = fhSize + dibSize
fh.OffBits = fhSize + _
bmi.biSize + (bmi.biClrUsed * 4)
Dim data(fh.Size) As Byte
RawSerializeInto(fh, data)
Marshal.Copy(dibPtr, data, fhSize, dibSize)
Dim stream As MemoryStream = _
New MemoryStream(data)
Dim tmp As Bitmap = New Bitmap(stream)
Dim result As Bitmap = New Bitmap(tmp)
tmp.Dispose()
tmp = Nothing
stream.Close()
stream = Nothing
data = Nothing
Return result
End Function
Private Shared Sub RawSerializeInto( _
ByVal anything As Object, ByVal datas As Byte())
Dim rawsize As Int32 = Marshal.SizeOf(anything)
If rawsize > datas.Length Then
Throw New ArgumentException( _
"buffer too small", "byte() datas")
End If
Dim handle As GCHandle = GCHandle.Alloc( _
datas, GCHandleType.Pinned)
Dim buffer As IntPtr = handle.AddrOfPinnedObject()
Marshal.StructureToPtr(anything, buffer, False)
handle.Free()
End Sub
<StructLayout(LayoutKind.Sequential, _
CharSet:=CharSet.Ansi, Pack:=1)> _
Private Class BITMAPFILEHEADER
<MarshalAs(UnmanagedType.ByValArray, _
SizeConst:=2)> _
Public Type As Char()
Public Size As Int32
Public reserved1 As Int16
Public reserved2 As Int16
Public OffBits As Int32
End Class
<StructLayout(LayoutKind.Sequential, Pack:=2)> _
Private Class BITMAPINFOHEADER
Public biSize As Int32
Public biWidth As Int32
Public biHeight As Int32
Public biPlanes As Int16
Public biBitCount As Int16
Public biCompression As Int32
Public biSizeImage As Int32
Public biXPelsPerMeter As Int32
Public biYPelsPerMeter As Int32
Public biClrUsed As Int32
Public biClrImportant As Int32
End Class
End Class
Gruß
Arne Janning
- Next message: Karsten Sosna: "Re: Datensatz ändern mit ADO.NET"
- Previous message: Markus Schuhmacher: "Re: Zufallsgenerator"
- In reply to: Christoph Redl: "Bitmap aus Zwischenablage lesen"
- Messages sorted by: [ date ] [ thread ]
Relevant Pages
|