Swing sehr großes Bild skalieren

Status
Nicht offen für weitere Antworten.

nuely

Mitglied
Moin zusammen.

Ich habe zwei Probleme mit einer sehr großen Grafik. Eine vergleichbare habe ich angehängt. Müsst ihr wieder vergrößern auf 6000x3000 Pixel. Das Original, was später eingesetzt werden soll, ist 230KB groß.
Über Pfeil Auf/Ab soll es möglich sein das Bild zu skalieren. Das habe ich auch soweit hinbekommen mit drawImage. Ich verwende VALUE_INTERPOLATION_NEAREST_NEIGHBOR, da dass die schnellste Methode sein soll. Nun zu meinen Problemen.

1. Das ganze ist ein Speicherfresser. Ohne mindestens mit -Xmx256M zu starten wird nicht mal das Bild geladen bzw. das Skalieren geht nicht. Manchmal funktioniert das Skalieren damit nicht einmal. Das Skalieren läuft nicht gerade flüssig. Ich hatte gehofft, wenn man fünf Mal verkleinert (fünf Mal sofort Pfeil Ab drücken) wird das relativ schnell ausgeführt. Es dauert aber etwa 5 Sekunden und auch nur wenn ich schon auf 512MB erhöhe. Wie kann ich das besser machen?

2. Wie kann ich den JFrame mit anpassen? Je kleiner das Bild wird, umso größer werden die grauen Bereiche, weil sich der Frame nicht mit anpasst. Mit setSize geht das zwar, aber ich möchte nicht, dass er größer wird als 1000x800. Das gleiche gilt für das verwendete JPanel und die JScrollPane.

Vielen Dank schon mal für eure Vorschläge.

Java:
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;

public class Visualisierung3 extends JFrame{

	private static final long serialVersionUID = 1L;
	private JScrollPane jScrollPane = null;
	private JPanel jPanel = null;
	private JLabel hintergrundLabel;
	private BufferedImage hintergrundBildNormal;
	private BufferedImage hintergrundBildScaled;
	private int widthHintergrund = 6000;
	private int heightHintergrund = 3000;
	private int zoom = 10;
	private final int MAXZOOM = 10;
	private final int MINZOOM = 1;
	
	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				Visualisierung3 thisClass = new Visualisierung3();
				thisClass.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			}
		});
	}

	public Visualisierung3() {
		super();
		try {
			hintergrundBildNormal = ImageIO.read(new File("C:\\Bild.gif"));
			hintergrundBildScaled = hintergrundBildNormal;
		} catch (IOException e) {
			e.printStackTrace();
		}
		this.setSize(1000, 800);
		this.setMaximumSize(new Dimension(1000, 800));
		this.setTitle("Visualisierung");
		this.addKeyListener(new java.awt.event.KeyAdapter() {
			public void keyPressed(java.awt.event.KeyEvent e)
			{
				if(e.getKeyCode()==KeyEvent.VK_DOWN)
				{
					if (zoom != MINZOOM)
					{
						zoom = zoom - 1;
					}
					labelSkalieren();
				}
				if(e.getKeyCode()==KeyEvent.VK_UP)
				{
					if (zoom != MAXZOOM)
					{
						zoom = zoom + 1;
					}
					labelSkalieren();
				}
			}
		});
		
		jPanel = new JPanel();
		jPanel.setLayout(null);
		hintergrundLabel = new JLabel(new ImageIcon(hintergrundBildScaled));
		hintergrundLabel.setSize(widthHintergrund, heightHintergrund);
		jPanel.setPreferredSize(hintergrundLabel.getSize());
		jPanel.add(hintergrundLabel);
		jScrollPane = new JScrollPane();
		jScrollPane.setViewportView(jPanel);
		this.setContentPane(jScrollPane);
		this.setVisible(true);
	}

	private void labelSkalieren() {
		hintergrundBildScaled = scale(hintergrundBildNormal, (float) zoom/MAXZOOM);
		hintergrundLabel.setSize(hintergrundBildScaled.getWidth(), hintergrundBildScaled.getHeight());
		hintergrundLabel.setIcon(new ImageIcon(hintergrundBildScaled));
//		this.setBounds(0, 0, hintergrundLabel.getWidth(), hintergrundLabel.getHeight());
//		this.setSize(hintergrundLabel.getSize());
		this.repaint();
	}
	
	public BufferedImage scale(BufferedImage source, float factor) {
        int width = (int) (source.getWidth() * factor);
        int height = (int) (source.getHeight() * factor);
        BufferedImage img = new BufferedImage(width, height,
                                                    BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = (Graphics2D) img.getGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                             RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
        g2d.drawImage(source, 0, 0, width, height, null);
        return img;
    }
}
 

