2017-10-20 2 views
0

ich ein Bild mit einer benutzerdefinierten Palette (mit anderen Worten einer benutzerdefinierte Farbmodell) zu schaffen:BufferedImage deaktiviert das Dithering beim Reduzieren von Farben mit einem benutzerdefinierten ColorModel?

BufferedImage img = new BufferedImage(orgImg.getWidth(), orgImg.getHeight(), 
     BufferedImage.TYPE_BYTE_INDEXED, 
     cm); 
Graphics2D g2 = img.createGraphics(); 
    g2.drawImage(orgImg, 0, 0, null); 
    g2.dispose(); 

Beachten Sie, dass der „cm“ Variable ein Farbmodell mit einer Palette von 256 Farben meiner Gewohnheit ist.

Die Variable "orgImg" ist ein vollfarbiges (24 großes argb) Bild.

Der obige Code führt zu einer Kopie von "orgImg" mit 256 Farben unter Verwendung der im Farbmodell definierten Palette.

Das funktioniert gut.

Aber Java verwendet Dithering, um Farben zu reduzieren. Ist es möglich, dieses Dithering zu deaktivieren?

Beachten Sie, dass ich meine eigene Palette verwenden muss, damit die endgültigen Bilder einer bestimmten Farbpalette entsprechen.

Antwort

2

Beim Zeichnen eines Bildes in ein Graphics2D Objekt können verschiedene Aspekte des Renderings unter Verwendung von RenderingHint s gesteuert werden. Sie sollten den Dithering mit den Graphics2D.setRenderingHint oder setRenderingHints Methoden deaktivieren können, die als Parameter KEY_DITHERING und VALUE_DITHER_DISABLE Wert übergeben:

Graphics2D g2 = img.createGraphics(); 
// Disable dithering 
g2.setRenderingHint(RenderingHint.KEY_DITHERING, RenderingHint.VALUE_DITHER_DISABLE); 
g2.drawImage(orgImg, 0, 0, null); 
g2.dispose(); 

die Java2D tutorial für weitere Informationen anzeigen.

PS: Beachten Sie, dass die Methoden/Klasse "Hinweis" genannt werden.

Dies ist vielleicht kein Problem mehr, aber in der Vergangenheit habe ich erlebt, dass die Deaktivierung des Dither mit dem Hinweis wie oben nicht funktioniert hat. Es ist auch nicht möglich, den zu verwendenden Dithering-Algorithmus zu spezifizieren, typischerweise wird nur ein "geordneter" oder "Diamant" -Muster-Dithering verwendet.

Ich habe daher meine eigenen Versionen verschiedener Dithering-Algorithmen für diesen Zweck implementiert. Sehen Sie die CopyDither (die für jedes Pixel eine Suche mit der besten Übereinstimmung durchführt, wahrscheinlich, was Sie hier wollen) und DiffusionDither (die eine "Floyd-Steinberg" -Fehlerdiffusion Dither implementiert). Beide der genannten Implementierungen beruhen auf einem schnellen Reverse-Lookup von Farbwerten. Leider macht der Standard IndexColorModel keine schnellen Reverse-Lookups. Also habe ich auch für diesen Fall eine spezielle Klasse implementiert, siehe InverseColorMapIndexColorModel Klasse.

Verbrauch:

BufferedImage img = new BufferedImage(orgImg.getWidth(), orgImg.getHeight(), BufferedImage.TYPE_BYTE_INDEXED, cm); 
CopyDither noDither = new CopyDither(new InverseColorMapIndexColorModel(cm)); // cm must be IndexColorModel 
noDither.filter(orgImg, img); 
+0

renderinghints Mit funktioniert nicht in diesem speziellen Fall (in anderen/den meisten Fällen es funktioniert), der KEY_DITHERING ignoriert. Es gibt einige Themen im Internet zu diesem Problem, aber keine gibt es eine Lösung, die eine gute Leistung hat. Probieren Sie es einfach aus. –

+1

Ich habe gerade gesehen, dass du deine Frage editiert hast ;-) Ich werde dir deine Klassen ansehen, sie sehen gut aus, weil die Verwendung von Rastern gut für die Performance ist. Ich werde Sie auf dem Laufenden halten! –

+0

Prost @HaraldK, es hat eine Weile gedauert, um die Dinge heute Morgen herauszufinden, aber nachdem du deine Abhängigkeiten gefunden hast, lief alles glatt. Ich habe CopyDither mit meinem Farbmodell verwendet und eine nicht geditherte Version erstellt. Und es ist auch ziemlich schnell, mein hacky setRgb (getRgb) für jedes Pixel ist 50% langsamer. Danke noch einmal! –

Verwandte Themen