Wie kann ich bei einem BufferedImage in Java eine leichte Transparenz erzeugen oder die Sättigung verstellen?

...komplette Frage anzeigen

2 Antworten

Über einzelne Pixel würde ich AUF GAR KEINEN FALL iterieren, da dieser Prozess selbst bei kleinen Bildern so dermaßen ineffizient ist, dass der Zeichenvorgang ewig dauern wird.

Diese Aufgabe solltest du der Grafikkarte überlassen, bzw. mit Hardware-Unterstützung arbeiten:

BufferedImage bi = ... // dein Bild
float opacity = 0.5f; // Halbtransparent
Graphics2D g2d = (Graphics2D)g; // nötiger Cast

int mode = AlphaComposite.SRC_OVER; // siehe API Docs
AlphaComposite ac = AlphaComposite.getInstance(mode, opacity);

g2d.setComposite(ac);
g2d.drawImage(bi, x, y, null); // Profit!

Es lohnt sich extrem sich einfach mal die GESAMTE Dokumentation zu den ganzen Grafikklassen anzusehen, dazu zählen natürlich BufferedImage und Graphics2D, genauso wie z. B. BasicStroke o. ä., falls du mal eigene Vektor-Grafiken erzeugen o. rendern willst! Aber das nur als gut gemeinter Rat.

Die Grafik-API von Java ist sehr sehr mächtig, und wenn man es richtig anstellt, lassen sich selbst aufwändige Operationen effizient erledigen.

Wenn du getRGB() von einem Image-Objekt benutzt, ist das fast immer ein sicheres Zeichen dafür, dass du irgend etwas falsch machst. Benutze nach Möglichkeit IMMER die bereitgestellte Highlevel-API, denn die ist zu großen Teilen auf Performance optimiert und nutzt fast immer die Hardware direkt.

Viel Erfolg! :)

Antwort bewerten Vielen Dank für Deine Bewertung
  • Über alle Pixel iterieren
  • RGB(A)-Wert auslesen
  • Entweder Alphawert erhöhen oder
  • Sättigung erhöhen (evtl. Farbe erst in HSV-Format konvertieren)

Die entsprechenden Werte für Rot, Grün, Blau (und Alpha) kann man aus dem RGB(A)-Wert einfach mit den Bitweisen Operatoren bekommen.

final int green = rgb >> 8 & 0xff;

Antwort bewerten Vielen Dank für Deine Bewertung
TeeTier 23.08.2016, 14:22

Deine Antworten sind eigentlich immer sehr gut, aber hier liegst du ausnahmsweise mal daneben. Theoretisch funktioniert deine Methode zwar, aber in der Praxis ist Java einfach viel viel viel zu langsam dafür; selbst auf High-End-PCs.

Versuch mal ein "nur" 640x480 großes Bild mit deiner Methode in ein Graphics-Objekt zu zeichnen (z. B. in ein JComponent über paintComponent()), und miss den Zeitaufwand und die CPU-Auslastung mit einem Profiler. Dann wirst du wissen warum. :)

Ich habs jetzt nicht gemessen, aber ich würde einfach mal raten, dass du selbst auf einem 5GHz Rechner damit nicht weit über 5FPS kommen wirst, bei nahezu 100% Auslastung auf mindestens einem Kern. :)

Siehe dazu auch meine Antwort! Damit sollten locker mehrere hundert FPS möglich sein, und zwar ohne dass dabei der Rechner groß ins Schwitzen kommt. :)

Aaaaaber, deine Antwort ist trotzdem gut, denn als Anfänger (z. B. der Fragensteller) sollte man sowieso mal pixelweise mit Bildern arbeiten, und ein paar einfache Filter implementieren. Zum Lernen ist das für ein Verständnis wunderbar, wenn man dabei mit min() und max() ein Bild in Graustufen umwandelt, Kanäle tauscht, einen Posterisier-Effekt "erfindet" oder einfach die Farben invertiert.

Also meine Kritik bitte nicht persönlich nehmen! Wie gesagt, theoretisch hast du natürlich Recht, aber in der Praxis bleibt man dabei im Flaschenhals bei allen Bildern stecken, die größer als ein gängiges Icon sind! :)

1
Unkreatiiiev 24.08.2016, 16:36
@TeeTier

Um die Performance hab' ich mir garkeine Gedanken gemacht. Im Kontext eines Spiels ist so eine Iteration über mehrere Tausend Pixel natürlich viel zu langsam. Vielleicht sollte man dann sogar VolatileImage in betracht ziehen.

1
TeeTier 24.08.2016, 20:54
@Unkreatiiiev

Sehr richtig! Oder einfach - auch wenn ich das jetzt nicht extra erwähnt habe - über den internen Puffer in Form eines Arrays iterieren. Das Problem dabei ist leider die extreme Hardware-Abhängigkeit, die einem bei getRGB() natürlich sehr transparent abgenommen wird ... wie gesagt auf Kosten der Performance. :)

Naja ... aber so langsam schweife ich ab. ><

1

Was möchtest Du wissen?