# Pixel setzen mit TYPE_INT_ARGB



## Gast (20. Sep 2008)

Hallo, nachdem ich es in einem anderen Thread versucht habe, dort aber keine Antwort bekam, roll ich mal das Thema neu auf: 
Mein Programm soll einem BufferedImage, dass mit TYPE_INT_ARGB deklariert wurde, ein genau ausgewählten RGB mit Alpha-Wert ersetzen.
Leider habe ich schon viele Möglichkeiten aus dem Forum ausprobiert. Das Problem war meistens, dass dort statt TYPE_INT_ARGB -> TYPE_INT_RGB oder statt BufferedImage -> Image, etc. benutzt wurde.
Kann mir jmd. einen Lösungsvorschlag angeben?


----------



## muckelzwerg (20. Sep 2008)

Was genau willst Du denn wissen?
BufferdImage hat doch die "setRGB(...)" und "getRGB(...)" Methoden.
(ist zwar langsam, fuktioniert aber erstmal)

  --  --  muckelzwerg


----------



## Gast (20. Sep 2008)

Mit denen funkioniert es. Aber wie du schon sagtest: sehr langsam :/
Ein Bild mit *mindestens* 1920 x 1024 Pxl. abzutasten und ggf. pixelweise zu ersetzen ist nicht die raffinierteste Methode. Gibt es nicht etwas schnelleres?


----------



## muckelzwerg (20. Sep 2008)

Du kannst die Daten direkt als array ansprechen.

```
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
```

"Raffiniert" versteh ich nicht. Wenn Du jeden Pixel anschauen und evt. ändern musst, dann gehts halt nicht anders.
Du kannst ansonsten noch alle auf einmal zurückschreiben, mit 
System.arraycopy(...), ob das in dem Fall Sinn macht ist ne andere Frage.

  --  --  muckelzwerg


----------



## Gast (20. Sep 2008)

Und ".getData()" liefert den ARGB-Wert?
Das "raffiniert" nehme ich zurück  Wo du recht hast, hast du recht.
Aber gibt es nicht noch die Möglichkeit mit einer LookupTable?


----------



## Ark (20. Sep 2008)

Erklär doch bitte mal, was du überhaupt machen willst.

Ark


----------



## muckelzwerg (20. Sep 2008)

Ich hab so ein bisschen das Gefühl, das Du weder in die Dokumentation schaust, noch die Hilfestellungen wirklich durcharbeitest.
setRGB() und getRGB() sind doch vollkommen eindeutig Kommentiert, was die Rückgabewerte angeht.
"getData()" ist eine Funktion der DataBuffer Klasse.
Schau in die Doku, wie sie funzt.
(kleiner Hinweis: Siehst Du in den zwei Zeilen irgendwo eine Indexangabe die den Pixel bestimmen könnte?)

  --  --  muckelzwerg


----------



## Gast (20. Sep 2008)

Okay - ausholende Erklärung:
Ich lade ein Tileset als BufferedImage in das Programm rein. Dort wird es beim Laden sofort in skalierte Tile-Kompartimente zerlegt und - wie in der Tileset-Datei - angezeigt. (Nun sind die Tiles anklickbar und) man kann über ein kleines Preview-Fenster Pixel anklicken (deren RGB repräsentant für alle Pixel aus dem Tileset mit diesem speziellen RGB sind). Mittels Zuweisungsereignis werden im ganzen Tileset an den jeweiligen Stellen die Pixel mit Transparenz ersetzt. Mit anderen Worten: Das Durchlaufen aller Pixel ist gekoppelt an einer 4-fach verschachtelten for-Schleife. Das ist äußerst unschön ^^


----------



## muckelzwerg (20. Sep 2008)

Du holst den RGB-Wert des Pixels. "getRGB()".
Du holst alle Pixel "getData()".
Du läufst einmal linear über das Array und ersetzt jeden Pixel, falls er dem vorher ermittelten Wert entspricht.

  --  --  muckelzwerg


----------



## Fancy (21. Sep 2008)

Moin,

Ergebnis einer kurzen persönlichen Fingerübung:


```
package fancy.jf.unsorted;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class ColorAlternation {

    public static void main(String args[]) throws IOException, InterruptedException {

        // get some sample data
        final BufferedImage sample = ImageIO.read(ColorAlternation.class.getResource("/pic.png"));

        // setup our buffered work image
        final BufferedImage work = new BufferedImage(sample.getWidth(), sample.getHeight(), BufferedImage.TYPE_INT_ARGB);
        final Graphics2D g = work.createGraphics();
        g.drawImage(sample, 0, 0, null);
        g.dispose();

        // setup color src and dst
        final Color srcColor = new Color(0, 0, 0, 0);
        final Color dstColor = new Color(255, 255, 0, 255);

        final int src = (srcColor.getAlpha() << 24) | (srcColor.getRed() << 16) | (srcColor.getGreen() << 8) | (srcColor.getBlue() << 0);
        final int dst = (dstColor.getAlpha() << 24) | (dstColor.getRed() << 16) | (dstColor.getGreen() << 8) | (dstColor.getBlue() << 0);

        // setup threads
        final int maxThreads = 4;
        final Thread[] threads = new Thread[maxThreads];
        final long timeThreads = System.currentTimeMillis();

        // several times because it is so fast
        for (int j = 0; j < 1000; j++) {

            final int[] pixels = ((DataBufferInt) work.getRaster().getDataBuffer()).getData();

            for (int i = 0; i < maxThreads; i++) {
                final int thread = i;
                threads[i] = new Thread(new Runnable() {
                    public void run() {
                        for (int i = thread; i < pixels.length; i += maxThreads) {

                            // replace pixel
                            if (pixels[i] == src) pixels[i] = dst;
                        }
                    }
                });

                threads[i].start();
            }

            // wait for all threads
            for (int i = 0; i < maxThreads; i++) {
                threads[i].join();
            }

        }

        System.out.println((System.currentTimeMillis() - timeThreads) / 1000.0);

        // show image
        final JFrame frame = new JFrame();
        final JLabel label = new JLabel(new ImageIcon(work));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(label);
        frame.pack();
        frame.setVisible(true);
    }

}
```


Braucht für die vom Gast angegebenen Bildgrößen gerade mal 2.5 Millisekunden. Für 100MPixel immerhin 130 Millisekunden.

(Schade, hätte eigentlich gehofft es wäre langsamer, dann wäre noch Raum für Optimierungen gewesen. Lohnt sich aber bei den Zeiten wohl kaum, es sei den unser Gast arbeitet im > 100MPixel Bereich.)

Gruß,
Michael


----------



## Gast (22. Sep 2008)

@Fancy: Derartiges habe ich gesucht und werde es morgen gleich mal ausprobieren. Die Routine für den >100MPixel-Bereich würde ich dennoch optional mit einbauen wollen... *g* Allerdings kann ich mir nicht vorstellen, was man da noch alles optimieren kann


----------

