Pixelgröße einer Grafikdatei ermitteln

Veröffentlicht: 22. Feb 2004 | Aktualisiert: 29. Jun 2004

Von Mathias Schiffer

Die Microsoft Newsgroups sind eine Quelle schier unerschöpflichen Wissens, das nahezu auf Knopfdruck abrufbar ist: Hunderte deutschsprachige Entwickler vom Einsteiger bis zum Profi treffen sich hier täglich virtuell, um Fragen zu stellen oder zu beantworten. Auch themennahe Probleme, Ansichten und Konzepte werden miteinander diskutiert. Sie kennen die Microsoft Newsgroups noch nicht? Detaillierte Information für Ihre Teilnahme finden Sie auf der Homepage der Microsoft Support Newsgroups.

Diese Kolumne greift regelmäßig ein besonders interessantes oder häufig nachgefragtes Thema aus einer der Entwickler-Newsgroups auf und arbeitet es aus.

Aus der Visual Basic Newsgroup microsoft.public.de.vb:

Ich möchte mit Visual Basic 6 ermitteln, welche Pixelgröße ein Bild hat. Das Bild liegt dabei als Grafikdatei (*.bmp, *.gif oder *.jpg) vor. Wie gehe ich am geschicktesten vor?

Die einfachste Variante, dieses Problem zu lösen, ist offensichtlich: Da Visual Basic die Möglichkeit anbietet, u.a. Bitmap-, GIF-, und JPEG-Grafikdateien als Bilder zu laden, können Sie einfach die LoadPicture-Funktion verwenden. Hierfür benötigen Sie nicht einmal eine Form mit einem PictureBox-Steuerelement. Sie können die Grafik auch in ein StdPicture-Objekt laden. Dieses bietet die Eigenschaften Width und Height, welche die gesuchten Kennzeichen enthalten. Zu beachten ist dabei, dass diese Eigenschaften mit der eher seltenen Skala vbHimetric arbeiten. Um diese Skala in Pixel umzurechnen, können Sie einfach die ScaleX-/ScaleY-Funktionen etwa einer Form verwenden.

' Ein StdPicture-Objekt zur Verfügung stellen... 
Dim MyPic As StdPicture 
  ' ... und mit einem Bild belegen 
  Set MyPic = LoadPicture("javascript:void(null);") 
  ' Umrechnung aus der Skala vbHimetric in die 
  ' Skala Pixel mit Hilfe von ScaleX/Y einer Form: 
  Debug.Print "Breite des Bildes in Pixeln:" 
  Debug.Print CLng(Form1.ScaleX(MyPic.Width, vbHimetric, vbPixels)) 
  Debug.Print "Höhe des Bildes in Pixeln:" 
  Debug.Print CLng(Form1.ScaleY(MyPic.Height, vbHimetric, vbPixels))

Natürlich hat dieses Vorgehen Nachteile, wenn sehr viele oder sehr große Bilder ausgewertet werden sollen: Das Laden der gesamten Datei vom Datenträger in den Speicher nimmt seine Zeit in Anspruch.

Header-Informationen auslesen
Eigentlich sind wir ja am Bild selber gar nicht interessiert. All die umfangreiche Information darüber, welcher Punkt an welcher Stelle welche Farbe haben soll, ist für unser Anliegen unbedeutend. Schön wäre es also, nur einen kleinen Teil der Dateien auslesen zu müssen.

Dafür wäre es notwendig, dass die Grafikdatei nicht nur die Bildinformation selber trägt, sondern auch zusätzliche Daten liefert. Tatsächlich ist das bei den üblichen Bildformaten auch der Fall. Wir müssen nur noch jeweils die entsprechenden Spezifikationen der einzelnen Bildformate berücksichtigen. Für die drei erwähnten Bildformate BMP, JPG und GIF folgen daher drei konzeptionell identische, im Detail aber unterschiedliche Lösungswege.

BMP-Dateien / Windows Bitmap-Grafiken
Erfreulich einfach gestaltet sich dieses Unterfangen bei Bitmap-Dateien: Ihr Aufbau ist so gut dokumentiert, dass sogar vordefinierte API-Strukturen für deren Auslesen zur Verfügung stehen: Die ersten Bytes einer BMP-Datei lassen sich so in eine BITMAPFILEHEADER- und eine unmittelbar folgende BITMAPINFOHEADER-Struktur lesen. Als zweites und drittes Element der BITMAPINFOHEADER-Struktur finden sich die von uns gesuchten Informationen über die Breite und Höhe der in der Datei abgelegten Grafik.

' Deklarationen für BMP-Dateien: 
Private Type BITMAPFILEHEADER ' 14 Bytes 
  bfType As Integer 
  bfSize As Long 
  bfReserved1 As Integer 
  bfReserved2 As Integer 
  bfOffBits As Long 
End Type 
Private Type BITMAPINFOHEADER ' 40 Bytes 
   biSize As Long 
   biWidth As Long  ' Breite der Grafik 
   biHeight As Long ' Höhe der Grafik 
   biPlanes As Integer 
   biBitCount As Integer 
   biCompression As Long 
   biSizeImage As Long 
   biXPelsPerMeter As Long 
   biYPelsPerMeter As Long 
   biClrUsed As Long 
   biClrImportant As Long 