Marco13

Top Contributor
Also, dass es langsam ist kann ich jetzt nicht nachvollziehen (keine merkliche Verzögerung, also weniger als 0.25 Sekunden oder so). Könnte am Rechner, an der JVM und den Startparametern liegen...

Zum Speicherverbrauch: Ein 6000x3000 Bild braucht prinzipbedingt schonmal 72 MB - da hilft alles nichts. Wenn dann für einen kurzen Moment das gleiche Bild nochmal um 10% kleiner vorliegt, kommt man auf ca. 150MB alleine für das Bild ... dann bleibt von 256 schon nicht mehr sooo viel übrig.

Das Anpassen der Größe... ja... och, da schreibt bestimmt noch jemand anderes was dazu...
 

dayaftereh

Top Contributor
Zu 2:

Versuche einfach immer pack() und revalidate() auf dem JFrame aufzurufen, dann geht er durchs Layout und setzt für Alle Komponenten die Größe neu, und schneiden nicht benötigten platz weg!

Zu 1:

Habe ich jetzt nicht so die Idee!Außer einfach ein Temp File anzulegen um es auf der Platte zwischen zu speichern!

Da habe ich auch noch ne frage, Jeder Kennt doch eine Miniatur Ansicht, wenn ich so was in eine JListe machen will und in die JListe Bilder Lade, dann muss ich die Miniatur Ansicht nach Laden, aber ich bekomme da doch ein Speicher Problem im Memory mit den ganzen Bildern ?

lg
 

nuely

Mitglied
Zum Speicherverbrauch: Ein 6000x3000 Bild braucht prinzipbedingt schonmal 72 MB - da hilft alles nichts. Wenn dann für einen kurzen Moment das gleiche Bild nochmal um 10% kleiner vorliegt, kommt man auf ca. 150MB alleine für das Bild ... dann bleibt von 256 schon nicht mehr sooo viel übrig.

Hab ich befürchtet.


Zu 2:
Versuche einfach immer pack() und revalidate() auf dem JFrame aufzurufen, dann geht er durchs Layout und setzt für Alle Komponenten die Größe neu, und schneiden nicht benötigten platz weg!

JFrame hat kein revalidate(). Hab jetzt mal ein this.setPreferredSize(new Dimension(1000, 800)) eingebaut und rufe nun beim Skalieren folgendes auf:

[Java]
jPanel.revalidate();
jScrollPane.revalidate();
this.pack();
this.repaint();
[/Java]

Ändert aber nichts.

Zu 1:
Habe ich jetzt nicht so die Idee!Außer einfach ein Temp File anzulegen um es auf der Platte zwischen zu speichern!

Der eigentliche Vorgang des Skalieren könnte durch vorgefertigte Bilder in jeder Größe in der Tat wegfallen. Der Speicherbedarf wäre trotzdem der selbe, da es kurzzeitig zwei eingelesene Bilder gibt.
 

Marco13

Top Contributor
Wenn man die Größen nicht alle selbst setzt, ist diese Anpassung nicht so schwierig
Java:
// From [url]http://www.java-forum.org/awt-swing-swt/92969-sehr-grosses-bild-skalieren.html[/url]

