package io.gitlab.jfronny.ImgJava.util; import javax.swing.*; import java.awt.*; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.List; /** * Der PictureViewer ist ein JFrame, der in der Lage ist ein * Objekt der Klasse Picture anzuzeigen. Zusätzlich können * mehrere Verarbeitungsschritte gespeichert werden, um ein * "zurück"-Funktion zu ermöglichen. * * @author Thomas Schaller * @version V1.2 vom 06.12.2019 */ public class ImageStackViewer extends JFrame implements MouseWheelListener, KeyListener { public static final int FIT = -1; public static final int NORMAL = 1; private double zoom; private final List history = new ArrayList<>(); private int currentIndex = 0; private final JLabel imagePane = new JLabel(); private final JScrollPane scrollPane; public ImageStackViewer(Dimension imageSize) { this.zoom = NORMAL; setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); Container cp = getContentPane(); cp.setLayout(new BorderLayout()); imagePane.setPreferredSize(imageSize); scrollPane = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); scrollPane.setViewportView(imagePane); cp.add(scrollPane, BorderLayout.CENTER); pack(); this.setVisible(true); Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); int x = (d.width - getSize().width); int y = 0; setLocation(x, y); scrollPane.addMouseWheelListener(this); scrollPane.addKeyListener(this); this.addMouseWheelListener(this); this.addKeyListener(this); setTitle("ImageViewer"); } /** * Speichert das übergebene Bild in der History. */ public Picture push(Picture image) { BufferedImage base = image.getImage(); BufferedImage bNew = new BufferedImage(base.getWidth(), base.getHeight(), base.getType()); image.getImage().copyData(bNew.getRaster()); history.add(bNew); if (history.size() == currentIndex + 2) { currentIndex++; resize(); } fixTitle(); return image; } /** * Ruft das letzte abgespeicherte Bild aus der History wieder auf. */ public void pop() { if (history.size() > 0) { history.remove(currentIndex); if (currentIndex >= history.size()) currentIndex = history.size() - 1; resize(); repaint(); } fixTitle(); } /** * Setzt den Zoom-Faktor für das Bild. * Als Zoomfaktor sind auch die Konstanten Bildanzeiger.FIT (auf Bildschirmgröße zoomen) und Bildanzeiger.NORMAL (100%) möglich. * * @param zoom Zoomfaktor (1.0 = 100%). */ public void setZoom(double zoom) { if (zoom > 0.01 && zoom < 10.0) { this.zoom = zoom; } // else this.zoom = NORMAL; resize(); repaint(); fixTitle(); } /** * Passt die Framegröße an das anzuzeigende Bild an. */ public void resize() { BufferedImage pictureCurrent = getCurrent(); if (pictureCurrent == null) return; int pref_x = (int) (pictureCurrent.getWidth() * zoom); int pref_y = (int) (pictureCurrent.getHeight() * zoom); imagePane.setPreferredSize(new Dimension(pref_x, pref_y)); Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); if ((pref_x > d.getWidth() - 30) || (pref_y > d.getHeight() - 100)) { pref_x = Math.min(pref_x, (int) d.getWidth() - 30); pref_y = Math.min(pref_y, (int) d.getHeight() - 100); scrollPane.setPreferredSize(new Dimension(pref_x, pref_y)); } else scrollPane.setPreferredSize(null); imagePane.revalidate(); pack(); } /** * Setzt das angezeigt Bild neu und beachtet dabei den Zoomfaktor. */ @Override public void repaint() { double f = zoom; BufferedImage pictureCurrent = getCurrent(); if (pictureCurrent != null) { if (zoom == FIT) { double faktorw = (double) imagePane.getWidth() / pictureCurrent.getWidth(); double faktorh = (double) imagePane.getHeight() / pictureCurrent.getHeight(); f = Math.min(faktorw, faktorh); } int disp_width = (int) (pictureCurrent.getWidth() * f); int disp_height = (int) (pictureCurrent.getHeight() * f); BufferedImage image = new BufferedImage(disp_width, disp_height, BufferedImage.TYPE_INT_ARGB); Graphics2D g = image.createGraphics(); g.drawImage(pictureCurrent, 0, 0, disp_width, disp_height, 0, 0, pictureCurrent.getWidth(), pictureCurrent.getHeight(), null); g.setColor(new java.awt.Color(0, 0, 0)); g.setStroke(new BasicStroke((float) 1)); g.drawRect(0, 0, disp_width - 1, disp_height - 1); imagePane.setIcon(new ImageIcon(image)); } imagePane.repaint(); super.repaint(); } private BufferedImage getCurrent() { if (currentIndex < 0) currentIndex = 0; if (currentIndex >= history.size()) return null; return history.get(currentIndex); } @Override public void mouseWheelMoved(MouseWheelEvent e) { int notches = e.getWheelRotation(); if (notches < 0) { setZoom(zoom * 1.1); } else { setZoom(zoom / 1.1); } } @Override public void keyTyped(KeyEvent e) { } @Override public void keyPressed(KeyEvent e) { } @Override public void keyReleased(KeyEvent e) { switch (e.getKeyCode()) { case KeyEvent.VK_DELETE -> pop(); case KeyEvent.VK_LEFT -> { int w = currentIndex - 1; if (w >= 0) currentIndex = w; resize(); repaint(); } case KeyEvent.VK_RIGHT -> { int w = currentIndex + 1; if (w < history.size()) currentIndex = w; resize(); repaint(); } default -> System.out.println(e.getKeyChar()); } fixTitle(); } private void fixTitle() { setTitle(getTitle()); } @Override public void setTitle(String title) { super.setTitle(title + " @ " + (currentIndex + 1) + "/" + history.size() + " # " + Math.round(zoom * 10000) / 10000d); } @Override public String getTitle() { String t = super.getTitle(); if (t.contains(" @ ")) { t = t.split(" @ ")[0]; } return t; } }