225 lines
6.9 KiB
Java
225 lines
6.9 KiB
Java
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<BufferedImage> 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;
|
|
}
|
|
}
|