Bilder skalieren: Unterschied zwischen den Versionen

Aus Byte-Welt Wiki
Zur Navigation springenZur Suche springen
K
 
(18 dazwischenliegende Versionen von 4 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
Nicht fertig!
+
=Bilder skalieren=
  
Ich habe mal einen Beitrag von Illuvatar zum Grunde genommen, um hier dieses Thema zu eröffnen.
+
Einen ausführlichen Artikel zum Thema 'Bilder skalieren' gibt es unter [https://web.archive.org/web/20070515094604/https://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html The Perils of getScaledInstance]. Die wichtigsten Punkte sind hier kurz zusammengefasst.
  
getScaledImage ist recht unperformant und sollte nicht verwendet werden.<br/>
+
Bim Skalieren von Bildern gibt es im wesentlichen zwei mögliche Ziele: Man will das Bild entweder ''skaliert zeichnen'', oder man will eine ''skalierte Instanz'' eines Bildes erstellen. In beiden Fällen kann man noch unterschiedliche Schwerpunkte setzen. So kann im einen Fall die Performance (also die Zeichengeschwindigkeit) besonders wichtig sein, und im anderen Fall die Bildqualität.
Statt dessen schlug Illu vor folgenden Code zu verwenden:<br/>
+
 
<code=java>BufferedImage bild = ImageIO.read(new File(loadF,en.nextElement()));  
+
== Bilder skaliert zeichnen ==
BufferedImage scaled = new BufferedImage(newwidth, newheight, bild.getType());  
+
 
Graphics2D g2d= scaled.createGraphics();  
+
Wenn man ein Bild skaliert zeichnen will, kann man das am einfachsten direkt mit der geeigneten [[Methode]] <code>drawImage</code> aus der Klasse <code>Graphics</code>. Von dieser Methode gibt es verschiedene Varianten, und unter anderem eine, mit der man direkt sagen kann, wie groß das Bild gezeichnet werden soll:
g2d.drawImage(bild, 0, 0, newwidth, newheight, null);  
+
<syntaxhighlight lang="java">
g2d.dispose();</code>
+
public boolean drawImage(Image image, int x, int y, int width, int height, ImageObserver observer)
 +
</syntaxhighlight>
 +
Um ein Bild in einer Größe von 400x300 Bildpunkten zu zeichnen, verwendet man also
 +
<syntaxhighlight lang="java">
 +
graphics.drawImage(image, 0, 0, 400, 300, null);
 +
</syntaxhighlight>
 +
 
 +
 
 +
== Skalierte Instanzen erstellen ==
 +
 
 +
Um eine skalierte Instanz eines Bildes zu erstellen, kann man einfach das vorhandene Bild in ein Bild der gewünschten Größe hineinzeichnen:
 +
<syntaxhighlight lang="java">
 +
BufferedImage originalImage = ImageIO.read(new File("image.png"));
 +
BufferedImage scaledImage = new BufferedImage(400, 300, BufferedImage.TYPE_INT_ARGB);
 +
Graphics g = scaledImage.createGraphics();
 +
g.drawImage(originalImage, 0, 0, 400, 300, null);
 +
g.dispose();
 +
</syntaxhighlight>
 +
Wie man sieht wird hierbei die gleiche Methode <code>drawImage</code> aus der [[Klasse]] {{JAPI|Graphics}} verwendet, wie beim skalierten Zeichnen. Allerdings wird das Bild hier nicht auf den [[Bildschirm]], sondern in ein anderes Bild hinein gezeichnet.
 +
 
 +
 
 +
== RenderingHints: Qualität oder Geschwindigkeit? ==
 +
 
 +
Sowohl beim skalierten Zeichnen als auch beim erstellen skalierter [[Instanz|Instanzen]] kann man durch das Setzen von ''Rendering Hints'' noch festlegen, ob eher in höherer Qualität oder eher in höherer Geschwindigkeit gezeichnet werden soll. Diese ''Rendering Hints'' setzt man in dem <code>Graphics2D</code>-Objekt, das man zum Zeichnen verwendet. Dabei ist egal, ob man direkt auf den Bildschirm oder in ein anderes Bild hinein zeichnet.
 +
 
 +
Zum Beispiel wird hier gesagt, dass ''bilineare Interpolation'' verwendet werden soll, was zwar etwas langsamer ist, aber für höhere Bildqualität sorgt:
 +
<syntaxhighlight lang="java">
 +
Graphics2D g = (Graphics2D)graphics;
 +
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
 +
                  RenderingHints.VALUE_INTERPOLATION_BILINEAR);
 +
g.drawImage(image, 0, 0, 400, 300, null);
 +
</syntaxhighlight>
 +
Hätte man statt <code>VALUE_INTERPOLATION_BILINEAR</code> den Wert <code>VALUE_INTERPOLATION_NEAREST_NEIGHBOR</code> angegeben, wäre die Bildqualität geringer, aber das Zeichnen etwas schneller.
 +
 
 +
 
 +
== Warum nicht getScaledInstance? ==
 +
 
 +
Oft werden mit der Methode {JAPI|Image#getScaledInstance}} skalierte Instanzen von Bildern erstellt und gezeichnet - im schlimmsten Fall sogar bei jedem Zeichenvorgang erneut. Diese [[Methode]] ist oft weder in Bezug auf Bildqualität noch in Bezug auf die Performance die geeignetste Lösung. Die Methoden aus der [[Klasse]] {{JAPI|Graphics2D}} und die {{JAPI|RenderingHints}} bieten mehr Möglichkeiten, die für das jeweilige Ziel beste Skalierungs-Art zu wählen. Zusätzlich können die skalierten [[Instanz|Instanzen]], die manuell erstellt werden, hardwarebeschleunigt sein, wodurch sie später schneller gezeichnet werden können.
 +
 
 +
 
 +
== Das war nicht alles! ==
 +
 
 +
Es gibt noch viele Details, die man beim Skalieren von Bildern berücksichtigen kann. Im oben verlinkten Artikel wird genauer auf diese Details eingegangen und verschiedene mögliche Strategien beim Skalieren besprochen, und die Ergebnisse mit Benchmarks und Testbildern verglichen. Aber schon die Frage, ob man Bilder in einem bestimmten Anwendungsfall eher ''skaliert zeichnen'' sollte, oder ob es besser wäre, eine ''skalierte Instanz'' eines Bildes zu erstellen, kann schwierig zu beantworten sein. Dieser Artikel soll nur die grundsätzlichen Unterschiede und Vorgehensweisen beschreiben, und hilft hoffentlich, zu verhindern, dass jemand vor jedem Zeichnen eines Bildes eine skalierte Instanz mit <code>getScaledInstance</code> erstellt....
 +
 
 +
 
 +
=Links=
 +
*Original-Link (nicht mehr verfügbar: https://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html) -> https://web.archive.org/web/20070515094604/https://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html
 +
*[https://stackoverflow.com/a/24746194/3182664 Java - resize image without losing quality - Stack Overflow]
 +
*[https://stackoverflow.com/a/32278737/3182664 java - How to improve the performance of g.drawImage() method for resizing images - Stack Overflow]
 +
 
 +
{{Fragen stellen}}
 +
 
 +
[[Kategorie:Tutorials (Java)]]|[[Kategorie:Java 2D]]

Aktuelle Version vom 12. Dezember 2023, 18:34 Uhr

Bilder skalieren

Einen ausführlichen Artikel zum Thema 'Bilder skalieren' gibt es unter The Perils of getScaledInstance. Die wichtigsten Punkte sind hier kurz zusammengefasst.

Bim Skalieren von Bildern gibt es im wesentlichen zwei mögliche Ziele: Man will das Bild entweder skaliert zeichnen, oder man will eine skalierte Instanz eines Bildes erstellen. In beiden Fällen kann man noch unterschiedliche Schwerpunkte setzen. So kann im einen Fall die Performance (also die Zeichengeschwindigkeit) besonders wichtig sein, und im anderen Fall die Bildqualität.

Bilder skaliert zeichnen

Wenn man ein Bild skaliert zeichnen will, kann man das am einfachsten direkt mit der geeigneten Methode drawImage aus der Klasse Graphics. Von dieser Methode gibt es verschiedene Varianten, und unter anderem eine, mit der man direkt sagen kann, wie groß das Bild gezeichnet werden soll:

public boolean drawImage(Image image, int x, int y, int width, int height, ImageObserver observer)

Um ein Bild in einer Größe von 400x300 Bildpunkten zu zeichnen, verwendet man also

graphics.drawImage(image, 0, 0, 400, 300, null);


Skalierte Instanzen erstellen

Um eine skalierte Instanz eines Bildes zu erstellen, kann man einfach das vorhandene Bild in ein Bild der gewünschten Größe hineinzeichnen:

BufferedImage originalImage = ImageIO.read(new File("image.png"));
BufferedImage scaledImage = new BufferedImage(400, 300, BufferedImage.TYPE_INT_ARGB);
Graphics g = scaledImage.createGraphics();
g.drawImage(originalImage, 0, 0, 400, 300, null);
g.dispose();

Wie man sieht wird hierbei die gleiche Methode drawImage aus der Klasse Graphics verwendet, wie beim skalierten Zeichnen. Allerdings wird das Bild hier nicht auf den Bildschirm, sondern in ein anderes Bild hinein gezeichnet.


RenderingHints: Qualität oder Geschwindigkeit?

Sowohl beim skalierten Zeichnen als auch beim erstellen skalierter Instanzen kann man durch das Setzen von Rendering Hints noch festlegen, ob eher in höherer Qualität oder eher in höherer Geschwindigkeit gezeichnet werden soll. Diese Rendering Hints setzt man in dem Graphics2D-Objekt, das man zum Zeichnen verwendet. Dabei ist egal, ob man direkt auf den Bildschirm oder in ein anderes Bild hinein zeichnet.

Zum Beispiel wird hier gesagt, dass bilineare Interpolation verwendet werden soll, was zwar etwas langsamer ist, aber für höhere Bildqualität sorgt:

Graphics2D g = (Graphics2D)graphics;
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                   RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(image, 0, 0, 400, 300, null);

Hätte man statt VALUE_INTERPOLATION_BILINEAR den Wert VALUE_INTERPOLATION_NEAREST_NEIGHBOR angegeben, wäre die Bildqualität geringer, aber das Zeichnen etwas schneller.


Warum nicht getScaledInstance?

Oft werden mit der Methode {JAPI|Image#getScaledInstance}} skalierte Instanzen von Bildern erstellt und gezeichnet - im schlimmsten Fall sogar bei jedem Zeichenvorgang erneut. Diese Methode ist oft weder in Bezug auf Bildqualität noch in Bezug auf die Performance die geeignetste Lösung. Die Methoden aus der Klasse Graphics2D und die RenderingHints bieten mehr Möglichkeiten, die für das jeweilige Ziel beste Skalierungs-Art zu wählen. Zusätzlich können die skalierten Instanzen, die manuell erstellt werden, hardwarebeschleunigt sein, wodurch sie später schneller gezeichnet werden können.


Das war nicht alles!

Es gibt noch viele Details, die man beim Skalieren von Bildern berücksichtigen kann. Im oben verlinkten Artikel wird genauer auf diese Details eingegangen und verschiedene mögliche Strategien beim Skalieren besprochen, und die Ergebnisse mit Benchmarks und Testbildern verglichen. Aber schon die Frage, ob man Bilder in einem bestimmten Anwendungsfall eher skaliert zeichnen sollte, oder ob es besser wäre, eine skalierte Instanz eines Bildes zu erstellen, kann schwierig zu beantworten sein. Dieser Artikel soll nur die grundsätzlichen Unterschiede und Vorgehensweisen beschreiben, und hilft hoffentlich, zu verhindern, dass jemand vor jedem Zeichnen eines Bildes eine skalierte Instanz mit getScaledInstance erstellt....


Links


Fragen

Das Thema wurde nicht ausreichend behandelt? Du hast Fragen dazu und brauchst weitere Informationen? Lass Dir von uns helfen!

Wir helfen dir gerne!


Dir hat dieser Artikel gefallen? Oder Du hast Fehler entdeckt und möchtest zur Berichtigung beitragen? Prima! Schreibe einen Kommentar!

Du musst angemeldet sein, um einen Kommentar abzugeben.|