Wie kann man eine Bildlupe als Vergößerung eines Bildausschnittes realisieren?
Das Programm erzeugt ein Fenster
mit zwei nebeneinander liegenden zentralen
Bildflächen und einem JSlider
zum Einstellen des Vergrößerungsmaßstabs.
Links werden das Originalbild und rechts ein
vergrößerter Ausschnitt dargestellt. Der
Ausschnitt zeigt den Bereich um die Cursorposition, wenn
dieser über das linke Bild bewegt wird.
Im Konstruktor werden nacheinander das Bild geladen, ein
initialer Ausschnitt kopiert [29] und schließlich
das GUI erzeugt [30]. Nach dem Laden des Bildes wird in
der Methode copyArea()
ein Ausschnitt
erzeugt. Hierzu werden in einem try-catch-Block
sichergestellt, dass sich der zu kopierende Ausschnitt
innerhalb des Bildbereiches liegt und der
Skalierungsfaktor größer 1 ist. Ist er gleich
1, so wird das Originalbild unskaliert angezeigt [71].
Der Faktor ist in der privaten Variablen scale
abgelegt [21] und nicht als Konstante definiert, um ihn
durch den Slider einstellen zu können.
Die x- und y-Koordinaten der linken oberen
Ausschnittecke werden aus der als Methodenparameter
übergebenen Cursorposition und dem
Skalierungsfaktor berechnet [75]. Das in einer
Instanzvariablen gespeicherte kopierte BufferedImage
wird durch die Methode getSubimage()
erzeugt. Sie wird auf dem BufferedImage
-Objekt
des Originals aufgerufen und bekommt die Koordinaten der
linken oberen Ecke, sowie Breite und Höhe des
Ausschnitts als Parameter übergeben.
Nach Beenden der Methode sind das Originalbild und die Kopie jeweils in einer Variablen [22] gespeichert und stehen zur Anzeige zur Verfügung.
import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.BorderLayout; import java.awt.Graphics; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.awt.image.BufferedImage; import java.awt.image.RasterFormatException; import java.io.IOException; import javax.imageio.ImageIO; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JSlider; import javax.swing.SwingUtilities; public class Bildlupe { private static final String PATH = "/img/Norton_Manx_200.png"; private static final String APP_NAME = "Bildlupe"; private int scale = 2; private BufferedImage bi, copy; public Bildlupe() { if (scale <= 0) { System.out.println("Skalierungsfaktor muss > 0 sein."); System.exit(1); } loadAndCopyImage(PATH); createGUI(); } private void createGUI() { ImagePanel sourcePanel = new ImagePanel(bi.getWidth(), bi.getHeight(), bi); ImagePanel copyPanel = new ImagePanel(bi.getWidth(), bi.getHeight(), copy); sourcePanel.addMouseMotionListener(new MouseMotionAdapter() { public void mouseMoved(MouseEvent e) { scaleArea(copyPanel, e.getX(), e.getY()); } }); JSlider slider = new JSlider(1, 10, 2); slider.addChangeListener(e -> { scale = slider.getValue(); slider.setToolTipText("1 : " + scale); copyPanel.repaint(); }); JFrame frame = new JFrame(APP_NAME); frame.setLayout(new BorderLayout()); JPanel imgPanel = new JPanel(new FlowLayout()); imgPanel.add(sourcePanel); imgPanel.add(copyPanel); frame.add(imgPanel, BorderLayout.CENTER); frame.add(slider, BorderLayout.PAGE_END); frame.pack(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLocationRelativeTo(null); frame.setVisible(true); } private void loadAndCopyImage(String path) { try { bi = ImageIO.read(getClass().getResource(path)); } catch (IOException e) { System.err.println("Couldn't load image"); } copyArea(0, 0); } private void copyArea(int x, int y) { try { if (scale == 1) { copy = bi; return; } x = x == 0 ? 0 : x - bi.getWidth() / (scale * 2); y = y == 0 ? 0 : y - bi.getHeight() / (scale * 2); copy = bi.getSubimage(x, y, bi.getWidth() / scale, bi.getHeight() / scale); } catch (RasterFormatException rfe) { return; } } private void scaleArea(ImagePanel panel, int x, int y) { copyArea(x, y); panel.setBi(copy); panel.repaint(); } class ImagePanel extends JPanel { private int width, height; private BufferedImage img; public ImagePanel(int width, int height, BufferedImage img) { this.width = width; this.height = height; this.img = img; this.setPreferredSize(new Dimension(width, height)); } private void setBi(BufferedImage img) { this.img = img; } public void paintComponent(Graphics g) { super.paintComponent(g); g.drawImage(img, 0, 0, width, height, null); } } public static void main(String[] args) { SwingUtilities.invokeLater(() -> new Bildlupe()); } }
Hierzu wird in createGUI()
das
Userinterface erzeugt. Es besteht aus einem JFrame
mit BorderLayout
. Zentral werden die
Bildflächen in einem gesonderten JPanel
mit FlowLayout
[49], unten ein JSlider
[53]
geladen.
Die Bildflächen sind in einer inneren Klasse [89]
von JPanel
abgeleitet, um paintComponent()
überschreiben zu können. Hier wird durch die Graphics
-Methode
drawImage()
das Bild gezeichnet. Die
Methode bekommt wiederum den linken oberen Punkt als x-
und y-Koordinaten und Breite und Höhe
übergeben. Der ebenfalls als Parameter verlangte ImageObserver
wird nicht benötigt und kann null
gesetzt werden.
Das Panel mit dem Original wird bei einem MouseMotionListener
angemeldet. So kann beim Überfahren der Fläche
mit der Maus die Methode scaleArea()
kontinuierlich aufgerufen werden [83]. Sie kopiert den
jeweiligen Ausschnitt abhängig von der
Cursonposition und dem Skalierungsfaktor durch den
internen Aufruf von copyArea()
[84],
übergibt diese Kopie an die Bildfläche [85]
und zeichnet sie neu [86].
Im unteren Fensterbereich ist eine JSlider
vorhanden [53], der zur Vorwahl des Skalierungsfaktors
dient. Hierzu ist er bei einem ChangeListener
angemeldet [42], der die Sliderposition an die Variable
scale
übergibt [43]. Durch Neuzeichnen
der zugehörigen Bildfläche [45] wird dann der
neu berechnete Bildausschnitt angezeigt.
Wenn Ihnen javabeginners.de gefällt, freue ich mich über eine Spende an diese gemeinnützigen Organisationen.