# Schwarzes Bild beim Abspeichern von JPanel



## syfds (1. Dez 2011)

Hallo zusammen,

ich bin gerade dabei, ein JPanel als Bild abzuspeichern. Da ich aber die Bildauflösung vor dem Speichern selbst bestimmen möchte, ändere ich die Größe des JPanels an die definierte Bildgröße, um in dem Zustand mein JPanel abzuspeichern, anschließend wird die ursprüngliche Größe wiederhergestellt. Nun habe ich das Problem, dass die erste Abspeicherung komplett schwarzes Bild liefert. Alle weitere Male bekomme ich korrekte Abzüge vom JPanel. Ich vermute, dass die Verkleinerung vor dem Speichern daran schuld ist, sodass das Image Objekt in dem Moment erstellt wurde, als das JPanel noch im Verkleinerungsprozess war. 

hier mein Code: 


```
panel.setSize(imageWidth, imageHeight);
panel.repaint();

BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g = image.createGraphics();

panel.paint(g);

ImageIO.write(image, "jpg", new File("test.jpg"));

//Wiederherstellung des ursprünglichen Zustands..
```

Hätte jemand Ahnung, woran es liegen könnte, dass das erste Bild komplett schwarz ist?
Ich bedanke mich für eure Hilfe im voraus!

Sergej


----------



## Spacerat (1. Dez 2011)

Nur eine sehr wage Vermutung, aber vllt. liegt's am DoubleBuffering. Möglicherweise speicherst du ja das, was im BackgroundPuffer liegt und genau dieser ist vorm ersten paint halt leer.


----------



## syfds (1. Dez 2011)

Danke erstmal für  die schnelle Antwort!

und wie könnte ich rausfinden, ob DoubleBuffering leer oder voll ist?


----------



## syfds (1. Dez 2011)

ich habe gerade festgestellt, dass wenn ich zwei Bilder nacheinander erzeuge, dann ist das erste komplett schwarz und das zweite korrekt. Hier der Code: 


```
//1. Bild
panel.setSize(imageWidth, imageHeight);
panel.repaint();
 
BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g = image.createGraphics();
 
panel.paint(g);
 
ImageIO.write(image, "jpg", new File("test.jpg"));
 
//Wiederherstellung des ursprünglichen Zustands..
container.validate();
container.repaint();


//2. Bild
panel.setSize(imageWidth, imageHeight);
panel.repaint();
 
image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g = image.createGraphics();
 
panel.paint(g);

ImageIO.write(image, "jpg", new File("test2.jpg"));
 
//Wiederherstellung des ursprünglichen Zustands..
container.validate();
container.repaint();
```


----------



## Spacerat (1. Dez 2011)

Also DBff ist standardmässig in Swing aktiviert und vor dem 1. Frame ist der Puffer immer leer. Vllt. hilft es, wenn du statt paint mal die in AWT übliche Methode update oder die in Swing übliche paintComponent aufrufst.


----------



## syfds (1. Dez 2011)

ich habe sowohl update als auch paintComponents Methoden ausprobiert, es hat nicht geholfen. Wie kann ich den Puffer(DBff ) befüllen bevor er zu zeichnen anfängt?


```
panel.paintComponents(img.getGraphics());

panel.update(img.getGraphics());
```


----------



## Spacerat (2. Dez 2011)

Gar nicht. In die sem Puffer müsste sich ja sonst ein Bild vor dem ersten befinden. Überspringe einfach das Erste und gut.


----------



## syfds (2. Dez 2011)

Hi, 

danke nochmals für deine Hilfe, deine Tipps haben mich weitergebracht. Nun habe ich das Problem, dass das Bild *nicht vollständig* gezeichnet wird. Es wird ein Bild geliefert, das in ein anderes geschrieben werden soll. 


```
public void paintIntoImage(BufferedImage writeImage){
//es wird das richtige Image Objekt geliefert
BufferedImage myImage = getImage();

//Mit einem MediaTracker versuche ich das Bild vollständig zu laden
MediaTracker mt = new MediaTracker(viewPanel);
		mt.addImage(myImage , 1);
		
		try {
			mt.waitForAll();
		} catch (InterruptedException e1) {
			//DO NOTHING
		}

//bei Thread.sleep(5000) an dieser Stelle funktioniert alles einwandfrei

//writeimage ist ein leeres BufferedImage Objekt
writeImage.getGraphics().drawImage( myImage , 0 , 0 , null);
}
```

