# Bild Pixelweise auslesen



## PixelHD (6. Jan 2012)

Hallo , 

ich habe ein Problem ich möchte ein Bild einlesen und das Bild einmal Pixel für Pixel durchgehen und nach einer Farbe suchen wenn die gefunden wird soll die Farbe auf Transparent geändert werden sodass nur die eigentliche Grafik da ist. In meinem Spiel setzte ich auf Canvas. Ich habe hier mal ein Beispiel Bild.



Im ersten Kästchen soll die Grüne Farbe rausgefiltert werden, sodass nur die 3 gelben Kreise im Spiel zu sehen sind. Ich weiß jedoch nicht wie ich ein Bild Pixel für Pixel einlese und wie ich eine bestimmte Farbe dann ändere.

Ich hoffe ihr habt Ideen und könnt mir bei meinem Problem helfen.

MFG ThePixel5D


----------



## Fu3L (6. Jan 2012)

Einfachstes Beispiel:


```
BufferedImage img = Dein Bild;
int yourColor = new Color(255, 0, 255).getRGB();
int newColor = new Color(0, 255, 255).getRGB();
for(int x = 0; x < img.getWidth(); x++) {
  for(int y = 0; y < img.getHeight(); y++) {
     if(img.getRGB(x, y) == yourColor) {
         img.setRGB(x, y, newColor);
     }
  }
}
```

Ersetzt jedes Vorkommen von der allgemein für Transparenz verwendeten Farbe 255, 0, 255 durch Cyan.
Einigen Methodennamen könnten leicht anders lauten (vllt toRGB()?), das hab ich nicht im Kopf.

Edit: Da du Transparenz möchtest, müsstest du natürlich Color mit 4 Argumenten konstruieren^^


----------



## PixelHD (6. Jan 2012)

Danke für die Hilfe ich habe auch den Tipp mit dem 4 Argument befolgt jedoch bleibt der Hintergrund schwarz oder weiß und bei anderen Wert passiert einfach nichts die Farbe wird nicht rausgefiltert nur wenn ich (0,0,0,0) o. (255,255,255,255) nehme.





So sieht es momentan aus jedoch sollte das schwarze durch Grau erstetzt werden. Sodass es wirklich transparent ist.

So schaut mein Code aus


```
int col = new Color(87, 0, 127, 255).getRGB();
		int col2 = new Color(0, 0, 0, 0).getRGB();
		for (int x = 0; x < img.getWidth(); x++) {
			for (int y = 0; y < img.getHeight(); y++) {
				if (img.getRGB(x, y) == col) {
					img.setRGB(x, y, col2);
				}
			}
		}
		return img;
	}
```

MFG Pixel


----------



## Fu3L (7. Jan 2012)

Könnte es daran liegen, dass du darauf prüfst, obs Grau ist und das schwarz machst, anstatt wie gewünscht auf Schwärze zu prüfen und diese durch Grau zu ersetzen?^^


----------



## PixelHD (7. Jan 2012)

Ich prüfe den RGB Wert (87,0,127) und ersetzte die Farbe mit (0,0,0,0) was eigentlich schwarz ist aber durch das 4. Argument sollte es doch transparent sein oder nicht ? Ich kann auch nicht mit einem "Player" (das rote Viereck) hinter die Schrift fahren dann sehe ich ihn nämlich nicht mehr. Die Farbe an sich wird aber richtig erkannt.

MFG


----------



## Fu3L (7. Jan 2012)

Also dashier funktioniert wunderbar mit deinem Bild. Der graue Hintergrund (51, 51, 51) wird transparent und lässt das rote Panel durchscheinen.

Kleiner Tip: Nicht als jpg speichern, die ändern gerne mal die Farbe leicht (ist hier nicht das Problem, wollts nur so gesagt haben)