import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;

public class Visualisierung3 extends JFrame{

    private static final long serialVersionUID = 1L;
    private JScrollPane jScrollPane = null;
    private JPanel jPanel = null;
    private JLabel hintergrundLabel;
    private BufferedImage hintergrundBildNormal;
    private BufferedImage hintergrundBildScaled;
    private int zoom = 10;
    private final int MAXZOOM = 10;
    private final int MINZOOM = 1;

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                Visualisierung3 thisClass = new Visualisierung3();
                thisClass.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            }
        });
    }

    public Visualisierung3() {
        super();
        try {
            hintergrundBildNormal = ImageIO.read(new File("Bild.gif"));
            hintergrundBildScaled = hintergrundBildNormal;
        } catch (IOException e) {
            e.printStackTrace();
        }
        this.setSize(1000, 800);
        this.setMaximumSize(new Dimension(1000, 800));
        this.setTitle("Visualisierung");
        this.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyPressed(java.awt.event.KeyEvent e)
            {
                if(e.getKeyCode()==KeyEvent.VK_DOWN)
                {
                    if (zoom != MINZOOM)
                    {
                        zoom = zoom - 1;
                    }
                    labelSkalieren();
                }
                if(e.getKeyCode()==KeyEvent.VK_UP)
                {
                    if (zoom != MAXZOOM)
                    {
                        zoom = zoom + 1;
                    }
                    labelSkalieren();
                }
            }
        });

        jPanel = new JPanel();
        jPanel.setLayout(new GridLayout(1,1));
        hintergrundLabel = new JLabel(new ImageIcon(hintergrundBildScaled));
        jPanel.add(hintergrundLabel);
        jScrollPane = new JScrollPane();
        jScrollPane.setViewportView(jPanel);
        this.setContentPane(jScrollPane);
        this.setVisible(true);
    }



    private void labelSkalieren() {
        hintergrundBildScaled = scale(hintergrundBildNormal, (float) zoom/MAXZOOM);
        hintergrundLabel.setIcon(new ImageIcon(hintergrundBildScaled));
//      this.setBounds(0, 0, hintergrundLabel.getWidth(), hintergrundLabel.getHeight());
//      this.setSize(hintergrundLabel.getSize());
        adjustSize();
        this.repaint();
    }

    private void adjustSize()
    {
        Dimension size = getPreferredSize();
        size.width = Math.min(size.width, 1000);
        size.height = Math.min(size.height, 800);
        setSize(size.width, size.height);
    }


    public BufferedImage scale(BufferedImage source, float factor) {
        int width = (int) (source.getWidth() * factor);
        int height = (int) (source.getHeight() * factor);
        BufferedImage img = new BufferedImage(width, height,
                                                    BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = (Graphics2D) img.getGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                             RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
        g2d.drawImage(source, 0, 0, width, height, this);
        return img;
    }
}
 

nuely

Mitglied
Ich hab jetzt einfach mal folgendes eingebaut:

Java:
System.out.println("Frame : "+this.getSize());
System.out.println("Scroll: "+jScrollPane.getSize());
System.out.println("Panel : "+jPanel.getSize());
System.out.println("Label : "+hintergrundLabel.getSize());

Ich hab gemerkt, dass sich die Größe des Panel nie verändert. Sie ist immer 6000x3000. Weil ich weiter oben jPanel.setPreferredSize(hintergrundLabel.getSize()) aufrufe. Ich habe den Aufruf jetzt beim Skalieren auch mit eingebaut und jetzt verkleinert sich das Panel auch mit. Lediglich der Frame bleibt immer bei 1000x800.
 

nuely

Mitglied
Wenn man die Größen nicht alle selbst setzt, ist diese Anpassung nicht so schwierig