Mal wird das Bild myImage gezeichnet, mal nicht ganz. Wo könnte hier mein Fehler liegen? Wie kann man noch das Laden eines Bildes abwarten? Wenn ich mithilfe von Thread.sleep(5000) einfach warte, wird das Bild vollständig gezeichnet. Es liegt vermutlich daran dass mein Mediatracker nicht lange genung wartet. 





Für eure Hilfe bedanke ich mich im voraus!

Sergej


----------



## syfds (2. Dez 2011)

Ich habe nun sowas versucht: 


```
public void paintIntoImage(BufferedImage writeImage){
//es wird das richtige Image Objekt geliefert
BufferedImage myImage = getImage();
 
//Mit einem MediaTracker versuche ich das Bild vollständig zu laden
MediaTracker mt = new MediaTracker(viewPanel);
        mt.addImage(myImage , 1);
        
        try {
            mt.waitForAll();
        } catch (InterruptedException e1) {
            //DO NOTHING
        }
 
Image loadedImage = new ImageIcon(myImage).getImage();
 myImage = ImageUtil.toBufferedImage(loadedImage);

//writeimage ist ein leeres BufferedImage Objekt
writeImage.getGraphics().drawImage( myImage , 0 , 0 , null);
}
```

ich habe nämlich gelesen, dass ImageIcon im Konstruktor das Bild vollständig lädt, das hilft mir aber auch nicht. Bei ungefähr einem von 6-7 Versuchen wird das Bild nicht komplett gezeichnet. Ich könnte manuell abwarten, was ich durch Thread.sleep(3000) erreichen könnte, ich möchte aber eine saubere Lösung haben. 

Wenn jemand von euch mit dem Problem konfrontiert ist, würde ich mich über jede Hinweise freuen!

mfg

Sergej


----------



## Michael... (2. Dez 2011)

syfds hat gesagt.:


> ```
> try {
> mt.waitForAll();
> } catch (InterruptedException e1) {
> ...


Sowas würde ich mir erst gar nicht angewöhnen. In den catch Block gehört mindestens ein 
	
	
	
	





```
e1.printStackTrace();
```
 eventuell wird in Deinem Fall sogar eine InterruptException geworfen? Denn eigentlich sollte waitForAll() auch warten bis alle Bilder geladen sind.

ImageIcon nutzt im Hintergrund auch den MediaTracker um das Bild zu laden. In dem Fall wird dann doppelt geladen.


----------



## syfds (3. Dez 2011)

Michael... hat gesagt.:


> Sowas würde ich mir erst gar nicht angewöhnen. In den catch Block gehört mindestens ein
> 
> 
> 
> ...



Hi, du hast Recht, das mit catch Block war jetzt nicht so sauber. 

Obwohl das Image Objekt vollständig geladen ist, wird es nicht vollständig gezeichnet. Welches Thema könnte ich mir genauer anschauen, um das Problem zu lösen?

Danke im voraus!

mfg

Sergej


----------



## Spacerat (4. Dez 2011)

Ganz wie Michael schon sagt, ImageIcon lädt anscheinend nochmal ohne das du irgendwie drauf warten könntest - obwohl... "toBufferedImage()" sollte eigentlich warten. Lass die Zeilen 16 und 17 einfach mal weg. Ausserdem... wenn "getImage()" bereits ein BufferedImage liefert, ist dein MediaTracker ebenso überflüssig. Daraus folgt, dass genau dieses "getImage()" bereits fehlerhaft ist.


----------



## syfds (4. Dez 2011)

Spacerat hat gesagt.:


> Ganz wie Michael schon sagt, ImageIcon lädt anscheinend nochmal ohne das du irgendwie drauf warten könntest - obwohl... "toBufferedImage()" sollte eigentlich warten. Lass die Zeilen 16 und 17 einfach mal weg. Ausserdem... wenn "getImage()" bereits ein BufferedImage liefert, ist dein MediaTracker ebenso überflüssig. Daraus folgt, dass genau dieses "getImage()" bereits fehlerhaft ist.



Alles klar, du hast Recht, ich werde mir die Methode 
	
	
	
	





```
getImage()
```
 genauer anschauen...


----------

