diff --git a/ImgJava/.gitignore b/ImgJava/.gitignore new file mode 100644 index 0000000..26ce0b3 --- /dev/null +++ b/ImgJava/.gitignore @@ -0,0 +1,4 @@ +run/ +.idea/ +.gradle/ +build/ \ No newline at end of file diff --git a/ImgJava/.idea/.gitignore b/ImgJava/.idea/.gitignore deleted file mode 100644 index 26d3352..0000000 --- a/ImgJava/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/ImgJava/.idea/compiler.xml b/ImgJava/.idea/compiler.xml deleted file mode 100644 index b73660a..0000000 --- a/ImgJava/.idea/compiler.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/ImgJava/.idea/gradle.xml b/ImgJava/.idea/gradle.xml deleted file mode 100644 index 1fdf7d2..0000000 --- a/ImgJava/.idea/gradle.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/ImgJava/.idea/jarRepositories.xml b/ImgJava/.idea/jarRepositories.xml deleted file mode 100644 index fdc392f..0000000 --- a/ImgJava/.idea/jarRepositories.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/ImgJava/.idea/misc.xml b/ImgJava/.idea/misc.xml deleted file mode 100644 index 1700c77..0000000 --- a/ImgJava/.idea/misc.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/ImgJava/.idea/uiDesigner.xml b/ImgJava/.idea/uiDesigner.xml deleted file mode 100644 index e96534f..0000000 --- a/ImgJava/.idea/uiDesigner.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/ImgJava/build.gradle.kts b/ImgJava/build.gradle.kts index 5b78a64..2c6aacf 100644 --- a/ImgJava/build.gradle.kts +++ b/ImgJava/build.gradle.kts @@ -16,8 +16,6 @@ dependencies { shadow(dependencyNotation) } - testImplementation("org.junit.jupiter:junit-jupiter-api:5.6.0") - testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") dependency("org.jdom:jdom:1.1") } diff --git a/ImgJava/cum.png b/ImgJava/cum.png deleted file mode 100644 index 7da097a..0000000 Binary files a/ImgJava/cum.png and /dev/null differ diff --git a/ImgJava/gradle/wrapper/gradle-wrapper.properties b/ImgJava/gradle/wrapper/gradle-wrapper.properties index da9702f..f371643 100644 --- a/ImgJava/gradle/wrapper/gradle-wrapper.properties +++ b/ImgJava/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/Main.java b/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/Main.java index b9398d8..81b00a8 100644 --- a/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/Main.java +++ b/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/Main.java @@ -1,14 +1,25 @@ package io.gitlab.jfronny.ImgJava; import io.gitlab.jfronny.ImgJava.imageProcessing.ImageUtil; +import io.gitlab.jfronny.ImgJava.util.ImageStackViewer; import io.gitlab.jfronny.ImgJava.util.Picture; +import java.awt.*; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; public class Main { public static void main(String[] args) { try { - ImageUtil.mirror(new Picture("iris.jpg")).save("cum.png"); + ImageStackViewer stackViewer = new ImageStackViewer(new Dimension(1000, 1000)); + stackViewer.setTitle("Jf Example"); + Path run = Paths.get("./run/"); + if (!Files.isDirectory(run)) + Files.createDirectory(run); + stackViewer.push(ImageUtil.mirror(stackViewer.push(new Picture("iris.jpg")))).save(run.resolve("cum.png")); + stackViewer.repaint(); } catch (IOException e) { e.printStackTrace(); } diff --git a/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/imageProcessing/ImageUtil.java b/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/imageProcessing/ImageUtil.java index d1cbee5..07158d9 100644 --- a/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/imageProcessing/ImageUtil.java +++ b/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/imageProcessing/ImageUtil.java @@ -13,26 +13,23 @@ import java.awt.*; */ public class ImageUtil { /** - * spiegeleHorizontal spiegelt das Bild, so dass rechts und links getauscht werden + * Horizontally mirrors an image (mutates original instance) * - * @param originalbild Ein Bild (Picture), das gespiegelt werden soll - * @return Eine gespiegelte Kopie des Bildes + * @param picture Picture to mirror + * @return The mirrored image */ - public static Picture mirror(Picture originalbild) { - int breite = originalbild.getWidth(); - int hoehe = originalbild.getHeight(); + public static Picture mirror(Picture picture) { + int w = picture.getWidth(); + int h = picture.getHeight(); - Color[][] pixel = originalbild.getPixelArray(); - Color[][] pixelNeu = new Color[breite][hoehe]; + Color[][] pixel = picture.getPixelArray(); + Color[][] pixelNeu = new Color[w][h]; - for (int x = 0; x < breite; x++) { - for (int y = 0; y < hoehe; y++) { - pixelNeu[x][y] = pixel[(breite - 1) - x][y]; - } + for (int x = 0; x < w; x++) { + System.arraycopy(pixel[(w - 1) - x], 0, pixelNeu[x], 0, h); } - Picture neuesBild = new Picture(); - neuesBild.setPixelArray(pixelNeu); - return neuesBild; + picture.setPixelArray(pixelNeu); + return picture; } } diff --git a/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/util/ImageObserver.java b/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/util/ImageObserver.java new file mode 100644 index 0000000..5f2a7aa --- /dev/null +++ b/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/util/ImageObserver.java @@ -0,0 +1,6 @@ +package io.gitlab.jfronny.ImgJava.util; + +public interface ImageObserver { + void resize(); + void repaint(Picture p); +} diff --git a/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/util/ImageStackViewer.java b/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/util/ImageStackViewer.java new file mode 100644 index 0000000..ae0fdf2 --- /dev/null +++ b/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/util/ImageStackViewer.java @@ -0,0 +1,214 @@ +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; +import java.util.Vector; + +/** + * 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++; + fixTitle(); + return image; + } + + /** + * Ruft das letzte abgespeicherte Bild aus der History wieder auf. + */ + public void pop() { + if (history.size() > 0) { + history.remove(history.size() - 1); + 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(); + 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 >= 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; + repaint(); + } + case KeyEvent.VK_RIGHT -> { + int w = currentIndex + 1; + if (w < history.size()) + currentIndex = w; + 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; + } +} diff --git a/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/util/Picture.java b/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/util/Picture.java index 500b18b..d925298 100644 --- a/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/util/Picture.java +++ b/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/util/Picture.java @@ -24,7 +24,7 @@ import java.nio.file.Paths; * @author Thomas Schaller (ZPG Informatik Klasse 9) * @version 1.2 from 06.12.2019 */ - +//TODO arrays to proper classes public class Picture { // Einstellungmoeglichkeiten fuer das Zeichnen von Rechtecken und Ellipsen @@ -38,7 +38,6 @@ public class Picture { // gespeichertes Bild, private BufferedImage image; private Graphics2D g; - private boolean antialiasing; // aktuelle Farbeinstellungen private Color background; @@ -56,7 +55,7 @@ public class Picture { private Font textfont = null; // muss ein Bildanzeiger benachrichtigt werden - private PictureViewer observer = null; + private ImageObserver observer = null; private boolean autorefresh = true; /** @@ -82,9 +81,7 @@ public class Picture { * @param file Dateiname des Bildes */ public Picture(Path file) throws IOException { - this.antialiasing = true; load(file); - showInFrame(); } /** @@ -93,9 +90,7 @@ public class Picture { * @param resourceName Name der Ressource */ public Picture(String resourceName) throws IOException { - this.antialiasing = true; loadResource("images/" + resourceName); - showInFrame(); } /** @@ -106,27 +101,22 @@ public class Picture { * @param background Farbe des Hintergrunds */ public Picture(int width, int height, String background) { - this.antialiasing = true; - this.background = decode(background); + this.background = Color.decode("0x" + background); this.pencolor = new Color(0, 0, 0); this.stroke = 1; this.fillcolor = null; makeImage(width, height); - showInFrame(); - } - - public void showInFrame() { - PictureViewer v = new PictureViewer(this); } private void makeImage(int width, int height) { this.image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); - g = (Graphics2D) this.image.getGraphics(); + g = createGraphics(); g.setColor(this.background); g.fillRect(0, 0, width - 1, height - 1); } - - protected void antialise() { + + private Graphics2D createGraphics() { + Graphics2D g = image.createGraphics(); // Antialiasing g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // Rendering @@ -135,25 +125,7 @@ public class Picture { g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); // Color g.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); - - // Sonstiges - // g.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); - // g.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE); - // g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); - // g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); - // g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE); - } - - public void setAntialising(boolean neuerWert) { - this.antialiasing = neuerWert; - } - - public boolean isAntialiasing() { - return antialiasing; - } - - public PictureViewer getObserver() { - return observer; + return g; } /** @@ -162,8 +134,9 @@ public class Picture { * * @param observer Anzeiger des Bildes */ - public void setObserver(PictureViewer observer) { + public Picture setObserver(ImageObserver observer) { this.observer = observer; + return this; } /** @@ -180,8 +153,9 @@ public class Picture { * * @param b Bild, das gespeichert werden soll. */ - public void setImage(BufferedImage b) { + public Picture setImage(BufferedImage b) { image = b; + return this; } /** @@ -192,14 +166,13 @@ public class Picture { * @param width Breite des Bildes * @param height Hoehe des Bildes */ - public void size(int width, int height) { - pushImage(); + public Picture size(int width, int height) { makeImage(width, height); g.setColor(background); g.fillRect(0, 0, width - 1, height - 1); if (observer != null) observer.resize(); - repaint(); + return repaint(); } /** @@ -220,19 +193,6 @@ public class Picture { return image.getHeight(); } - /** - * Erzeugt eine Kopie des Bildes und uebergibt sie an den Observer (falls existent), damit dieser die Versionen speichern kann - */ - private void pushImage() { - if (observer != null) { - observer.pushImage(); - } - } - - public void setTitle(String titel) { - getObserver().setTitle(titel); - } - /** * Legt fest, ob nach jedem Zeichenbefehl automatisch das Bild auch in * der Oberflaeche aktualisiert wird. Die Einstellung "false" beschleunigt @@ -241,26 +201,26 @@ public class Picture { * * @param autoRefresh true = nach jedem Zeichenbefehl die Anzeige aktualisieren, false= nur durch die Methode refresh neu zeichnen */ - public void setAutoRefresh(boolean autoRefresh) { + public Picture setAutoRefresh(boolean autoRefresh) { this.autorefresh = autoRefresh; + return this; } /** * Auch die anzeigenden Klasse wird zum Neuzeichnen aufgefordert. */ - private void repaint() { - if (observer != null && autorefresh) { - observer.repaint(); - } + public Picture repaint() { + return repaint(false); } /** * Ein repaint() (das Neuzeichnen) kann manuell erzwungen werden. */ - public void forceRepaint() { - if (observer != null) { - observer.repaint(); + public Picture repaint(boolean force) { + if (observer != null && (force || autorefresh)) { + observer.repaint(this); } + return this; } // ----------------------------------------- Zeichenfunktionen ----------------------------------------------- @@ -270,13 +230,12 @@ public class Picture { * Der Hintergrund wird mit der Hintergrundfarbe neu gefuellt. */ - public void clear() { - pushImage(); + public Picture clear() { makeImage(image.getWidth(), image.getHeight()); g.setColor(background); g.fillRect(0, 0, image.getWidth() - 1, image.getHeight() - 1); - repaint(); + return repaint(); } /** @@ -286,7 +245,7 @@ public class Picture { * @param coord Array mit vier Koordinateneintraegen im gegebenen Modus * @param mode Modus der Koordinaten (CORNER, CORNERS, RADIUS oder CENTER) */ - private void convert(int[] coord, int mode) { + private Picture convert(int[] coord, int mode) { switch (mode) { case CORNER: break; @@ -301,6 +260,7 @@ public class Picture { coord[0] -= coord[2] / 2; coord[1] -= coord[3] / 2; } + return this; } /** @@ -317,8 +277,9 @@ public class Picture { * * @param mode Modus der Koordinateninterpretation (CORNER, CORNERS, CENTER oder RADIUS) */ - public void rectMode(int mode) { + public Picture rectMode(int mode) { rectMode = mode; + return this; } /** @@ -335,8 +296,9 @@ public class Picture { * * @param mode Modus der Koordinateninterpretation (CORNER, CORNERS, CENTER oder RADIUS) */ - public void ellipseMode(int mode) { + public Picture ellipseMode(int mode) { ellipseMode = mode; + return this; } /** @@ -350,16 +312,14 @@ public class Picture { * @param x2 x-Koordinate des 2. Punktes * @param y2 y-Koordinate des 2. Punktes */ - public void line(int x1, int y1, int x2, int y2) { - pushImage(); - + public Picture line(int x1, int y1, int x2, int y2) { if (stroke > 0) { g.setColor(pencolor); g.setStroke(new BasicStroke((float) stroke)); // if(antialiasing) antialise(); g.drawLine(x1, y1, x2, y2); } - repaint(); + return repaint(); } /** @@ -373,9 +333,7 @@ public class Picture { * @param c meist die Breite des Rechtecks (kann durch rectMode() geaendert werden). * @param d meist die Hoehe des Rechtecks (kann durch rectMode() geaendert werden). */ - public void rect(int a, int b, int c, int d) { - pushImage(); - + public Picture rect(int a, int b, int c, int d) { int[] coord = {a, b, c, d}; convert(coord, rectMode); if (fillcolor != null) { @@ -387,7 +345,7 @@ public class Picture { g.setStroke(new BasicStroke((float) stroke)); g.drawRect(coord[0], coord[1], coord[2], coord[3]); } - repaint(); + return repaint(); } /** @@ -401,9 +359,7 @@ public class Picture { * @param c meist die Breite des Rechtecks (kann durch ellipseMode() geaendert werden). * @param d meist die Hoehe des Rechtecks (kann durch ellipseMode() geaendert werden). */ - public void ellipse(int a, int b, int c, int d) { - pushImage(); - + public Picture ellipse(int a, int b, int c, int d) { int[] coord = {a, b, c, d}; convert(coord, ellipseMode); if (fillcolor != null) { @@ -416,7 +372,7 @@ public class Picture { // if(antialiasing) antialise(); g.drawOval(coord[0], coord[1], coord[2], coord[3]); } - repaint(); + return repaint(); } /** @@ -432,10 +388,10 @@ public class Picture { * @param x3 meist die x-Koordinate des 3. Punkts. * @param y3 meist die y-Koordinate des 3. Punkts. */ - public void triangle(int x1, int y1, int x2, int y2, int x3, int y3) { + public Picture triangle(int x1, int y1, int x2, int y2, int x3, int y3) { int[] px = {x1, x2, x3}; int[] py = {y1, y2, y3}; - polygon(px, py); + return polygon(px, py); } /** @@ -454,10 +410,11 @@ public class Picture { * @param x4 meist die x-Koordinate des 3. Punkts. * @param y4 meist die y-Koordinate des 3. Punkts. */ - public void quad(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) { + public Picture quad(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) { int[] px = {x1, x2, x3, x4}; int[] py = {y1, y2, y3, y4}; polygon(px, py); + return this; } /** @@ -469,9 +426,7 @@ public class Picture { * @param y Liste der y-Koordinaten der Punkte. */ - public void polygon(int[] x, int[] y) { - pushImage(); - + public Picture polygon(int[] x, int[] y) { if (fillcolor != null) { g.setColor(fillcolor); g.fillPolygon(x, y, y.length); @@ -482,7 +437,7 @@ public class Picture { // if(antialiasing) antialise(); g.drawPolygon(x, y, x.length); } - repaint(); + return repaint(); } /** @@ -492,8 +447,9 @@ public class Picture { * @param x x-Koordinate des Punktes * @param y y-Koordinate des Punktes */ - public void point(int x, int y) { + public Picture point(int x, int y) { ellipse(x, y, 1, 1); + return this; } // ----------------------------------------- Schriftdarstellung ----------------------------------------------- @@ -506,9 +462,7 @@ public class Picture { * @param x x-Koordinate des Textanfangs * @param y y-Koordinate der Grundlinie des Textes. */ - public void text(String s, int x, int y) { - pushImage(); - + public Picture text(String s, int x, int y) { if (pencolor != null) { if (fillcolor == null) g.setColor(Color.black); @@ -519,7 +473,7 @@ public class Picture { // if(antialiasing)g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); g.drawString(s, x, y); } - repaint(); + return repaint(); } /** @@ -528,46 +482,13 @@ public class Picture { * * @param font ein Font-Objekt */ - public void textFont(Font font) { + public Picture textFont(Font font) { this.textfont = font; + return this; } // ----------------------------------------- Farbfestlegungen ----------------------------------------------- - /** - * Hilfsfunktion zur Interpretation von Farben - */ - private Color decode(String color) { - try { - return new Color( - Integer.valueOf(color.substring(0, 2), 16), - Integer.valueOf(color.substring(2, 4), 16), - Integer.valueOf(color.substring(4, 6), 16)); - } catch (Exception e) { - System.err.println("Falscher Farbcode"); - return Color.BLACK; - } - } - - /** - * Hilfsfunktion zur Interpretation von Farben - */ - private Color decode(int color) { - try { - if (color >= 0 && color < 256) { - return new Color(color, color, color); - } else { - int r = color / 0x010000 % 0xFF; - int g = color / 0x000100 % 0xFF; - int b = color % 0xFF; - // System.out.println(""+r+","+g+","+b); - return new Color(r, g, b); - } - } catch (Exception e) { - System.err.println("Falscher Farbcode"); - return Color.BLACK; - } - } /** * Legt die Farbe fest, mit der Linien und Raender um Formen gezeichnet werden. @@ -576,8 +497,9 @@ public class Picture { * * @param pencolor Stiftfarbe in Hexadezimaldarstellung */ - public void stroke(String pencolor) { - this.pencolor = decode(pencolor); + public Picture stroke(String pencolor) { + this.pencolor = Color.decode("0x" + pencolor); + return this; } /** @@ -586,8 +508,9 @@ public class Picture { * * @param pencolor Stiftfarbe (0-255: Graustufe zwischen 0 schwarz und 255 weiss, sonst: c wird als 3-Byte RGB-Wert interpretiert) */ - public void stroke(int pencolor) { - this.pencolor = decode(pencolor); + public Picture stroke(int pencolor) { + this.pencolor = new Color(pencolor); + return this; } /** @@ -598,15 +521,17 @@ public class Picture { * @param g Gruenanteil (0-255) der Stiftfarbe * @param b Blauanteil (0-255) der Stiftfarbe */ - public void stroke(int r, int g, int b) { + public Picture stroke(int r, int g, int b) { this.pencolor = new Color(r, g, b); + return this; } /** * Legt fest, dass keine Linien oder Raender um Formen gezeichnet werden soll. */ - public void noStroke() { + public Picture noStroke() { this.pencolor = null; + return this; } /** @@ -615,8 +540,9 @@ public class Picture { * * @param width Breite in Pixel */ - public void strokeWeight(double width) { + public Picture strokeWeight(double width) { this.stroke = width; + return this; } /** @@ -626,8 +552,9 @@ public class Picture { * * @param fillcolor Fuellfarbe in Hexadezimaldarstellung */ - public void fill(String fillcolor) { - this.fillcolor = decode(fillcolor); + public Picture fill(String fillcolor) { + this.fillcolor = Color.decode("0x" + fillcolor); + return this; } /** @@ -636,8 +563,9 @@ public class Picture { * * @param fillcolor Fuellfarbe (0-255: Graustufe zwischen 0 schwarz und 255 weiss, sonst: c wird als 3-Byte RGB-Wert interpretiert) */ - public void fill(int fillcolor) { - this.fillcolor = decode(fillcolor); + public Picture fill(int fillcolor) { + this.fillcolor = new Color(fillcolor); + return this; } /** @@ -648,15 +576,17 @@ public class Picture { * @param g Gruenanteil (0-255) der Fuellfarbe * @param b Blauanteil (0-255) der Fuellfarbe */ - public void fill(int r, int g, int b) { + public Picture fill(int r, int g, int b) { this.fillcolor = new Color(r, g, b); + return this; } /** * Legt fest, dass die Formen nicht gefuellt werden sollen. */ - public void noFill() { + public Picture noFill() { this.fillcolor = null; + return this; } /** @@ -665,16 +595,13 @@ public class Picture { * * @param c Farbe fuer den Hintergrund (0-255: Graustufe zwischen 0 schwarz und 255 weiss, sonst: c wird als 3-Byte RGB-Wert interpretiert) */ - public void background(int c) { + public Picture background(int c) { if (c < 256) { this.background = new Color(c, c, c); } else { - int r = c / 0x010000; - int g = c / 0x000100 % 0xFF; - int b = c % 0xFF; - this.background = new Color(r, g, b); + this.background = new Color(c); } - this.clear(); + return this.clear(); } /** @@ -685,9 +612,9 @@ public class Picture { * @param g Gruenanteil (0-255) der Hintergrundfarbe * @param b Blauanteil (0-255) der Hintergrundfarbe */ - public void background(int r, int g, int b) { + public Picture background(int r, int g, int b) { this.background = new Color(r, g, b); - this.clear(); + return this.clear(); } /** @@ -696,9 +623,9 @@ public class Picture { * * @param hex String Farbe in Hexadezimalangabe */ - public void background(String hex) { - this.background = decode(hex); - this.clear(); + public Picture background(String hex) { + this.background = Color.decode("0x" + hex); + return this.clear(); } // ----------------------------------------- Dateioperationen ----------------------------------------------- @@ -709,8 +636,8 @@ public class Picture { * * @param file Dateipfad */ - public void load(String file) throws IOException { - load(Files.newInputStream(Paths.get(".").toAbsolutePath().normalize().resolve(file))); + public Picture load(String file) throws IOException { + return load(Files.newInputStream(Paths.get(".").toAbsolutePath().normalize().resolve(file))); } /** @@ -719,8 +646,8 @@ public class Picture { * * @param file Dateipfad */ - public void load(Path file) throws IOException { - load(Files.newInputStream(file)); + public Picture load(Path file) throws IOException { + return load(Files.newInputStream(file)); } /** @@ -729,15 +656,15 @@ public class Picture { * * @param stream Bildquelle */ - public void load(InputStream stream) throws IOException { + public Picture load(InputStream stream) throws IOException { this.image = ImageIO.read(stream); - this.g = (Graphics2D) image.getGraphics(); - this.background = decode("D0D0D0"); + this.g = createGraphics(); + this.background = Color.decode("0xD0D0D0"); this.pencolor = new Color(0, 0, 0); this.fillcolor = null; this.stroke = 1; if (observer != null) observer.resize(); - this.repaint(); + return this.repaint(); } /** @@ -745,8 +672,8 @@ public class Picture { * * @param resource Ressourcenpfad */ - public void loadResource(String resource) throws IOException { - load(Thread.currentThread().getContextClassLoader().getResourceAsStream(resource)); + public Picture loadResource(String resource) throws IOException { + return load(Thread.currentThread().getContextClassLoader().getResourceAsStream(resource)); } /** @@ -756,16 +683,17 @@ public class Picture { * * @param file Neuer Dateipfad */ - public void save(Path file) throws IOException { + public Picture save(Path file) throws IOException { String[] fn = file.getFileName().toString().split("\\."); if (fn.length == 0) { - save(file.resolve("unnamed.png")); + return save(file.resolve("unnamed.png")); } else if (fn.length < 2) { - save(file.getParent().resolve(fn[0] + ".png")); + return save(file.getParent().resolve(fn[0] + ".png")); } else { ImageIO.write(image, fn[fn.length - 1].toUpperCase(), Files.newOutputStream(file)); + return this; } } @@ -776,8 +704,8 @@ public class Picture { * * @param file Neuer Dateipfad */ - public void save(String file) throws IOException { - save(Paths.get(".").toAbsolutePath().normalize().resolve(file)); + public Picture save(String file) throws IOException { + return save(Paths.get(".").toAbsolutePath().normalize().resolve(file)); } // ----------------------------------------- Sonstiges ----------------------------------------------- @@ -804,7 +732,7 @@ public class Picture { * * @param pixel zweidimensionales Array von Color-Objekten */ - public void setPixelArray(Color[][] pixel) { + public Picture setPixelArray(Color[][] pixel) { size(pixel.length, pixel[0].length); for (int x = 0; x < image.getWidth(); x++) { @@ -814,18 +742,6 @@ public class Picture { } } repaint(); - } - - /** - * Hilfsfunktion zum Verzoegern der Ausgabe - * - * @param millis Wartezeit in Millisekunden - */ - public void delay(int millis) { - try { - Thread.sleep(millis); - } catch (Exception e) { - System.out.println("Fehler beim Verzoegern der Ausgabe"); - } + return this; } } diff --git a/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/util/PictureViewer.java b/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/util/PictureViewer.java deleted file mode 100644 index 4bee87f..0000000 --- a/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/util/PictureViewer.java +++ /dev/null @@ -1,220 +0,0 @@ -package io.gitlab.jfronny.ImgJava.util; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.MouseWheelEvent; -import java.awt.event.MouseWheelListener; -import java.awt.image.BufferedImage; -import java.util.Vector; - -/** - * 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 PictureViewer extends JFrame implements MouseWheelListener { - public static final int FIT = -1; - public static final int NORMAL = 1; - - private static final int ANZ_BACK = 0; - protected Picture picture = null; - private double zoom; - private final Vector history; - private final JLabel imagePane = new JLabel(); - private final JScrollPane scrollPane; - // private boolean antialiasing; - - /** - * Erzeugt ein ScrollPanel der Größe 500x400 - */ - public PictureViewer() { - this(800, 500); - } - - /** - * Erzeugt ein ScrollPanel der angegebenen Größe - * - * @param width Breite des Bildes - * @param height Höhe des Bildes - */ - public PictureViewer(int width, int height) { - this(new Picture(width, height)); - } - - public PictureViewer(Picture p) { - picture = p; - picture.setObserver(this); - this.history = new Vector(); - this.zoom = NORMAL; - setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); - Container cp = getContentPane(); - cp.setLayout(new BorderLayout()); - imagePane.setPreferredSize(new Dimension(p.getWidth(), p.getHeight())); - 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); - - repaint(); - - Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); - int x = (d.width - getSize().width); - //int x = 0; - int y = 0; - setLocation(x, y); - - scrollPane.addMouseWheelListener(this); - } - - /** - * Speichert das übergebene Bild in der History. - * - * @param b zu speicherndes Bild - */ - public void pushImage() { - if (ANZ_BACK > 0) { - if (history.size() == ANZ_BACK) { - history.removeElementAt(0); - } - - BufferedImage b = new BufferedImage(picture.getWidth(), picture.getHeight(), picture.getImage().getType()); - Graphics g = b.getGraphics(); - g.drawImage(picture.getImage(), 0, 0, null); - g.dispose(); - - history.add(b); - } - } - - /** - * Ruft das letzte abgespeicherte Bild aus der History wieder auf. - */ - private void popImage() { - int anz = history.size(); - if (anz > 0) { - BufferedImage i = history.get(anz - 1); - history.removeElementAt(anz - 1); - picture.setImage(i); - repaint(); - } - } - - /** - * Ruft das letzte abgespeicherte Bild aus der History wieder auf. - */ - public void back() { - popImage(); - } - - /** - * 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 factor 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(); - } - - // public void setAntialiasing(boolean antialiasing) { - // this.antialiasing = antialiasing; - // } - - /** - * Setzt die automatische Neuanzeige des Bildes. - * Mit dieser Methode kann man einstellen, ob nach jedem Zeichenbefehl - * die Anzeige auf dem Bildschirm aktualisiert werden soll. Bei sehr - * vielen Zeichenbefehlen wird die Ausgabe dadurch sehr langsam. Es reicht - * eine Anzeige am Ende der Zeichenbefehle. Rufen Sie dann für das Neuzeichnen - * die Methode refresh() auf. - * - * @param autoRefresh true, wenn nach jedem Zeichenbefehl die Anzeige aktualisiert werden soll. - */ - public void setAutoRefresh(boolean autoRefresh) { - picture.setAutoRefresh(autoRefresh); - } - - /** - * Sorgt für die Aktualisierung der Bildschrimanzeige. Das aktuelle Bild - * wird dadurch angezeigt. Durch Einstellung von autoRefresh kann die - * Anzeige automatisiert werden. - */ - public void refresh() { - repaint(); - } - - /** - * Passt die Framegröße an das anzuzeigende Bild an. - */ - public void resize() { - int pref_x = (int) (picture.getWidth() * zoom); - int pref_y = (int) (picture.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. - */ - - public void repaint() { - double faktor = zoom; - - if (zoom == FIT) { - double faktorw = (double) imagePane.getWidth() / picture.getWidth(); - double faktorh = (double) imagePane.getHeight() / picture.getHeight(); - faktor = Math.min(faktorw, faktorh); - } - int disp_width = (int) (picture.getWidth() * faktor); - int disp_height = (int) (picture.getHeight() * faktor); - - BufferedImage image = new BufferedImage(disp_width, disp_height, BufferedImage.TYPE_INT_ARGB); - Graphics2D g = (Graphics2D) image.getGraphics(); - - if (picture.isAntialiasing()) { - picture.antialise(); - } else g.getRenderingHints().clear(); - - g.drawImage(picture.getImage(), 0, 0, disp_width, disp_height, 0, 0, picture.getWidth(), picture.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(); - - } - - /** - * Setzt ZoomFaktor über MouseWheel - */ - public void mouseWheelMoved(MouseWheelEvent e) { - int notches = e.getWheelRotation(); - if (notches < 0) { - setZoom(zoom * 1.1); - } else { - setZoom(zoom * 1.0 / 1.1); - } - } -}