Hatte deinen Post gerade noch gar nicht gesehen. Das funktioniert in der Tat in diesem Beispiel. Aber du hast aus dem Layout ein GridLayout gemacht. Ich muss mal gucken, ob das Originalprogramm dann noch funktioniert.

MATH.min kannte ich noch gar nicht.
 

nuely

Mitglied
Wenn man auf Layoutmanager verzichtet und glaubt sich mit einem Null-Layout das Leben einfacher machen zu können, muss eben auch mit den Konsequenzen leben ;-)

Das stimmt natürlich :). In diesem Fall werd ich auf das große Bild aber andere Label pixelgenau setzen und auch hin und herspringen lassen. Und da weiß ich nichts besseres als ein Null-Layout.

Wenn ich das setPreferredSize() wieder rausnehme kann ich jedenfalls Marcos Variante nutzen und das obwohl ich noch öfters setSize() auf die anderen Komponenten verwende.
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
Ernesto95 JavaFX JavaFX GUI mit sehr vielen Update requests AWT, Swing, JavaFX & SWT 4
P JTextField wird nur sehr klein angezeigt und verändert die Größe nicht AWT, Swing, JavaFX & SWT 3
E Java-TexturePaint sehr langsam AWT, Swing, JavaFX & SWT 9
S Swing Schrift sehr klein Ubuntu/eclipse AWT, Swing, JavaFX & SWT 18
Tommy135 JFileChooser ist sehr langsam AWT, Swing, JavaFX & SWT 13
MadMax2506 Swing JTable lädt sehr lange AWT, Swing, JavaFX & SWT 1
A JavaFX Sehr viele Exceptions bei Taschenrechner mit JavaFx AWT, Swing, JavaFX & SWT 2
RalleYTN Modaler Dialog und JTree Node mit sehr... seeeeehr vielen Elementen AWT, Swing, JavaFX & SWT 6
M Problem mit Layoutmanagern... Hilfe wäre sehr nett. AWT, Swing, JavaFX & SWT 2
J JavaFX Rendering von Canvas sehr langsam AWT, Swing, JavaFX & SWT 2
J Anfänger GUI Problem bei der Ausführung eines sehr einfachen Programms AWT, Swing, JavaFX & SWT 2
L [Slick2d] Sidescroller/Hintergrundbild sehr langsam AWT, Swing, JavaFX & SWT 3
E JavaFX Sehr viel und unterschiedlich Großen Inhalt auf einer "Fläche" ... Umsetzbar ? AWT, Swing, JavaFX & SWT 3
M JTable mit wechselnden Spalten - sehr Langsam AWT, Swing, JavaFX & SWT 5
E 3D-Grafik JOGL (lädt sehr lange) AWT, Swing, JavaFX & SWT 20
P sehr doll äußerst immens dringlich.... JFrame füllt sich nicht!!! AWT, Swing, JavaFX & SWT 5
R Image laden sehr langsam AWT, Swing, JavaFX & SWT 7
J Sehr schnell Text anzeigen? AWT, Swing, JavaFX & SWT 15
S Swing Swing macht sehr seltsame Zeichnungen. AWT, Swing, JavaFX & SWT 13
B JTree - sehr individuell AWT, Swing, JavaFX & SWT 3
K Swing Spiel flackert sehr häufig AWT, Swing, JavaFX & SWT 2
J 2D-Grafik JPanel reagiert sehr träge AWT, Swing, JavaFX & SWT 3
V Swing remove(Component) blockiert Thread sehr lange. AWT, Swing, JavaFX & SWT 6
K Graphics.drawImage() sehr schnell AWT, Swing, JavaFX & SWT 5
A Swing JTextPane sehr langsam AWT, Swing, JavaFX & SWT 6
T JList / ListSelectionListener / sehr eigenartig AWT, Swing, JavaFX & SWT 11
R JPanel sehr große JPanel hinzufügen AWT, Swing, JavaFX & SWT 5
R JTable für sehr viele Daten sehr langsam AWT, Swing, JavaFX & SWT 20
R Ich suche einen sehr simplen. AWT, Swing, JavaFX & SWT 2
G Sehr kleine JButtons mit Icon oder Beschriftung AWT, Swing, JavaFX & SWT 2
S Bilder werden sehr langsam geladen AWT, Swing, JavaFX & SWT 4
W gridbaglayout streckt sich zu sehr. AWT, Swing, JavaFX & SWT 17
doctus img.getScaledInstance() sehr rechenintensiv und langsam? AWT, Swing, JavaFX & SWT 3
ARadauer spalten überschriften von jtable sehr klein AWT, Swing, JavaFX & SWT 2
C JButton + JFrame Reaktion SEHR langsam. AWT, Swing, JavaFX & SWT 2
S GridLayout mit sehr großen Abständen AWT, Swing, JavaFX & SWT 3
E sehr simpel AWT, Swing, JavaFX & SWT 6
cool_brivk24 Großes Textfeld AWT, Swing, JavaFX & SWT 8
D JavaFX Leuchtendes großes Feld? AWT, Swing, JavaFX & SWT 2
S Swing [gelöst] GUI-Befehle bleiben wirkungslos, wenn danach was großes gemacht wird. AWT, Swing, JavaFX & SWT 5
W Suche großes vollständiges Swing GUI Beispiel nach MVC Model AWT, Swing, JavaFX & SWT 5
S Großes Array Problem AWT, Swing, JavaFX & SWT 10
B Ein großes JTextPane komplett drucken AWT, Swing, JavaFX & SWT 2
M JavaFX Mandelbrot-bild noch nicht optimiert AWT, Swing, JavaFX & SWT 7
berserkerdq2 Wie füge ich ein Bild in javafx mit dem Scenebuilder ein, das automatisch mitgezogen wird, wenn das Fenster vergrößert wird oder Vollbildmodus AWT, Swing, JavaFX & SWT 6
frager2345 Bild aus Dateien lesen und als Hintergrund verwenden AWT, Swing, JavaFX & SWT 2
T Bild in ein graphics füllen AWT, Swing, JavaFX & SWT 2
N imageIcon zeigt kein Bild an AWT, Swing, JavaFX & SWT 5
B Bild lädt nicht AWT, Swing, JavaFX & SWT 2
izoards Bild ausdrucken - PageFormat setzen geht nicht AWT, Swing, JavaFX & SWT 5
M Bild wird nicht geladen obwohl sie gefunden wird AWT, Swing, JavaFX & SWT 0
V JavaFX Bild leer und keine Fehlermeldung AWT, Swing, JavaFX & SWT 21
D JavaFX Bearbeitetes Bild wird nicht gespeichert AWT, Swing, JavaFX & SWT 9
D JavaFX Größe des Bild an ImageView anpassen AWT, Swing, JavaFX & SWT 3
M Bewegtes Bild im BorderLayout.CENTER AWT, Swing, JavaFX & SWT 6
C Falschfarbenbild (lineare Grauwertspreizung)aus Grauwert-Bild erstellen AWT, Swing, JavaFX & SWT 15
C Kleineres Bild an bestimmte Koordinaten setzen AWT, Swing, JavaFX & SWT 6
S Bild neu skalieren - Bild in Bild speichern? AWT, Swing, JavaFX & SWT 6
N Bild Drehen AWT, Swing, JavaFX & SWT 1
Hatsi09 Swing JPanel Bild einfügen AWT, Swing, JavaFX & SWT 14
J Bild von anderer Klasse will nicht laden AWT, Swing, JavaFX & SWT 1
M JavaFX Bild zur ImageView in einem Kreis anzeigen. AWT, Swing, JavaFX & SWT 4
T JFrame Bild einfügen AWT, Swing, JavaFX & SWT 9
M Combobox bild anklicken AWT, Swing, JavaFX & SWT 2
cool_brivk24 Swing ImageIcon lädt kein Bild AWT, Swing, JavaFX & SWT 12
L Bild nicht in der Mitte AWT, Swing, JavaFX & SWT 16
B JavaFX Bild um die eigene Achse drehen lassen AWT, Swing, JavaFX & SWT 0
J Swing Bild in Button AWT, Swing, JavaFX & SWT 11
I Bild über FXML (ImageView, Image) anzeigen AWT, Swing, JavaFX & SWT 1
T Image Loader lädt Bild nicht AWT, Swing, JavaFX & SWT 10
stroggi Swing Mehrere transparentes Objekte (Grafiken) über einem Bild (JLabel) darstellen AWT, Swing, JavaFX & SWT 4
P Kein Bild wird angezeigt bei ImageIcon AWT, Swing, JavaFX & SWT 16
T JavaFX Bild in Tabellenzelle AWT, Swing, JavaFX & SWT 2
Ksanatos Swing Bild (.jpg) einlesen und per Button wechseln AWT, Swing, JavaFX & SWT 9
S JPanel rotieren, Bild ist abgeschnitten, Clipping? AWT, Swing, JavaFX & SWT 0
MaxG. Swing Bild Button AWT, Swing, JavaFX & SWT 7
P Swing Bild Skallieren AWT, Swing, JavaFX & SWT 1
P Jframe Bild einfügen, Hintergrund Farbe ändern, und Button schrift Größe ändern AWT, Swing, JavaFX & SWT 2
A Swing Bild wird nicht mehr geladen AWT, Swing, JavaFX & SWT 4
A Swing Gemaltes Bild über saveDialog speichern unter AWT, Swing, JavaFX & SWT 15
R 2D-Grafik PNG Bild per Graphics auf JPanel AWT, Swing, JavaFX & SWT 9
S Bild mit ImageIcon auf GUI verkleinern AWT, Swing, JavaFX & SWT 3
T AWT Farben in einem Bild ändern AWT, Swing, JavaFX & SWT 8
I JFrame Bild strecken und auf Bildschirmgröße anpassen AWT, Swing, JavaFX & SWT 2
F Gezeichnetes als bild speichern AWT, Swing, JavaFX & SWT 4
B 2D-Grafik Bild farblich filtern AWT, Swing, JavaFX & SWT 2
B JavaFX ImageView neues Bild zuweisen AWT, Swing, JavaFX & SWT 19
A 2D-Grafik Bild wird nicht neu gezeichnet AWT, Swing, JavaFX & SWT 24
K Bild in JFrame AWT, Swing, JavaFX & SWT 2
S JavaFX Teil eines Bildes ausschneiden / als neues Bild nutzen AWT, Swing, JavaFX & SWT 8
B Swing Unterteiltes JFrame mit Bild in der Mitte AWT, Swing, JavaFX & SWT 4
I Applet BlueJ Applet - Bild mit if-Schleife zeichnen lassen AWT, Swing, JavaFX & SWT 16
Z Bildervorschau, MouseDragged das Bild verschieben AWT, Swing, JavaFX & SWT 1
M JavaFX Ein Bild ohne Rahmen fällt runter? AWT, Swing, JavaFX & SWT 2
G Anonyme Instanz von JXImageView erstellen und mit Bild initialisieren AWT, Swing, JavaFX & SWT 7
A JPanel Bild laden (Porblem mit Dateipfad) AWT, Swing, JavaFX & SWT 2
M JavaFX - Bild in Jar einbinden, sodass es auch außerhalb der IDE geladen wird. AWT, Swing, JavaFX & SWT 2
M Bild Beschreibung mit ImageIO speichern AWT, Swing, JavaFX & SWT 1
M "ImageIO.read()" liest Bild nicht richtig ein AWT, Swing, JavaFX & SWT 3
I Swing JLabel Bild für 1sec anzeigen lassen AWT, Swing, JavaFX & SWT 13

Ähnliche Java Themen

Neue Themen


Oben