Vorlesung Informatik 2 - Teil A: Java Kurs

6.6 Bild-Dateien lesen

Neben Texten und Sound sind Bilder als Dateiformate für uns interessant.

Für das Lesen und Schreiben von Bilddateien gibt es eine ganze Reihe von Möglichkeiten:

  • Die Klasse javax.swing.ImageIcon: gedacht für kleine Icons in der Navigation, kann aber auch zum einfachen Lesen von Bildern im JPEG, PNG oder GIF Format verwendet werden.
  • Die Klasse Toolkit bietet eine Methode createImage zum Lesen eines Bildes aus einer Datei.
  • Im Paket javax.imageio gibt es Klassen zum Lesen und Schreiben von Bildern, die erheblich mehr Möglichkeiten bieten als ImageIcon und Toolkit.createImage.
Wir beschränken uns zunächst auf die ImageIcon Klasse. 

Wir erzeugen im Projekt unter dem Verzeichnis src das neue Unterverzeichnis bilder und können von dort ein Bild mit den folgenden Aufrufen erzeugen:

ImageIcon icon = new ImageIcon("/bilder/test.jpg");
Image bild = icon.getImage();

Das Objekt bild vom Type java.awt.Image können wir jetzt z.B. auf einem Graphics2D Objekt darstellen, dazu später.

Es ist aber aus mehreren Gründen vorteilhaft, einen kleinen Umweg über eine URL Objekt zu gehen:
  • Der ImageIcon Konstruktor fängt alle Fehler intern ab, wir bekommen also z.B. nicht mit, wenn die Datei nicht existiert.
  • Wenn wir die Anwendung in eine ausführbare .jar-Datei packen, wird die Bilddatei nicht mehr gefunden.

Deshalb erzeugen wir zunächst ein URL Objektl:

        URL url = getClass().getResource("/bilder/test.jpg");
if(url==null) {
System.out.println("FEHLER: Bild nicht gefunden");
}else {
ImageIcon bildIcon = new ImageIcon(url);
bild = bildIcon.getImage();
}

Das Image Objekt kann jetzt auf einer grafische Fläche mit der Methode drawImage gezeichnet werden 

public void zeichne(Graphics2D g){     
       g.drawImage(bild, 0, 0, this);

Der beiden int-Parameter von drawImage sind die Position der linken oberen Ecke des Bildes, der letzte Parameter ist der sogenannte ImageObserver. Die von Component abgeleiteten Swing-Klassen implementieren dieses Interface, deshalb ist this fast immer richtig. Der ImageObserver wird benachrichtigt, wenn das Bild fertig geladen wurde, er ermöglicht das asynchrone Laden von sehr großen Bild-Dateien. 

Eine vollständige Anwendung zur Darstellung eines Bildes sieht dann so aus:

public class BildLesen extends StandardAnwendung {
public static void main(String[] args) {
starteAnwendung();
}
private Image bild;
public BildLesen() {
super("Bild", 800, 600);
URL url = getClass().getResource("/bilder/test.jpg");
if(url==null) {
JOptionPane.showMessageDialog(this, "Bild nicht gefunden", "FEHLER", JOptionPane.ERROR_MESSAGE);
}else {
ImageIcon bildIcon = new ImageIcon(url);
bild = bildIcon.getImage();
}
}
@Override
public void zeichne(Graphics2D g) {
g.drawImage(bild, 0, 0, this);
}
}
@Override
public void zeichne(Graphics2D g) {
float bildBreite = bild.getWidth(null);
float bildHoehe = bild.getHeight(null);
float svBild = bildBreite/bildHoehe;

float panelBreite = this.getWidth();
float panelHoehe = this.getHeight();
float svPanel = panelBreite/panelHoehe;

float b = panelBreite, h=panelHoehe;
if(svBild>svPanel) h = bildHoehe*panelBreite/bildBreite;
else         b = bildBreite*panelHoehe/bildHoehe;
g.drawImage(bild, 0,0, (int)(b+0.5), (int)(h+0.5), this);
}

Lehrvideo (YouTube)