Bild mit Transparenz aus Zwischenablage / Drag&Drop bekommen

    • VB.NET

      Bild mit Transparenz aus Zwischenablage / Drag&Drop bekommen

      Ich ärgere mich schon längere Zeit damit, dass Bilder, die aus der Zwischenablage mit diesem Code:

      VB.NET-Quellcode

      1. If Clipboard.ContainsImage Then
      2. DoSomething(Clipboard.GetImage)
      3. End If
      herausgeholt werden, die Transparenz verlieren.

      Ich habe mich deshalb auf die Suche nach einer Lösung gemacht. Weil das relativ lange gedauert hat und ich keine komplette Lösung gefunden habe, habe ich mich entschlossen, die Lösung hier zu posten, damit es andere leichter haben.

      Den Schlüssel habe ich von diesem Blog:
      hecgeek.blogspot.co.at/2007/04/converting-from-dib-to.html

      Nachfolgend der Code. Hoffentlich ausreichend kommentiert.

      VB.NET-Quellcode

      1. Sub ...()
      2. 'Das IDataObject stellt den Zugriff auf das Bild bereit.
      3. 'Die Zwischenablage kann über ClipBoard.GetDataObject() angesprochen werden.
      4. 'Per Drag&Drop gezogene Daten über die Data-Property der gelieferten DragEventArgs.
      5. Dim DataObject As IDataObject = ...
      6. Dim Bytes As Byte()
      7. 'DIB steht für "Device Independent Bitmap".
      8. 'Das IDataObject gibt für dieses Format einen MemoryStream zurück. Wir benötigen aber die rohen Bytes als Array.
      9. Using Stream = DirectCast(DataObject.GetData(DataFormats.Dib), System.IO.MemoryStream)
      10. If Stream Is Nothing Then
      11. 'Wenn der Stream Nothing ist, kann kein Bild abgerufen werden. Das trifft z.B. zu, wenn sich Text in der Zwischenablage befindet.
      12. End If
      13. 'Stream.Length ist vom Typ Int64. Ich ignoriere an dieser Stelle mal, dass es theoretisch so große Bilder geben könnte, denn da geht vorher der Arbeitsspeicher aus.
      14. Dim ByteCount = CInt(Stream.Length)
      15. Bytes = New Byte(ByteCount - 1) {}
      16. Stream.Read(Bytes, 0, ByteCount)
      17. End Using
      18. 'Der Header der DIB-Daten enthält am Anfang einen 32Bit-Wert und dann die Breite und Höhe des Bildes, angegeben als vorzeichenlose 32Bit-Werte (UInt32) im Big-Endian-Format (Höchstwertigstes Byte zuletzt).
      19. 'Der <<-Operator auf ein Byte angewandt, gibt ein Byte zurück. Das würde für diesen Zweck nicht funktionieren (Die Bits würden links abgeschnitten werden). Deshalb wird jedes Byte gleich zu UInt32 konvertiert. Das Ergebnis wird dann zu Int32 konvertiert (auch hier angenommen, dass kein normales Bild breiter als 2^31 Pixel ist).
      20. Dim Width = CInt(CUInt(Bytes(7)) << 24 Or CUInt(Bytes(6)) << 16 Or CUInt(Bytes(5)) << 8 Or CUInt(Bytes(4)))
      21. Dim Height = CInt(CUInt(Bytes(11)) << 24 Or CUInt(Bytes(10)) << 16 Or CUInt(Bytes(9)) << 8 Or CUInt(Bytes(8)))
      22. 'Per GCHandle wird das Byte-Array im Arbeitsspeicher "festgepinnt".
      23. Dim Handle = System.Runtime.InteropServices.GCHandle.Alloc(Bytes, System.Runtime.InteropServices.GCHandleType.Pinned)
      24. 'Der dritte Parameter (stride) gibt an, wie viele Bytes eine Zeile des Bildes benötigt. Da ein Pixel 4 Bytes groß ist (ARGB), ist Stride Width * 4.
      25. 'Der letzte Parameter (scan0) gibt die Adresse des Byte-Arrays an. Der Header der DIB-Daten ist 40 Bytes groß und wird übersprungen. Deshalb + 40.
      26. Dim Bpm As New Bitmap(Width, Height, Width * 4, Imaging.PixelFormat.Format32bppArgb, Handle.AddrOfPinnedObject + 40)
      27. 'Komischerweise ist das Bild vertikal gespiegelt. Deshalb muss noch RotateFlip angewandt werden.
      28. Bpm.RotateFlip(RotateFlipType.RotateNoneFlipY)
      29. 'Anschließend noch das GCHandle freigeben.
      30. Handle.Free()
      31. 'Hier kann mit Bpm weitergearbeitet werden.
      32. 'Disposen nicht vergessen ;)
      33. End Sub



      Edit:
      Ich habe Probleme, einen Bildausschnitt, der aus Paint kopiert ist, so zu bekommen. Das gibt einer AccessViolationException bei Bpm.RotateFlip().
      Wenn ich dazu komme, das genauer zu testen, werde ich versuchen, eine Lösung zu finden.
      (Windows 8 64bit)
      "Luckily luh... luckily it wasn't poi-"
      -- Brady in Wonderland, 23. Februar 2015, 1:56
      Desktop Pinner | ApplicationSettings | OnUtils

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Niko Ortner“ ()