# Bild effektiv vergrössern / verkleinern (zoom)



## el_vital (25. Jan 2009)

Ich zeige ein Bild auf einem jLabel als Icon an. Das Bild möchte ich zoomen. Wenn ich es durch unten stehende Methode mache, dann ist es ziemlich langsam. Gibt es einen Weg es mit einem Icon zu beschleunigen oder sollte man das Bild anders darstellen?
Danke im Voraus.



```
iGlobHeight = iGlobHeight - 10;
   iGlobWidth = iGlobWidth - 10;
   jLabelBild.setIcon(new ImageIcon(ImgKlein.getScaledInstance(iGlobWidth, iGlobHeight, Image.SCALE_FAST)));
```


----------



## Wolfgang Lenhard (25. Jan 2009)

Ja, es gibt bessere Möglichkeiten.  Der von Dir eingeschlagene Weg ist nicht zu empfehlen: http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html
Am Besten ist das "On-The-Fly Scaling".

Ciao,
  Wolfgang

P.S.: Und Code gibt's natürlich hier im Forum auch: http://www.java-forum.org/de/viewtopic.php?p=479936&highlight=#479936


----------



## el_vital (25. Jan 2009)

alles klar. Danke. So werde ich es auch machen.

Noch eine Frage. Kann man das Aktualisieren der Oberfläche ausschalten, etwas tun und dann einschalten?
Ich habe ein Laben mit einem Bild. Über dem LAbel habe ich noch ein Label mit einem transparenten PNG Bild. Wenn ich an dem unteren Bild was ändere muss ich das obere Bild neu zeichnen. Wenn ich das mache, flackert das Bild. Es wäre besser die Aktualisierung der Oberfläche auszuschalten, unteres Bild ändern, oberes zeichen und die Oberfläche aktualisieren. Dann würde nichts flackern. Zu mindestens ist es bei C# so.


----------



## el_vital (25. Jan 2009)

bei einer Bewegung nach links mache ich jetzt z.B. folgendes:


```
iGlobY = iGlobY+10; 
    
    // Kann man hier die grafische Aktualisierung ausschalten?    
    gLabelImage.clearRect(0, 0, 500, 500);
    gLabelImage.drawImage(buffImgOriginal, iGlobX, iGlobY,  iGlobWidth, iGlobHeight, null);
    gLabelMaske.drawImage(buffImgMaske, 0, 0,  350, 450, null);
    // und hier wieder einschalten?
```

ist es Möglich überhaupt Aktualisierung zu sperren?


----------



## Wolfgang Lenhard (25. Jan 2009)