```
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;

import javax.swing.JFrame;
import javax.swing.JPanel;

import tools.ImageTools;

public class ImageReplacement extends JPanel {
	BufferedImage img;

	public ImageReplacement() {
		this.setBackground(Color.RED);
		img = ImageTools.getInstance().getImage("Unbenannt.png");
		int col = new Color(51, 51, 51, 255).getRGB();
		int col2 = new Color(0, 0, 0, 0).getRGB();
		for(int x = 0; x < img.getWidth(); x++) {
			for(int y = 0; y < img.getHeight(); y++) {
				if(img.getRGB(x, y) == col) {
					img.setRGB(x, y, col2);
				}
			}
		}
	}

	public static void main(String[] args) {
		JFrame f = new JFrame();
		f.setSize(500, 500);
		f.add(new ImageReplacement());
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f.setVisible(true);
	}

	@Override
	protected void paintComponent(Graphics g) {
		// TODO Auto-generated method stub
		super.paintComponent(g);
		g.drawImage(img, 0, 0, null);
	}

}
```


----------



## PixelHD (7. Jan 2012)

Komisch den Code kann ich garnicht ausführen.





Auf diesem Bild sieht man auch mal die PNG Datei (ein Teil davon) es sollen ja zwei Farben gefiltern werden habe ich auch soweit ohne Probleme geschafft 

```
int col = new Color(87, 0, 127).getRGB();
		int col2 = new Color(178, 0, 255, 255).getRGB();
		int col3 = new Color(0, 0, 0, 0).getRGB();
		for (int x = 0; x < img.getWidth(); x++) {
			for (int y = 0; y < img.getHeight(); y++) {
				if (img.getRGB(x, y) == col || img.getRGB(x, y) == col2) {
					img.setRGB(x, y, col3);
				}
			}
		}
```

Nur es wird nicht transparent warum weiß ich nicht.

EDIT:// 

Kann es vielleicht sein das er mit .setRGB/.getRGB nur die ersten 3 Werte nimmt ?


----------



## Fu3L (7. Jan 2012)

Der Code oben wird nicht ausführbar sien, weil die Methode zum Laden der Bilder eine meiner eigenen Klassen ist, ich kopiers mal direkt rein.
Ich vermute, dass es am Typ des BufferedImages liegt.

Hier im File sind zwei Möglichkeiten zum Laden, die kürzere habe ich unkommentiert gelassen. Das Auskommentierte wäre die zweite Möglichkeit. Das zweite verwende ich seit Jahren so, weils eine Klasse ist, die Quaxlie in seinem Spieletutorial vorstellt, aber die erste Methode ist hier ebenso angemessen.

Beachte besonders das TYPE_INT_*A*RGB.


```
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class ImageReplacement extends JPanel {
	BufferedImage img;

	/*private static GraphicsEnvironment ge;
	private static GraphicsConfiguration gc;

	static {

		//GraphicsConfiguration für VolatileImage
		ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
		gc = ge.getDefaultScreenDevice().getDefaultConfiguration();

	}*/

	public ImageReplacement() {
		this.setBackground(Color.RED);
		URL location = getClass().getClassLoader().getResource("Unbenannt.png");
		BufferedImage pic = null;
		try {
			pic = ImageIO.read(location);
		} catch (Exception ex) {
			System.out.println("Fehler beim Laden: " + ex);
		}

		/*img = gc.createCompatibleImage(pic.getWidth(), pic.getHeight(), Transparency.BITMASK);
		Graphics g = img.getGraphics();
		g.drawImage(pic, 0, 0, null);*/
		img = new BufferedImage(pic.getWidth(), pic.getHeight(), BufferedImage.TYPE_INT_ARGB);
		Graphics g = img.getGraphics();
		g.drawImage(pic, 0, 0, null);
		int col = new Color(51, 51, 51, 255).getRGB();
		int col2 = new Color(0, 0, 0, 0).getRGB();
		for(int x = 0; x < img.getWidth(); x++) {
			for(int y = 0; y < img.getHeight(); y++) {
				if(img.getRGB(x, y) == col) {
					img.setRGB(x, y, col2);
				}
			}
		}
	}

	public static void main(String[] args) {
		JFrame f = new JFrame();
		f.setSize(500, 500);
		f.add(new ImageReplacement());
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f.setVisible(true);
	}

	@Override
	protected void paintComponent(Graphics g) {
		// TODO Auto-generated method stub
		super.paintComponent(g);
		g.drawImage(img, 0, 0, null);
	}

}
```


