Bauen mit Microsoft - Fotos verwalten

Digitale Fotografie hat in den letzten Jahren einen unwahrscheinlichen Aufschwung erlebt. Kein Wunder, bekommt man doch die Ergebnisse praktisch sofort zu Gesicht. Und billiger ist es auf die Dauer auch noch, bildet man sich zumindest ein.

Digitale Bilder kann man sehr schön auf einem Computermonitor betrachten. Der etwas ambitioniertere Hobby-Fotograf jedoch steht auf Begriffe wie Blende und Belichtungszeit, ISOWert und Brennweite. Diese Informationen sind wichtig zur Bewertung der Schärfentiefe, aber auch, um reproduzierbare Ergebnisse in ähnlichen Situationen zu erhalten. Dass diese Informationen zusammen mit den Bildinformationen in der Datei stehen, hat sicher jeder der oben genannten Zielpersonen schon gehört. Aber wie kommt man an die Daten heran?

Ganz einfach: mit einer kostenlosen Version von Visual Basic 2005 Express und etwas Wissen um die internen Strukturen dieser Metadaten.

Sicherlich hat fast jeder schon mal ein VBA-Makro gesehen oder gar selbst programmiert. Visual Basic .NET ist da sehr ähnlich. Etwas strikter zwar, aber dafür können wir das Geschriebene später auch noch lesen. Sicherlich gibt es schon Tools, die die EXIF-Daten auslesen können. Aber seien wir doch mal ehrlich: ein selbstgeschriebenes Program ist doch cool, oder?

Schritt 1: Projekt anlegen

Nach der Installation von Visual Basic 2005 Express legen wir einfach ein neues Windows-Projekt an und nennen es FotoInfo- Viewer. Im Projektmappen-Explorer klicken wir doppelt auf Form1.vb und dann einfach nochmals doppelt direkt auf das Formular. Damit kommen wir in den Code-Bereich und schreiben im Form1_Load Event Folgendes, um die Titelzeile anzuzeigen:

Me.Text = "FotoInfoViewer"

Klicken Sie auf die Abbildung um den Code zu erhalten!

Jetzt gehen wir zurück auf den Reiter "Form1_vb [Entwurf]" und ziehen ein OpenFileDialog-Steuerelement aus der Toolbox (Kategorie: Dialogfelder) auf das Formular. Desweiteren einen Button (Name: btnNeu), eine PictureBox (Name: picFoto) und 7 mal jeweils ein Label und eine Textbox, die wir wie im Bild zu sehen anordnen:

OpenFileDialog-Steuerelement, Button, PictureBox, 7 Label und eine Textbox auf dem Formular

Klicken Sie auf die Abbildung um den Code zu erhalten!

Bei den Labels setzen wir die Text-Eigenschaft, bei den Textboxen die Name-Eigenschaft über das Eigenschaften-Fenster auf folgende Werte:

Text-Eigenschaft

Schritt 2: Code

Jetzt kommen wir zum eigentlichen Herzen des Programms, dem Code. Dazu klicken wir doppelt auf den Button und befinden uns nun im entsprechenden Click-Event. Dieser Code läuft ab, wenn wir während der Programmausführung auf den Button klicken. Hier verdrahten wir den OpenFileDialog, so dass wir die ausgewählte Datei verwenden können.

With OpenFileDialog1
  .FileName = ""
  .Filter = "JPEG-Dateien|*.jpg|Alle Dateien|*.*"
  If .ShowDialog() = Windows.Forms.DialogResult.OK Then
    HoleExifInfos(.FileName)
  End If
End With

Klicken Sie auf die Abbildung um den Code zu erhalten!

Dazu schreiben wir gleich noch die Prozedur, welche die EXIFDaten in die entsprechenden Textboxen schreibt:

Private Sub HoleExifInfos(ByVal fName As String)
  picFoto.Image = Image.FromFile(fName)
  tbDateiname.Text = fName
  Dim InfoStruct As EXIFDataStruct = _
    EXIFData.GetEXIFData(Image.FromFile(fName))
  With InfoStruct
    tbKamera.Text = .Kameramodell
    tbAuflöung.Text = .Auflösung
    tbBlende.Text = .Blende
    tbBelichtungszeit.Text = .Belichtungszeit
    tbISO.Text = .ISO
    tbBrennweite.Text = .Brennweite
  End With
End Sub

Klicken Sie auf die Abbildung um den Code zu erhalten!

Imports
System.Drawing.Imaging
Imports System.BitConverter

Public Structure EXIFDataStruct
  Public Kameramodell As String
  Public Belichtungszeit As String
  Public Blende As String
  Public ISO As String
  Public Brennweite As String
  Public Auflösung As String
End Structure

Public Class EXIFData

