# Canvas Inhalt als Bild speichern!



## Javalus (15. Jan 2009)

Hallo!

Bin noch recht unerfahren was Java angeht, bin gerade aber dabei ein kleines Mal-Programm zu kreieren.
Klappt alles eigentlich wunderbar, auch habe ich eine Funktion zum Speichern des Bildes eingebaut.
Wenn ich den Canvas speichere, ist das Gemalte auf dem Bild aber leider nicht zu sehen, sondern nur der Hintergrund. Warum, das frage iech euch .


```
Malen aufn Canvas so:

public void mouseClicked(MouseEvent e){
  int x=e.getX(); int y=e.getY();
  Graphics g = canvas.getGraphics();
  g.drawOval(x,y,20,20);

}



..........

public void Speichern_ActionPerformed(ActionEvent evt) {

       BufferedImage bufferedImage = new BufferedImage(canvas.getWidth(), canvas.getHeight(),BufferedImage.TYPE_INT_RGB);
       canvas.paint(bufferedImage.getGraphics());
       try {ImageIO.write(bufferedImage, "JPEG",new File("bild.jpg"));}
       catch (IOException e1) {e1.printStackTrace();}
       
  }
```


----------



## Ebenius (15. Jan 2009)

Weil man eben nicht getGraphics() benutzt. Zeichne gleich in ein Image per Image.getGraphics(), rufe repaint() auf und überschreib die paint()-Methode des Canvas, um das Image dann darzustellen.

Grüße, Ebenius


----------



## Javalus (15. Jan 2009)

Ebenius hat gesagt.:
			
		

> Zeichne gleich in ein Image per Image.getGraphics(), rufe repaint() auf und überschreib die paint()-Methode des Canvas, um das Image dann darzustellen.
> 
> Grüße, Ebenius



War das jetzt ironisch oder ernst gemeint?


----------



## Ebenius (16. Jan 2009)

Nö. Genauer gesagt: Man benutzt Component.getGraphics() lieber nicht. Image.getGraphics() ist super. Meintest Du das?


----------



## Javalus (16. Jan 2009)

Aber wenn ich repaint() benutze, wird doch das ganze Applet neu geladen oder nicht?


----------



## Ebenius (16. Jan 2009)

huh? Wo steht das?


----------



## Javalus (16. Jan 2009)

Ebenius hat gesagt.:
			
		

> huh? Wo steht das?



Stehen tuts nirgends  . Hab eher die Erfahrung damit gemacht, weil ichs wohl falsch benutzt habe. Blutiger Anfänger .
Ebenius ich verstehe nicht, was du mit Image.getGraphics meinst statt getGraphics. Könntest du das vielleicht anhand eines kleinen Beispiels verdeutlichen? Wäre sehr nett


----------



## Ebenius (16. Jan 2009)

Ich hab mal als Beispiel einen Canvas gemacht. Den musst Du für die Variable "canvas" benutzen. Die Größe der Zeichenfläche kannst Du später ja noch ändern.
	
	
	
	





```
public class ZeichenCanvas extends Canvas {

  private final Image buffer =
        new BufferedImage(640, 480, BufferedImage.TYPE_INT_ARGB);

  @Override
  public void paint(Graphics g) {
    super.paint(g);
    g.drawImage(buffer, 0, 0, this);
  }

  public Image getOffscreenImage() {
    return buffer;
  }
}
```

Und jetzt änderst Du noch Deine MouseListener-Methode: 
	
	
	
	





```
public void mouseClicked(MouseEvent e){ 
  int x=e.getX(); int y=e.getY(); 
  Graphics g = canvas.getOffscreenImage().getGraphics(); 
  g.drawOval(x,y,20,20);
  canvas.repaint();
}
```

Wird's so klarer?

Ebenius


----------



## Javalus (16. Jan 2009)

Ebenius hat gesagt.:
			
		

> Ich hab mal als Beispiel einen Canvas gemacht. Den musst Du für die Variable "canvas" benutzen. Die Größe der Zeichenfläche kannst Du später ja noch ändern.
> 
> 
> 
> ...



Ich verstehe den ersten Code garnicht :S. Warum eigentlich extra eine neue Klasse eröffnen?


----------



## Javalus (16. Jan 2009)

Hab einfach add(canvas) gemacht  :?


----------