End Type 
' Code-Lösungsansatz für BMP-Dateien: 
Dim ff As Integer 
Dim BMPFile As BITMAPFILEHEADER 
Dim BMPInfo As BITMAPINFOHEADER 
  ' Binäres Öffnen und teilweises Auslesen einer BMP-Datei 
  ff = FreeFile() 
  Open "test.bmp" For Binary Access Read As #ff 
 Get #ff, , BMPFile  ' Interessiert uns nicht 
 Get #ff, , BMPInfo  ' Hier finden wir die Information! 
  Close #ff 
  ' Anzeige der ermittelten Information: 
  MsgBox "Die Grafik in test.bmp ist " & vbNewLine & _ 
   CStr(BMPInfo.biWidth) & " Pixel breit und " & vbNewLine & _ 
   CStr(BMPInfo.biHeight) & " Pixel hoch.", _ 
   vbInformation, "BMP-Analyse"

Lohnendes Ergebnis: Statt im Einzelfall beliebig große Dateien einlesen zu müssen, reichen hier bereits die ersten 58 Bytes.

Noch schneller geht's, wenn Sie ausschließlich die benötigten Informationen direkt von den entsprechenden Byte-Positionen der Datei auslesen. So ersparen Sie sich weiteres Auslesen von Daten, die nicht benötigt werden:

Dim ff As Integer 
Dim BMPWidth As Long 
Dim BMPHeight As Long 
  ' Binäres Öffnen und exakt passendes Auslesen einer BMP-Datei 
  ff = FreeFile() 
  Open "javascript:void(null);" For Binary Access Read As #ff 
 Get #ff, 19, BMPWidth 
 Get #ff, 23, BMPHeight 
  Close #ff 
  ' Anzeige der ermittelten Information: 
  MsgBox "Die Grafik in test.bmp ist " & vbNewLine & _ 
   CStr(BMPWidth) & " Pixel breit und " & vbNewLine & _ 
   CStr(BMPHeight) & " Pixel hoch.", _ 
   vbInformation, "BMP-Analyse"

JPG-Dateien / JPEG-Grafiken
Etwas komplizierter als bei den Bitmaps ist der Aufbau von JPEG-Dateien. Doch auch hierzu findet sich ein analoger Lösungsweg. Das folgende Codebeispiel ist eng an einen Ansatz angelehnt, den Thomas Füssl in den Microsoft Newsgroups der Öffentlichkeit zur Verfügung gestellt hat:

Dim strDummy As String 
Dim ff As Integer 
Dim c As Integer 
Dim S As String 
Dim L As Long 
Dim JPGWidth As Long 
Dim JPGHeight As Long 
  ff = FreeFile() 
  Open "test.jpg" For Binary Access Read As #ff 
  ' Test auf JPEG-Datei 
  If Input(2, #ff) <> (Chr$(&HFF) & Chr$(&HD8)) Then 
 Close #ff 
 Exit Sub 
  End If 
  strDummy = Input(2, #ff) 
  Do 
 L = Asc(Input(1, #ff)) 
 L = L * 256 + Asc(Input(1, #ff)) 
 S = Input(L - 2, #ff) 
 If c = &HC0 Or c = &HC2 Then 
   JPGWidth = Asc(Mid$(S, 4, 1)) 
   JPGWidth = JPGWidth * 256 + Asc(Mid$(S, 5, 1)) 
   JPGHeight = Asc(Mid$(S, 2, 1)) 
   JPGHeight = JPGHeight * 256 + Asc(Mid$(S, 3, 1)) 
 End If 
 If Input(1, #ff) <> Chr$(255) Then 
   Exit Do 
 End If 
 c = Asc(Input(1, #ff)) 
  Loop While c <> &HD9 
  Close #ff 
  ' Anzeige der ermittelten Information: 
  MsgBox "Die Grafik in test.jpg ist " & vbNewLine & _ 
   CStr(JPGWidth) & " Pixel breit und " & vbNewLine & _ 
   CStr(JPGHeight) & " Pixel hoch.", _ 
   vbInformation, "JPG-Analyse"

GIF-Dateien / Graphics Interchange Format-Grafiken
Aus unserer ursprünglichen Aufzählung fehlen nur noch die GIF-Dateien bzw. -Grafiken. In diesen Dateien finden sich die gesuchten Angaben unmittelbar nach einem 6 Byte langen Versionsheader an den Byte-Positionen 7-8 (Breite) und 9-10 (Höhe).

Entsprechend einfach können wir analog zum Bitmap-Vorgehen die Informationen ermitteln:

Dim ff As Integer 
Dim GIFWidth As Integer 
Dim GIFHeight As Integer 
  ' Binäres Öffnen und exakt passendes Auslesen einer BMP-Datei 
  ff = FreeFile() 
  Open "test.gif" For Binary Access Read As #ff 
 Get #ff, 7, GIFWidth 
 Get #ff, 9, GIFHeight 
  Close #ff 
  ' Anzeige der ermittelten Information: 
  MsgBox "Die Grafik in test.gif ist " & vbNewLine & _ 
   CStr(GIFWidth) & " Pixel breit und " & vbNewLine & _ 
   CStr(GIFHeight) & " Pixel hoch.", _ 
   vbInformation, "GIF-Analyse"

Andere Formate
Mit dem gleichen Konzept können Sie auch andere Grafikformate auswerten, ohne die gespeicherten Grafiken komplett laden zu müssen. Natürlich ist hierfür eine Kenntnis des jeweiligen Dateiformats unumgänglich. Eine sehr umfassende Sammlung aller möglichen Dateiformate, darunter auch für Grafikdateien, finden Sie auf den Webseiten von WotsIt.org.