Vorlesung Informatik 2 - Teil A: Java Kurs
8.1 Die Klassen BuferedImage und ImageIO
Bilder entstehen durch unterschiedliche Prozesse:
- Bildgebende Verfahren:
Kameras, optische Scanner, Röntgengeräte, Tomografen, Resonanz-Verfahren wie Kernspinresonanz, Lidar Scanner, elektrische Impedanz (Impedanz-Tomografie) , Radargeräte, Sonar, Mikrowellen Radiometer zur Feuchtigkeitsmessung, Spektrometer, ...
Besonders in der Astronomie und der Erdbeobachtung werden ausgefallene Verfahren eingesetzt, um Bilder zu erzeugen. Ein exotisches modernes Verfahren zur Durchleuchtung von Gestein ist die Myonen-Tomografie, bei der die kosmische Strahlung genutzt wird um architektonische Strukturen zu durchleuchten. Sie wurde unter anderem zur Untersuchung der Cheops-Pyramide und der havarierten Reaktoren in Fukushima eingesetzt oder um die Magma-Kammer von Vulkanen zu untersuchen. - Synthetische Bilder:
- Mit Unterstützung von Software wie Illustrator, Maya, MAx3D, Paintbrush, Leonardo, ...
- Algorithmisch erzeugte Bilder, wie z.B. algorithmische Kunst, Darstellung mathematischer Funktionen, Graphen von Oszilloskopen und anderen Messgeräten, Aufzeichnungen von Seismographen, Barographen u.s.w. oder grafische Darstellungen zur Visualisierung von Daten.
- Vektorgrafiken: die geometrischen Elemente (Geraden, Rechtecke, Kurven, Kreise) in den Bildern sind parametrisch gespeichert. Dadurch sind sie beliebig ohne Qualitätsverlust skalierbar. Typische Dateiformate für Vektorgrafiken sind SVG (Scalable Vector Graphic) PS (Postscript) und EPS sowie AI (Adobe Illustrator).
- Pixelgrafiken: bestehen aus einem rechteckigen Raster von Bildpunkten (Pixeln). Für jedes Pixel wird die Farb- oder Helligkeitsinformation gespeichert. Typische Dateiformate sind RAW, GIF, PNG, JPEG, JPEG2000, PSD, TIF oder BMP.
Ein weiterer Aspekt, auf den hier nicht eingegangen wird, ist die Darstellung von Bildern z.B. durch Druckverfahren, Projektion, Bildschirm oder VR-Brille.
Wir werden in Java mit Pixelgrafiken arbeiten, dabei verwenden wir die Klasse BufferedImage, die von der Klasse Image abgeleitet ist, die wir schon kurz kennengelernt haben. Während ein Image Objekt im Wesentlichen nur dargestellt werden kann, bietet ein BufferedImage die Möglichkeit, an alle Informationen im Bild heranzukommen bzw. sie zu manipulieren.
Ein BufferedImage enthält neben allgemeinen Informationen wie Breite und Höhe zwei Eigenschaften:
- Das Farbmodell, ein Objekt vom Typ java.awt.image.ColorModel.
- das Pixel-Raster, ein Objekt vom Typ java.awt.image.Raster.
Um ein BufferedImage zu lesen verwenden wir die Methode read der Klasse ImageIO. Die Bild-Datei kann dabei entweder über ein URL oder ein File- Objekt adressiert werden. Beispiel:
BufferedImage bild;
URL url = getClass().getResource("/bilder/bild.jpg");
if(url==null) {
JOptionPane.showMessageDialog(this, "Bild nicht gefunden", "FEHLER", JOptionPane.ERROR_MESSAGE);
}else {
try {
bild = ImageIO.read(url);
System.out.println(bild.getColorModel());
} catch (IOException e) {
JOptionPane.showMessageDialog(this, "Fehler beim Lesen des Bildes", e.getMessage(), JOptionPane.ERROR_MESSAGE);
}
}
Der Zugriff über eine URL ist vorteilhaft, wenn die Bilddatei Teil des Projekts ist, denn sie wird auch dann gefunden, wenn die Anwendung in eine Jar-Datei gepackt wird.
File datei = new File("/bilder/bild.jpg");
if(datei.exists() && datei.isFile()) {
try {
bild = ImageIO.read(datei);
} catch (IOException e) {
JOptionPane.showMessageDialog(this, "Fehler beim Lesen des Bildes", e.getMessage(), JOptionPane.ERROR_MESSAGE);
e.printStackTrace();
}
}else {
JOptionPane.showMessageDialog(this, "Bild nicht gefunden", "FEHLER", JOptionPane.ERROR_MESSAGE);
}
Da BufferedImage von Image abgeleitet ist, kann es wie ein Image Objekt auf einer Graphics2D Fläche dargestellt werden.
Mit ImageIO können wir ein BufferedImage auch wieder auf die Festplatte schreiben:
try{
ImageIO.write(bild,"JPEG","D:/test.jpg");
}catch(IOException e){
e.printStackTrace();
}
Von Haus aus unterstützt Java die Formate JPEG, BMP, PNG, GIF und TIFF, im Netz gibt es Bibliotheken für weitere Formate.
Die Liste der unterstützen Format-Namen findet man mit ImageIO.getReaderFormatNames():String[] und getWriterFormatNames():String[]:
for(String fmt:ImageIO.getReaderFormatNames()) System.out.println(fmt);
Die wichtigsten Methoden von BufferedImage im Überblick:
getWidth(), getHeight() : int - Größe in Pixeln
getType(): int - z.B. TYPE_RGB, TYPE_ARGB, TYPE_GRAY, ...
getGraphics(): Graphics - liefert aber ein Graphics2D Objekt
createGraphics(): Graphics2D - liefert Grafischen Kontext, mit dem man auf das Bild zeichnen kann.
getColorModel(): ColorModel() - liefert das Farbmodell
getData(), getData(ausschnitt: Rectangle) : Raster - liefert Pixel-Matrix mit Lesezugriff, komplett oder einen Ausschnitt
getRaster(), getAlphaRaster() : WritableRaster - liefert die Pixel-Matrix mit Schreibzugriff
getRGB(x,y): int, setRGB(r,g,b:int): void - liest/schreibt das Pixel (x,y)
getSubimage(x, y, width, height: int): BufferdImage - liefert einen Bildausschnitt getScaledImage(width, height, hint): Image - liefert eine skalierte Version wobei hint z.B. BufferedImage. SCALE_DEFAULT oder SCALE_SMOOTH ist
Der für uns wichtige Konstruktor ist:
BufferedImage(width, height, imageType: int)
wobei wir als imageType entweder BufferedImage.TYPE_RGB oder BufferedImage.TYPE_ARGB verwenden,der Unterschied wird im nächsten Kapitel behandelt.
Um also ein synthetisches Bild zu erzeugen schreiben wir:
try{ BufferedImage bild2 = new BufferedImage(600,600,BufferedImage.TYPE_INT_RGB);
Graphics2D g = bild2.createGraphics();
g.setColor(Color.RED);
g.fillRect(100, 100, 100, 100);
ImageIO.write(bild2,"PNG",new File("D:/bild04.png")); catch(IOException e){ ...
Im nächsten Kapitel behandeln wir noch die Begriffe Alpha-Kanal und Compositing an, die eine wichtiges Basiswissen für viele Arbeiten in der Computergrafik bzw. im Fernsehstudio oder am Filmset sind.