## André Uhres (16. Jan 2009)

Vielleicht noch zum grundlegenden Verständnis der allgemeinen Malmechanismen:
das AWT benutzt einen "callback" ("Wiederholungsbesuch") Mechanismus zum Zeichnen. 
Das heißt, daß ein Programm den Darstellungscode der Komponente innerhalb einer bestimmten 
überschriebenen Methode setzen sollte, und das Toolkit ruft diese Methode auf, wenn es Zeit ist zu malen. 
Die zu überschreibende Methode ist in java.awt.Component:


```
public void paint(Graphics g)
```

Programme müssen dieses Graphics Object verwenden (oder ein von ihm abgeleitetes) 
um die Oberfläche darzustellen. Sie sind frei, den Zustand des Graphics Objektes so zu ändern, 
wie es benötigt wird. 
Entwickler, die neu bei AWT sind, werden einen Blick auf das PaintDemo Beispiel werfen wollen, 
das ein lauffähiges Programmbeispiel liefert, wie man den paint callback in einem AWT Programm verwendet:

PaintDemo
http://java.sun.com/products/jfc/tsc/articles/painting/src/PaintDemo.java

Um anwendungsausgelöstes Malen zu ermöglichen, liefert das AWT die folgenden java.awt.Component Methoden, 
damit Programme einen asynchronen Malvorgang anfragen können:


```
public void repaint() 
    public void repaint(long tm) 
    public void repaint(int x, int y, int width, int height) 
    public void repaint(long tm, int x, int y, int width, int height)
```

Da es bei einem Malprogramm umständlich wäre, die ganzen Zeichnereien in der paint Methode nachzuvollziehen, 
zeichnet man einfach auf ein Image und malt das Image dann in der paint Methode mit g.drawImage(..):

```
private Canvas canvas;
private Graphics2D g2d;
private BufferedImage image;
...
canvas = new Canvas() {

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        if (image == null) {
            image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
            g2d = (Graphics2D) image.getGraphics();
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setColor(Color.white);
            g2d.fillRect(0, 0, getWidth(), getHeight());
            g2d.setColor(Color.black);
        }
        Rectangle r = g.getClipBounds();
        g.drawImage(image, r.x, r.y, r.width + r.x, r.height + r.y,
                r.x, r.y, r.width + r.x, r.height + r.y, null);

    }
};
```
Zum Speichern brauchen wir dann weiter nix zu machen, als das image in die Datei zu schreiben:

```
ImageIO.write(image, "JPEG", new File("bild.jpg"));
```

Und hier noch ein Beispiel: http://www.java-forum.org/de/userfiles/user3690/PaintDemo2.java


----------



## Ebenius (16. Jan 2009)

Javalus hat gesagt.:
			
		

> Hab einfach add(canvas) gemacht  :?



Die API-Doc der Canvas-Klasse sagt: 





> A Canvas component represents a blank rectangular area of the screen onto which the application can draw or from which the application can trap input events from the user.
> 
> An application must subclass the Canvas class in order to get useful functionality such as creating a custom component. The paint method must be overridden in order to perform custom graphics on the canvas.



Ebenius


----------



## Javalus (16. Jan 2009)

Hmm krieg bei canvas.getOffscreenImage() immer nen Fehler dass es nich gefunden wird


----------



## Ebenius (16. Jan 2009)

Du musst Deine canvas-Variable als ZeichenCanvas deklarieren.


----------



## Javalus (16. Jan 2009)

Ebenius hat gesagt.:
			
		

> Du musst Deine canvas-Variable als ZeichenCanvas deklarieren.



java:159:20: cannot find symbol
symbol  : variable ZeichenCanvas
  Graphics g = ZeichenCanvas.getOffscreenImage().getGraphics();


----------



## Ebenius (16. Jan 2009)

Du musst die ZeichenCanvas-Klasse (siehe oben) auch in Dein Projekt mit aufnehmen.

Und Du solltest mal ein Java-Buch für die Grundlagen zur Hand nehmen. Da lernst Du mehr, als beim durchhangeln.

Ebenius


----------



## André Uhres (16. Jan 2009)

In meinem Beitrag oben findest du ganz unten im Beitrag einen Link zu einem funtkionierenden Beispiel. Der Beitrag selbst gibt auch wissenswerte Hintergrundinformationen.


----------