----------



## PixelHD (7. Jan 2012)

Danke ich schätze mal das es daran liegt nur ich rendere über diese Methode 
	
	
	
	





```
public void render() {
		BufferStrategy bs = getBufferStrategy();
		if (bs == null) {
			createBufferStrategy(3);
			return;
		}
		Graphics g = bs.getDrawGraphics();
		g.fillRect(0, 0, getWidth(), getHeight());
		level.render(g);
		player.render(g);
		bs.show();
	}
```

muss ich jetzt noch ein Grafikobjekt erstellen ? Womit ich dann das BufferedImage rendere ? Oder wie weise ich meinem BufferedImage den TYPE ARGB zu ?


----------



## Fu3L (7. Jan 2012)

Ist es nicht eher deine Absicht, die Buchstaben direkt mit Transparenz irgendwo drauf zu zeichnen? Dann könntest du das schon beim Laden der Bilder machen.
Allerdings verstünde ich dann nicht, was gegen direkte Nutzung von Transparenz in den Bilddateien spricht?

In meinem Spiel Delirium! (letztens vorgestellt), nutze ich keine Transparenz, sondern die Farbe 255, 0, 255, wo keine Überdeckung stattfinden soll, aber da hab ich auch das gesamte Zeichnen selbst implementiert^^


----------



## PixelHD (7. Jan 2012)

> Ist es nicht eher deine Absicht, die Buchstaben direkt mit Transparenz irgendwo drauf zu zeichnen? Dann könntest du das schon beim Laden der Bilder machen.



Stimmt genau nur ich weiß nicht wie. Ich lade das Bild so :


```
BufferedImage image = ImageIO.read(Game.class.getResourceAsStream("/font.png"));
```

Aber wie weise ich genau dem BufferedImage ein neuen Typen zu. So wie es in deinem Beispiel ist muss ich dann noch eins erstellen und von dem neuen BufferedImage dann die Graphics nehmen und mit dem dann das image zeichnen. 


```
Allerdings verstünde ich dann nicht, was gegen direkte Nutzung von Transparenz in den Bilddateien spricht?
```

Da die Zeichnungen weiß sind kann man sie sehr schwer erkennen in Paint.NET

Bin dir echt dankbar für deine ganze Hilfe 

MFG Pixel


----------



## Fu3L (7. Jan 2012)

> So wie es in deinem Beispiel ist muss ich dann noch eins erstellen und von dem neuen BufferedImage dann die Graphics nehmen und mit dem dann das image zeichnen.



Das kannst du am Anfang ja schon erledigen, später belastet es den Spielfluss dann nicht mehr (bei den kleinen Bildern eh nicht).

Zu Paint.net:
Mach einfach eine schwarze Fläche, dann drücke strg+shift+n, so erhältst du eine neue transparente Ebene. Darauf malst du in weiß deinen Buchstaben. Dann löschst du einfach die schwarze untere Ebene und fertig ist dein Buchstabe. Solltest du ihn editieren müssen, fügst du einfach wieder eine schwarze Ebene ein.

Allerdings muss man dazu sagen, dass du es auch da wirst ummalen müssen in TYPE_INT_ARGB, da er sonst das BufferedImage vom Typ "Custom" nimmt und das ist ganz böse für die Performance. 
Siehe hierzu: http://www.java-forum.org/spiele-multimedia-programmierung/120318-performance-bufferedimages.html


----------



## PixelHD (7. Jan 2012)

Danke danke ... es klappt jetzt alles wo wie es soll. 

MFG Pixel


----------



## Marco13 (8. Jan 2012)

Hab's nicht gelesen, wollt' nur einwerfen dass es auch RasterOp (Java Platform SE 6) gibt, mit denen man sowas "high level" machen kann - aber vermutlich nicht so effizient


----------