Private Enum EXIFPropertyName As Integer
  Kameramodell = 272
  Belichtungszeit = 33434
  Blende = 33437
  ISO = 34855
  Brennweite = 37386
  XAuflösung = 40962
  YAuflösung = 40963
End Enum

Public Shared Function GetEXIFData(ByRef img As Image) As EXIFDataStruct

  Dim exifResult As EXIFDataStruct = Nothing
  SetDefaults(exifResult)
  Dim props() As PropertyItem = img.PropertyItems

  For Each propItem As PropertyItem In props
    Select Case propItem.Id
      Case EXIFPropertyName.Kameramodell
        exifResult.Kameramodell = _
          System.Text.Encoding.ASCII.GetString(propItem.Value)
          
      Case EXIFPropertyName.Belichtungszeit
        Dim iFirstPart As UInt32 = ToUInt32(propItem.Value, 0)
        Dim iSecondPart As UInt32 = ToUInt32(propItem.Value, 4)
        If (iFirstPart = iSecondPart) Then
          exifResult.Belichtungszeit = _
            iSecondPart.ToString("0") + " sec"
          Else
            exifResult.Belichtungszeit = _
              iFirstPart.ToString("0") + "/" + _
              iSecondPart.ToString("0") + " sec"
          End If

Case EXIFPropertyName.Blende
  Dim fNumber As Single = ToSingle(propItem.Value, 0) / _
  ToSingle(propItem.Value, 4)
  exifResult.Blende = "F " + fNumber.ToString("0.0")

  Case EXIFPropertyName.ISO
    exifResult.ISO = ToUInt16(propItem.Value, 0).ToString()

  Case EXIFPropertyName.Brennweite
    Dim focLen As UInt16 = ToUInt16(propItem.Value, 0)
    exifResult.Brennweite = focLen.ToString() + " mm"

Klicken Sie auf die Abbildung um den Code zu erhalten!

    Case EXIFPropertyName.XAuflösung
      exifResult.Auflösung = ToInt16(propItem.Value, 0).ToString

    Case EXIFPropertyName.YAuflösung
      exifResult.Auflösung += " x " + ToInt16(propItem.Value, 0).ToString
      
    End Select
  Next
  Return exifResult

  End Function

  Private Shared Sub SetDefaults(ByRef resEXIF As EXIFDataStruct)
    With resEXIF
      .Kameramodell = "n/a"
      .Belichtungszeit = "n/a"
      .Blende = "n/a"
      .ISO = "n/a"
      .Brennweite = "n/a"
      .Auflösung = "n/a"
    End With
  End Sub
End Class

Klicken Sie auf die Abbildung um den Code zu erhalten!

Nun brauchen wir allerdings noch das Wichtigste, den Code für das Ermitteln der Informationen. Dazu erzeugen wir uns eine neue Klasse durch Rechtsklick auf FotoInfoViewer im Projektmappen-Explorer.

Klasse durch Rechtsklick auf FotoInfoViewer im Projektmappen-Explorer erzeugen

Diese Klasse benennen wir EXIFData. Der Code dazu schaut folgendermaßen aus:

Die Prozedur SetDefaults bzw. Funktion GetEXIFData in der Klasse EXIFData wurden als Shared deklariert, damit wir keine Instanz der Klasse erzeugen müssen, um diese verwenden zu können. Die EXIF-Daten, die wir haben wollen, sind Metadaten innerhalb der Bilddatei. Sie stecken in so genannten PropertyItems, die von System.Drawing.Imaging bereitgestellt werden. Über die folgende Zeile im oben genannten Code, holen wir uns alle PropertyItems und schreiben sie in ein Array:

Dim props() As PropertyItem = img.PropertyItems

Klicken Sie auf die Abbildung um den Code zu erhalten!

Über die nachfolgende "For Each"-Schleife durchlaufen wir die Metadaten und schauen dabei aber nur nach bestimmten Properties, die wir vorher über die Enum EXIFPropertyName festgelegt haben. Es folgen ein paar Konvertierungen in die richtigen Datenformate und wir haben was wir wollten. Die Helper-Prozedur SetDefaults existiert nur, um Standardwerte zu setzen, für den Fall, dass keine entsprechenden Metadaten vorhanden sind, d.h. dass das Bild beispielsweise nicht aus einer Digitalkamera kommt. Die Ergebnisse werden zum Schluss auf die öffentliche Struktur EXIFDataStruct geschrieben, auf die wir dann aus dem Formular heraus (in HoleExifInfos) zugreifen können. Und so sieht er dann in Aktion aus, unser Viewer für EXIF-Daten:

Der FotoInfoViewer

Anmerkung: Aus Gründen der Übersichtlichkeit wurde in diesem Beispiel bewusst auf Fehlerbehandlung (Exception Handling) verzichtet.