Einige Bilddatei-Formate (z..B. TIFF, PNG oder JPEG) bieten die Möglichkeit, ergänzende Informationen zum Bild einzutragen. Diese Angaben werden im Bild nicht sichtbar, können aber durch spezielle Routinen verwaltet werden. Es handelt sich dabei z.B. um den Titel des Bildes, einen Kommentar, das Erstellungsdatum oder um einen Kennstring zum verwendeten Kameramodell. Auch ein kleines Vorschaubild ("Thumbnail") kann enthalten sein. Praktisch sind solche Extra-Infos bei der Verwaltung der eigenen Fotografien, weil diese Angaben beim Umbenennen, Kopieren, Verschieben oder Versenden einer Bilddatei erhalten bleiben. Das Net-Framework umfasst den Namespace "System.Windows.Media.Imaging", der Methoden zum Lesen und Schreiben der Extra-Infos für Bilddatei-Formate enthält - sog. Metadaten. Laut VB-Doku lesen und schreiben diese Routinen bei JPEGs nach dem Standard des “International Press Telecommunications Council” (IPTC). Allerdings verarbeiten nicht alle Bildbearbeitungsprogramme, die sich auf diesen Standard beziehen, alle Felder und auch nicht in gleicher Weise. Das Modul: Variablen der Struktur "strucJPEGExtraInfos" dienen zum Eintragen und Abfragen der ergänzenden Bild-Informationen und werden als Parameter der Funktionen "SetJPEGExtraInfos" und "GetJPEGExtraInfos" verwendet. Vor der Verwendung müssen die Strukturvariablen durch die Methode "Clear" initialisiert werden. Die Gesamtlänge (Anzahl Zeichen) der zusätzlichen Angaben in einem ITPC-Header sollte 8192 nicht übersteigen. Falls im JPEG zu einem Feld keine Angabe enthalten ist, gibt die Parametervariable "ExtraInfos" beim Lesen mit "GetJPEGExtraInfos" einen Leerstring zurück bzw. bei "DateTaken" den Default-Wert und bei "Rating" den Wert 0. Die Angaben zum Autor und zu den Schlüsselwörtern werden als Listen verwaltet. Man beachte, dass das Feld "DateTaken" im Datentyp "BitmapMetaData" zwar als String geführt ist, intern aber ein gültiges Zeit-Format erwartet wird ("Win32-FileTime"). Die Routine "SetJPEGExtraInfos" passt den Date-Wert an dieses Format an. Beim Lesen des Feldes kommt es gelegentlich zu einer Fehlermeldung weil manche Bildverarbeitungssoftware ein anderes Format in das Datums-Feld schreibt. Die Routine "GetJPEGExtraInfos" fängt ggf. die Ausnahme auf und registriert den Vorfall im Feld "ErrorMessage" (als Initialisierungs-, Überlauf- oder Bereichsfehler). Der Lesevorgang wird danach fortgesetzt. Die Thumbnails werden in "strucJPEGExtraInfos" zur einfacheren Verwendung als Instanzen der Klasse Bitmap (System.Drawing) abgelegt. Diese Klasse ist nicht kompatibel zur Klasse "BitmapSource" (System.Windows.Media.Imaging). Das Modul enthält deshalb Methoden zur Umwandlung. Die Routine "SetJPEGExtraInfos" überträgt die Bilddaten der Quell-Datei direkt (=verlustfrei) in die angegebene Zieldatei und fügt die Angaben im Parameter "ExtraInfos" im Datei-Header ein. Alle Felder in "strucJPEGExtraInfos" sind beim Schreiben mit "SetJPEGExtraInfos" optional. Wird zu einem Feld keine Angabe gemacht, bleibt die entsprechende Eintragung in der neu erstellten Bilddatei leer bzw. bereits vorhandene Angaben in der Quell-Bilddatei werden unverändert übernommen (sonst: ggf. überschrieben). Der Parameter "AllowOverwrite" legt fest, ob eine bereits vorhandene Zieldatei in den Papierkorb verschoben werden darf. Falls kein Vorschaubild angegeben worden ist, wird ein bereits vorhandenes Thumbnail aus der Quell-Datei übernommen bzw. neu erstellt. (Das direkte Eintragen von ergänzenden Informationen in eine bereits bestehende Bilddatei ist weniger empfehlenswert, weil bei der dabei erforderlichen Reorganisation der Kopfangaben Probleme auftreten können.) Viele Digitalkameras speichern technische Details (z.B. Blende, Belichtungszeit, Brennweite, ISO, Blitz, Belichtungsverfahren, Korrektur-Einstellungen - bis zu 50 Infos). Auch Angaben zum Farbraum oder zu Pixeldimensionen können enthalten sein. Diese Daten werden gemäß dem "Exchangeable Image File Format” (Exif) direkt in die Bild-Datei geschrieben. Die Routine "ReadEXIF" liest alle vorhandenen Klartext-"Exif"-Angaben und gibt sie als Liste zurück. Ergänzende Hinweise: Gelegentlich kann eine JPEG-Datei nicht decodiert werden, obwohl andere Bildbearbeitungssoftware dazu eventuell in der Lage ist. Die Fehlertoleranz des JPEGDecoders ist vergleichsweise gering. Es kommt z.B. zur Fehler-Rückgabe: "Keine geeignete Imaging-Komponente gefunden". Die Meldung "Ungeeigneter Datenstromtyp" weist meist darauf hin, dass die angegebene Datei keine JPEG-Codierung enthält. In seltenen Fällen meldet "GetJPEGExtraInfos" den Fehler "beschädigter Metadaten-Header". Soweit ich beurteilen kann, ist die Ursache häufig keine tatsächliche Beschädigung, sondern ein nicht unterstütztes Metadaten-Format. Die Extra-Infos können in diesem Fall nicht gelesen werden. Fehlerhafte oder ungültige Einträge können dazu führen, dass der Virenscanner ein "Exploit" entdeckt und die erstellte JPEG-Datei in die "Quarantäne" verschiebt oder sie löscht. Die VB-Dokumentation ist zu allen diesen Punkten sehr lückenhaft. Hilfreich war der Blog von Robert A. Wlodarczyk, der C#-Code enthält (Download unter: http://rwlodarcmsdnblog.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=35304) Beispiel: Private Sub Demo() Dim picfile As String = "I:\daten\adriana.jpg" Dim picfile_new As String = "I:\daten\adriana_new.jpg" Dim extrainfos_write, extrainfos_read As New clsJPEGExtraInfos Dim errormessage As String = "" ' alle Angaben optional / ' Thumbnail automatisch, falls nicht vorhanden With extrainfos_write .Title = "<Titel des Bildes>" .Authors.Add("<Autor>") .Authors.Add("<CoAutor>") .Keywords.Add("<Kategorie 1>") .Keywords.Add("<Kategorie 2>") .Comment = "<Bild-Kommentar>" .DateTaken = CDate("1.1.2010") .Subject = "<Motivangaben o.ä.>" .ApplicationName = "SetJPEGExtraInfos" .CameraModel = "<verwendete Kamera>" End With ' Informationen in die Bilddatei eintragen If Not SetJPEGExtraInfos(picfile, picfile_new, extrainfos_write, , errormessage) Then MessageBox.Show(errormessage, "", MessageBoxButtons.OK, _ MessageBoxIcon.Exclamation) Else If extrainfos_write.ErrorMessage <> String.Empty Then MessageBox.Show("Einige Datenfelder konnten nicht eingetragen werden" & _ Environment.NewLine & extrainfos_write.ErrorMessage, "", _ MessageBoxButtons.OK, MessageBoxIcon.Exclamation) End If ' Geschriebene Informationen zur Kontrolle wieder einlesen If Not GetJPEGExtraInfos(picfile_new, extrainfos_read, errormessage) Then MessageBox.Show(errormessage, "", MessageBoxButtons.OK, _ MessageBoxIcon.Exclamation) End If End If ' Um Angaben zu ergänzen, liest man zunächst die vorhandenen ' Daten, hängt die neuen Einträge an die gelesenen Strings und ' schreibt die erweiterten Daten in eine neue Bilddatei End Sub Das Modul "modJPEGExtraInfos" Option Strict On Option Explicit On Option Infer Off ' Erforderliche Verweise auf Framework-Bibliotheken: ' System, System.Core, System.Drawing ' PresentationCore, PresentationFramework, Windowbase Imports System ' Exception, StringComparison, IntPtr Imports System.IO ' FileStream Imports Microsoft.VisualBasic.FileIO ' UIOption, RecycleOption Imports System.Windows.Media.Imaging ' (JPEG)BitmapDecoder, 'Bitmapframe, -source, -metadata, -createoptions, -sizeoptions, -cachoption Imports System.Runtime.InteropServices ' Marshall Imports System.Drawing ' Bitmap. Rectangle, Imaging Imports System.Collections.Generic ' List(Of T) Imports System.Collections.ObjectModel ' ReadOnlyCollection(Of T) ''' <summary> ''' Verwaltung ergänzender Bildinformationen ''' </summary> Module modJPEGExtraInfos Const cMaxStringLength As Integer = 256 'maximale Länge Stringeintrag Const cThumbnailHeight As Integer = 200 'Höhe des Thumbnails (Pixel) #Region "strucJPEGExtraInfos" ''' <summary>Datenstruktur für ergänzende Bildinformationen</summary> Public Class clsJPEGExtraInfos Friend Const DefaultDate As Date = #1/2/1601# ''' <summary>Anwendung für Bildverwaltung</summary> Public ApplicationName As String ''' <summary>Liste der Autoren</summary> Public Authors As List(Of String) ''' <summary>Hersteller der aufnehmenden Kamera</summary> Public CameraManufacturer As String ''' <summary>Modelbezeichnung der aufnehmenden Kamera</summary> Public CameraModel As String ''' <summary>Kommentar zum Bild</summary> Public Comment As String ''' <summary>Copyright-Vermerk</summary> Public Copyright As String ''' <summary>Aufnahme-/Erstellungs-Datum</summary> Public DateTaken As Date ''' <summary>Liste der Schlüsselworte zur Bildverwaltung</summary> Public Keywords As List(Of String) ''' <summary>positive Ganzzahl (Bild-Rating)</summary> Public Rating As UInteger ''' <summary>Thema/Verwendungszweck des Bildes</summary> Public Subject As String ''' <summary>Titel des Bildes</summary> Public Title As String ''' <summary>Thumbnail als Bitmap (oder Nothing)</summary> Public Thumbnail As Bitmap ''' <summary>Rückgabe: Fehler bei Bearbeitung (oder Leer)</summary> Public ErrorMessage As String ' Konstruktor (incl. Initialisierung) Public Sub New() Clear() End Sub ''' <summary>Initialisiert die Elemente der Struktur</summary> Public Sub Clear() Dim e As String = String.Empty Authors = New List(Of String) : Keywords = New List(Of String) ApplicationName = e Comment = e : Copyright = e ' DefaultDate = CDate("#1/2/1601#") DateTaken = DefaultDate : Rating = 0 CameraManufacturer = e : CameraModel = e Subject = e : Title = e : ErrorMessage = e Thumbnail = Nothing End Sub End Class #End Region #Region "Öffentliche Methoden (Lesen und Schreiben von Metadaten)" ''' <summary>Ergänzen von Rahmeninformationen in einer Bilddatei</summary> ''' <param name="filename">Bilddatei (JPEG-codiert)</param> ''' <param name="savefilename">Ausgabedatei mit den Rahmeninformationen ''' (wird ggf. gelöscht!)</param> ''' <param name="ExtraInfos">Rahmenangaben zur Bilddatei</param> ''' <param name="AllowOverwrite">Darf die Zieldatei - falls bereits vorhanden - ''' in den Papierkorb geworfen werden?</param> ''' <param name="ErrorMessage">Fehlermeldung (oder Leer)</param> ''' <returns>Alles OK?</returns> Public Function SetJPEGExtraInfos(ByVal filename As String, _ ByVal savefilename As String, _ ByVal ExtraInfos As clsJPEGExtraInfos, _ Optional ByVal AllowOverwrite As Boolean = False, _ Optional ByRef ErrorMessage As String = "") As Boolean ' Rückgabe initialisieren ErrorMessage = String.Empty ExtraInfos.ErrorMessage = String.Empty ' Berechnung des erforderlichen Zusatzspeichers Dim PaddingAmount As UInteger = ComputePaddingAmount(ExtraInfos) If PaddingAmount > 8192 Then ErrorMessage = "Zu viele ExtraInfos" : Return False End If Dim source As BitmapDecoder ' zum Lesen des Bildes Dim jpegenc As New JpegBitmapEncoder ' zum Schreiben des Bildes Dim md As BitmapMetadata ' Aktualisierung der ExtraInfos Dim CreateOptions As BitmapCreateOptions = _ BitmapCreateOptions.PreservePixelFormat Or _ BitmapCreateOptions.IgnoreColorProfile Dim str() As String Dim thumb As BitmapSource = Nothing Try With My.Computer.FileSystem If Not .FileExists(filename) Then ErrorMessage = "Bilddatei nicht vorhanden" Return False End If If .FileExists(savefilename) Then If Not AllowOverwrite Then ErrorMessage = "Die Ausgabedatei ist bereits vorhanden" Return False Else .DeleteFile(savefilename, _ UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin) End If End If End With Catch ex As Exception ErrorMessage = ex.Message : Return False End Try Try Using picstream As New FileStream _ (filename, FileMode.Open, FileAccess.Read) source = BitmapDecoder.Create _ (picstream, CreateOptions, BitmapCacheOption.None) If Not source.CodecInfo.FileExtensions.ToLower.Contains("jpg") Then ErrorMessage = "Kein Decoder für das File vorhanden" Return False End If If source.Frames(0) IsNot Nothing And _ source.Frames(0).Metadata IsNot Nothing Then ' Metadaten der Eingabedatei klonen md = CType(source.Frames(0).Metadata.Clone, BitmapMetadata) ' zusätzlich benötigten Speicher anfordern md.SetQuery("/app1/ifd/PaddingSchema:Padding", PaddingAmount) md.SetQuery("/app1/ifd/exif/PaddingSchema:Padding", PaddingAmount) md.SetQuery("/xmp/PaddingSchema:Padding", PaddingAmount) With ExtraInfos ' ExtraInfos kontrolliert in die Metadaten übertragen Try SetString(.ApplicationName, md.ApplicationName) SetString(.CameraManufacturer, md.CameraManufacturer) SetString(.CameraModel, md.CameraModel) SetString(.Comment, md.Comment) SetString(.Copyright, md.Copyright) SetString(.Subject, md.Subject) SetString(.Title, md.Title) Catch ex As Exception .ErrorMessage &= _ StringOrEmpty("String: " & ex.Message & " ") End Try Try SetString(.DateTaken.ToString("G", _ New System.Globalization.CultureInfo("en-US")), md.DateTaken) Catch ex As Exception .ErrorMessage &= _ StringOrEmpty("Date: " & ex.Message & " ") End Try ' negative Werte sind nicht zulässig md.Rating = CInt(.Rating) ' Auflistungen kontrolliert übertragen If .Authors IsNot Nothing _ AndAlso .Authors.Count > 0 Then ReDim str(.Authors.Count - 1) For i As Integer = 0 To ExtraInfos.Authors.Count - 1 str(i) = String.Empty If md.Author IsNot Nothing Then If i < md.Author.Count Then str(i) = md.Author(i) End If SetString(.Authors(i), str(i)) Next i md.Author = New ReadOnlyCollection(Of String)(str) End If If .Keywords IsNot Nothing _ AndAlso .Keywords.Count > 0 Then ReDim str(.Keywords.Count - 1) For i As Integer = 0 To .Keywords.Count - 1 str(i) = "" If md.Keywords IsNot Nothing Then If i < md.Keywords.Count Then str(i) = md.Keywords(i) End If SetString(.Keywords(i), str(i)) Next i md.Keywords = New ReadOnlyCollection(Of String)(str) End If Try If .Thumbnail IsNot Nothing Then ' explizit vorgegebene Thumbnail thumb = BitMapToBitmapSource _ (CreateThumbnail(.Thumbnail)) ElseIf source.Frames(0).Thumbnail IsNot Nothing Then ' T. bereits in Bilddatei enthalten thumb = source.Frames(0).Thumbnail Else ' T. aus der Bilddatei erstellen thumb = BitMapToBitmapSource _ (CreateThumbnail(New Bitmap(filename))) End If Catch ex As Exception .ErrorMessage &= _ StringOrEmpty("Thumbnail: " & ex.Message & " ") End Try End With With source ' verlustfreie Übertragung des Input-Bildes ' unter Hinzufügung der Metadaten in den Output-Frame jpegenc.Frames.Add(BitmapFrame.Create _ (.Frames(0), thumb, md, .Frames(0).ColorContexts)) End With Try ' Ausgabe-Bilddatei schreiben Using savefile As New FileStream(savefilename, _ FileMode.Create, FileAccess.ReadWrite, FileShare.None) jpegenc.Save(savefile) End Using Catch ex As Exception ErrorMessage = ex.Message End Try End If End Using Catch ex As Exception ErrorMessage = ex.Message End Try Return (ErrorMessage = String.Empty) End Function ''' <summary>Abfrage der Extra-Infos einer Bilddatei</summary> ''' <param name="filename">Name der Bilddatei</param> ''' <param name="ExtraInfos">Struktur für die Extrainfos</param> ''' <param name="ErrorMessage">Fehlermeldung</param> ''' <returns>Alles OK?</returns> Public Function GetJPEGExtraInfos(ByVal filename As String, _ ByRef ExtraInfos As clsJPEGExtraInfos, _ Optional ByRef ErrorMessage As String = "") As Boolean Dim picstream As FileStream Dim jpDecoder As JpegBitmapDecoder Dim md As BitmapMetadata ' Rückgabe initialisieren ErrorMessage = String.Empty ExtraInfos.Clear() ' Initialisierung ' Bilddatei zur Weiterverarbeitung öffnen Try picstream = New FileStream(filename, _ FileMode.Open, FileAccess.Read, FileShare.None) Catch ex As Exception ErrorMessage = ex.Message : Return False End Try Try ' JPEG-Decoder für die geöffnete Bilddatei erstellen jpDecoder = New JpegBitmapDecoder _ (picstream, BitmapCreateOptions.PreservePixelFormat, _ System.Windows.Media.Imaging.BitmapCacheOption.Default) ' Rahmendaten abfragen md = CType(jpDecoder.Frames(0).Metadata, BitmapMetadata) Catch ex As Exception picstream.Close() ErrorMessage = ex.Message ExtraInfos.ErrorMessage &= _ StringOrEmpty("Decode: " & ex.Message & " ") Return False End Try ' Extra-Informationen in die Rückgabe-Struktur übertragen With ExtraInfos ' Kontrollierte Abfrage der String-Daten .ApplicationName = StringOrEmpty(md.ApplicationName) .CameraManufacturer = StringOrEmpty(md.CameraManufacturer) .CameraModel = StringOrEmpty(md.CameraModel) .Comment = StringOrEmpty(md.Comment) .Copyright = StringOrEmpty(md.Copyright) .Subject = StringOrEmpty(md.Subject) .Title = StringOrEmpty(md.Title) ' Feld mit Datumsangabe Try If Not String.IsNullOrEmpty(md.DateTaken) Then .DateTaken = CDate(md.DateTaken) Else .DateTaken = clsJPEGExtraInfos.DefaultDate End If Catch ex As Exception .DateTaken = clsJPEGExtraInfos.DefaultDate .ErrorMessage &= StringOrEmpty("Date: " & ex.Message & " ") End Try .Rating = CUInt(md.Rating) ' kontrollierte Abfrage der Listen (Author, Keywords) .Authors.Clear() If md.Author IsNot Nothing AndAlso md.Author.Count > 0 Then For i As Integer = 0 To md.Author.Count - 1 .Authors.Add(StringOrEmpty(md.Author(i))) Next i End If .Keywords.Clear() If md.Keywords IsNot Nothing AndAlso md.Keywords.Count > 0 Then For i As Integer = 0 To md.Keywords.Count - 1 .Keywords.Add(StringOrEmpty(md.Keywords(i))) Next i End If Try ' Abfrage des Thumbnail If jpDecoder.Frames(0).Thumbnail IsNot Nothing Then .Thumbnail = BitMapSourceToBitmap(jpDecoder.Frames(0).Thumbnail) Else .Thumbnail = Nothing End If Catch ex As Exception ExtraInfos.ErrorMessage &= _ StringOrEmpty("Thumbnail: " & ex.Message & " ") End Try End With picstream.Close() ErrorMessage = "" : Return True End Function ''' <summary>EXIF-Einträge in Bilddatei ermitteln</summary> ''' <param name="filename">Pfad zu einer Bilddatei</param> ''' <returns>Liste der Exif-Einträge</returns> Public Function ReadEXIF(ByVal filename As String) As List(Of String) Dim exif_list As New List(Of String) Try ' Bilddatei lesen Dim text As String = My.Computer.FileSystem.ReadAllText(filename) Const exif As String = "<exif:" Const comp As StringComparison = StringComparison.InvariantCultureIgnoreCase Dim pos, pos1, pos2 As Integer Dim key, value As String ' Suche nach exif-Kennungen pos = 0 While text.IndexOf(exif, pos, comp) >= 0 ' Startposition ermitteln pos = text.IndexOf(exif, pos, comp) ' Ende der Exif-Kennung: Start des Exif-Value pos1 = text.IndexOf(">", pos, comp) If pos1 - pos > exif.Length + 1 Then ' Ende des Exif-Value pos2 = text.IndexOf("<", pos1, comp) If pos2 - pos1 > 1 Then ' Kennung und Wert der Kennung lesen key = text.Substring _ (pos + exif.Length, pos1 - pos - exif.Length) value = text.Substring(pos1 + 1, pos2 - pos1 - 1) key = StringOrEmpty(key) : value = StringOrEmpty(value) If key <> String.Empty And value <> String.Empty Then ' nichtleere Exif-Angaben in Liste übertragen exif_list.Add(key & ": " & value) End If End If End If pos += exif.Length End While ' Rückgabe Return exif_list Catch Return Nothing End Try End Function #End Region #Region "Hilfsfunktionen (Strings, Bitmap-Konvertierung, Thumbnails)" Private Function StringOrEmpty(ByVal str As String) As String ' Hilfsfunktion: Nullstring filtern, Trimmen, ' max. Länge überwachen, NL-Ersetzung If str Is Nothing Then Return String.Empty str = str.Trim If str <> String.Empty Then str = str.Replace(Environment.NewLine, " ") End If Dim rlength As Integer If str.Length > cMaxStringLength Then rlength = str.Length - cMaxStringLength str = str.Substring(0, cMaxStringLength) & "...&" & CStr(rlength) End If ' Rückgabe Return str.Trim End Function Private Sub SetString(ByVal quelle As String, ByRef ziel As String) ' Hilfsfunktion: kontrolliertes Überschreiben des Zielstrings, ' falls ein nicht-leerer Quell-String gegeben worden ist ziel = StringOrEmpty(ziel) Dim q As String = StringOrEmpty(quelle) If q <> String.Empty Then ziel = q End Sub Private Function ComputePaddingAmount _ (ByVal Extrainfos As clsJPEGExtraInfos) As UInteger ' Hilfsfunktion: Abschätzung der Größe des zusätzlich ' benötigten Speichers für die Extrainfos Dim l As Long = 0 With Extrainfos l += StringOrEmpty(.ApplicationName).Length l += StringOrEmpty(.CameraManufacturer).Length l += StringOrEmpty(.CameraModel).Length l += StringOrEmpty(.Comment).Length l += StringOrEmpty(.Copyright).Length l += StringOrEmpty(.DateTaken.ToString).Length l += 4 ' Rating l += StringOrEmpty(.Subject).Length l += StringOrEmpty(.Title).Length If .Authors IsNot Nothing Then For i As Integer = 0 To .Authors.Count - 1 l += StringOrEmpty(.Authors(i)).Length Next i End If If .Keywords IsNot Nothing Then For i As Integer = 0 To .Keywords.Count - 1 l += StringOrEmpty(.Keywords(i)).Length Next i End If End With l = ((l + 1024) \ 1024) * 1024 Return CUInt(l) End Function Private Function BitMapSourceToBitmap(ByVal bs As BitmapSource) As Bitmap ' Hilfsfunktion: Umwandlung einer BitmapSource (Media.Imaging) ' in eine Bitmap (Drawing) Dim stride As Integer ' derzeit nur 24-Bit-Bilder (Standard bei JPEGs) If bs.Format.BitsPerPixel <> 24 Then Return Nothing ' Skalierung der BitmapSource (??) Dim tBS As BitmapSource = New TransformedBitmap _ (bs, New System.Windows.Media.ScaleTransform(1, 1)) With tBS stride = .PixelWidth * 3 While stride Mod 4 > 0 : stride += 1 : End While ' Bytearray mit den Bilddaten füllen Dim bytes(.PixelHeight * stride - 1) As Byte .CopyPixels(bytes, stride, 0) ' Bitmap in korrekter Größe erstellen Dim bmp As Bitmap = New Bitmap _ (.PixelWidth, .PixelHeight, Imaging.PixelFormat.Format24bppRgb) ' zur Sperre der gesamten Bitmap Dim bmp_rect As New Rectangle(0, 0, .PixelWidth, .PixelHeight) ' Bitmap sperren Dim bmp_data As Imaging.BitmapData = _ bmp.LockBits(bmp_rect, Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat) ' Bilddaten in die Bitmap übertragen Marshal.Copy(bytes, 0, bmp_data.Scan0, bytes.Length) ' Bitmap freigeben bmp.UnlockBits(bmp_data) ' Rückgabe Return bmp End With End Function Private Function BitMapToBitmapSource(ByVal Bmp As Bitmap) As BitmapSource ' Hilfsfunktion: Umwandlung einer Bitmap (Drawing) in eine ' BitmapSource (Media.Imaging) Dim hBitmap As IntPtr = Bmp.GetHbitmap() Return System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap _ (hBitmap, IntPtr.Zero, System.Windows.Int32Rect.Empty, _ BitmapSizeOptions.FromEmptyOptions()) End Function Private Function CreateThumbnail(ByVal bmp As Bitmap) As Bitmap ' Hilfsfunktion: Zu einer Bitmap wird ein Thumbnail erstellt If bmp Is Nothing Then Return Nothing Return CType(bmp.GetThumbnailImage(cThumbnailHeight, _ CInt(cThumbnailHeight * bmp.Height / bmp.Width), Nothing, Nothing), Bitmap) End Function #End Region End Module |