Du kannst natürlich wie im Beispiel mit der ImageComponent zusätzliche Variablen einbauen (z. B. eine Klassenvariable boolean paint = true und dann in der paintComponent abfragen, ob bzw. was  gezeichnet werden soll. Auf diese Weise lässt sich das gut regeln. Also in Deinem Beispiel etwas wie:


```
iGlobY = iGlobY+10;
   
    // Kann man hier die grafische Aktualisierung ausschalten?   
    gLabelImage.setRepaint(false);
    gLabelImage.clearRect(0, 0, 500, 500);
    gLabelImage.drawImage(buffImgOriginal, iGlobX, iGlobY,  iGlobWidth, iGlobHeight, null);
    gLabelMaske.drawImage(buffImgMaske, 0, 0,  350, 450, null);
    gLabelImage.setRepaint(true);    
// und hier wieder einschalten?
```

Den Setter musst Du natürlich in diesem Fall ebenfalls noch schreiben.


----------



## el_vital (25. Jan 2009)

Hallo Wolfgang,

ich habe das mit paintComponent  nicht ganz verstanden. Wie müßte die setRepaint Funktion aussehen und wie kann ich in der paintComponent bestimmen, dass ein Panel nicht gezeichnet werden soll?


----------



## el_vital (26. Jan 2009)

also gibt so etwas wie SuspendLayout() bei Java nicht?


----------



## Wolfgang Lenhard (26. Jan 2009)

Ich kenne SuspendLayout nicht und kann Dir das also nicht beantworten. Wenn Du die paintComponent-Methode überschreiben möchtest, dann benötigst Du eine eigene Klasse, z. B. die unten stehende. Über Getter und Setter kannst Du regeln, was dann dort genau geschehen soll:


```
public class ImageComponent extends JComponent {
   private static final long serialVersionUID = -2077784274430624977L;
   private Image image = null;
   private boolean paintModus = true;

   public ImageComponent(Image image) {
      this.image = image;
   }

   public ImageComponent() {

   }

public void setPaintModus(boolean paintModus){
   this.paintModus = paintModus;
}

   public void setImage(Image image) {
      this.image = image;
      repaint();
   }

   public void paintComponent(Graphics g) {
      super.paintComponent(g);

     //abfragen, ob das Bild gezeichnet werden soll
     if(paintModus){
      Graphics2D g2 = (Graphics2D) g;
      g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
            RenderingHints.VALUE_INTERPOLATION_BILINEAR);
      g2.setRenderingHint(RenderingHints.KEY_RENDERING,
            RenderingHints.VALUE_RENDER_QUALITY);
      if (image != null)
         g2.drawImage(image, 0, 0, getWidth(), getHeight(), null);
      
      g2.dispose();
      }
   }

}
```

Wenn Du setPaintModus(false) setzt, dann wird das Bild nicht gezeichnet, ansonsten schon. Schaue Dir mal die paintComponent an. Die entsprechende Abfrage findest Du dort.

Du kannst die Klasse natürlich beliebig erweitern, mehrere Bilder vorhalten, Bilder übereinander zeichnen etc. Ich gehe so teilweise vor, um Bilder mit Transparenzeffekten zu überlagern. Schaue Dir einmal Graphics2D an. Das bietet Dir viele Möglichkeiten.

Wenn Du möchtest, dann ein Panel gar nicht gezeichnet wird, dann müsstest Du es per setVisible(false) unsichtbar machen. Ich glaube aber nicht, dass es das ist, was Du möchtest.

Ciao,
 Wolfgang

P.S.: Wenn Du die Zeile super.paintComponent(g);  mit in die Klammer der If-Bedingung nimmst, dann würde die Komponente bei einem Repaint nicht neu gezeichnet werden, so wie das wohl beim SuspendLayout der Fall ist.


----------



## el_vital (26. Jan 2009)

ok, danke. Ich probiere es heute Abend aus. Ich glaube aber noch nicht, dass das die Lösung für das Problem ist. Ich möchte es ja zeichnen, aber die Darstellung halt erstmal nicht aktualisieren, sondern wenn alles gezeichnet ist, das dann auf einmal anzeigen. Bei deiner Methode würde doch wenn ich die Anzeige wieder zulasse auch nacheinander gezeichnet werden und das Flimmern wäre genau so da. Oder verstehe ich da noch was falsch?

Zu C#:

SuspendLayout => Unterbricht vorübergehend die Layoutlogik für das Steuerelement.

drauf beliebig in mehreren Schritten zeichnen

ResumeLayout => Nimmt die übliche Layoutlogik wieder auf. Und stellt alles gezeichnete auf einmal dar.


----------



## Wolfgang Lenhard (26. Jan 2009)

Du kannst das im obigen Code-Beispiel realisieren, indem Du das repaint() aus der Methode setImage herausnimmst, ein neues Bild übergibts und dann die Komponente zeichnen lässt (komponenteXYZ.repaint()). Da sollte eigentlich nichts flackern.


----------



## el_vital (26. Jan 2009)

irgend wie bekomme ich es nicht hin. Ich glaube, dass ich grundsätzlich einen falschen Ansatz habe.
Ich habe ein Panel mit Null Layout. Dem Panel füge ich nach einander zwei Labels zu. Auf dem unteren wird ein Bild angezeigt. Auf dem oberen die durchsichtige PNG-Datei. Wenn ich das untere Bild bewege oder vergrößere, dann muss ich das Bild und dann die Maske (PNG) neu zeichnen. Deswegen kommt es zu diesem Flimmern. Und ich kann die Tipps hier nicht umsetzen, damit es nicht flimmert und ich alles so machen kann wie ich es gerne würde.


Hier ist ein Beispiel: http://www.vs-multimedia.com/java/
Bewegt das Bild um zu sehen was ich meine.


----------



## Ebenius (26. Jan 2009)

Nimm einfach ein Panel und zeichne die Images mit g.drawImage(...) übereinander.


----------



## el_vital (26. Jan 2009)

Ebenius hat gesagt.:
			
		

> Nimm einfach ein Panel und zeichne die Images mit g.drawImage(...) übereinander.


eben ausprobiert. Flimmert genau so, weil es erst gelöscht und dann die zwei Bilder nacheinander gezeichnet werden müssen.


----------



## Ebenius (26. Jan 2009)

Dann zeichne beides in ein Offscreen-Image und zeichne das dann.


----------



## André Uhres (27. Jan 2009)

1234567890


----------



## el_vital (27. Jan 2009)

André Uhres hat gesagt.:
			
		

> Ich hab hier mal ein kleines Beispiel gemacht, das scheint gut zu funktionieren.
> Man kann das grosse Bild verschieben:


ein Bild zu verschieben ist nicht das Problem. Das Problem ist ein Bild unter einem anderen zu verschieben und beide neu zu zeichnen ohne, dass das obere kurzfristig ausgeblendet wird und dadurch Flimmern verursacht wird.
Aber Offscreen-Image scheint mir der richtige Ansatz zu sein.


----------



## André Uhres (27. Jan 2009)

1234567890


----------



## Ebenius (27. Jan 2009)

Offscreen-Image ist meist der richtige Ansatz; besonders wenn es darum geht, dass komprimierte Bilder skaliert dargestellt werden sollen. Viel Erfolg!


----------



## André Uhres (27. Jan 2009)

1234567890


----------



## Ebenius (27. Jan 2009)

André Uhres hat gesagt.:
			
		

> Swing hat das Doublebuffering bereits fertig im Toolkit eingebaut :wink:


Ist mir bekannt und ändert nix an meiner Aussage.


----------



## André Uhres (27. Jan 2009)

1234567890


----------



## Guest (27. Jan 2009)

André Uhres hat gesagt.:
			
		

> Doch, versuch's mal.


wie kann ich es mit NetBeans IDE 6.1 kompilieren?


----------



## el_vital (27. Jan 2009)

André Uhres hat gesagt.:
			
		

> Doch, versuch's mal.


hab es eben ausprobiert. Es sieht gut aus, aber ich verstehe dein Code jetzt auf die schnelle nicht. Werde es mir heute Abend genauer anschauen und versuchen es in meinem Applet umzusetzen. Danke.


----------



## el_vital (27. Jan 2009)

André Uhres: vielen Dank!!! Du hast mir super geholfen. Deine Lösung funktioniert bestens!


----------

