("test") {
+ useJUnitPlatform()
+}
\ No newline at end of file
diff --git a/ImgJava/cum.png b/ImgJava/cum.png
new file mode 100644
index 0000000..7da097a
Binary files /dev/null and b/ImgJava/cum.png differ
diff --git a/ImgJava/gradle/wrapper/gradle-wrapper.jar b/ImgJava/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..e708b1c
Binary files /dev/null and b/ImgJava/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/ImgJava/gradle/wrapper/gradle-wrapper.properties b/ImgJava/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..da9702f
--- /dev/null
+++ b/ImgJava/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/ImgJava/gradlew b/ImgJava/gradlew
new file mode 100644
index 0000000..4f906e0
--- /dev/null
+++ b/ImgJava/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/ImgJava/gradlew.bat b/ImgJava/gradlew.bat
new file mode 100644
index 0000000..107acd3
--- /dev/null
+++ b/ImgJava/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/ImgJava/settings.gradle.kts b/ImgJava/settings.gradle.kts
new file mode 100644
index 0000000..a473dd9
--- /dev/null
+++ b/ImgJava/settings.gradle.kts
@@ -0,0 +1,2 @@
+rootProject.name = "ImgJava"
+
diff --git a/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/Main.java b/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/Main.java
new file mode 100644
index 0000000..b9398d8
--- /dev/null
+++ b/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/Main.java
@@ -0,0 +1,16 @@
+package io.gitlab.jfronny.ImgJava;
+
+import io.gitlab.jfronny.ImgJava.imageProcessing.ImageUtil;
+import io.gitlab.jfronny.ImgJava.util.Picture;
+
+import java.io.IOException;
+
+public class Main {
+ public static void main(String[] args) {
+ try {
+ ImageUtil.mirror(new Picture("iris.jpg")).save("cum.png");
+ } 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
new file mode 100644
index 0000000..d1cbee5
--- /dev/null
+++ b/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/imageProcessing/ImageUtil.java
@@ -0,0 +1,38 @@
+package io.gitlab.jfronny.ImgJava.imageProcessing;
+
+import io.gitlab.jfronny.ImgJava.util.Picture;
+
+import java.awt.*;
+
+/**
+ * Algorithmen zur Änderung der Pixelpositionen eines Pictures
+ * z.B. drehen, spiegeln usw.
+ *
+ * @author Thomas Schaller
+ * @version 1.1 (28.11.2019)
+ */
+public class ImageUtil {
+ /**
+ * spiegeleHorizontal spiegelt das Bild, so dass rechts und links getauscht werden
+ *
+ * @param originalbild Ein Bild (Picture), das gespiegelt werden soll
+ * @return Eine gespiegelte Kopie des Bildes
+ */
+ public static Picture mirror(Picture originalbild) {
+ int breite = originalbild.getWidth();
+ int hoehe = originalbild.getHeight();
+
+ Color[][] pixel = originalbild.getPixelArray();
+ Color[][] pixelNeu = new Color[breite][hoehe];
+
+ for (int x = 0; x < breite; x++) {
+ for (int y = 0; y < hoehe; y++) {
+ pixelNeu[x][y] = pixel[(breite - 1) - x][y];
+ }
+ }
+
+ Picture neuesBild = new Picture();
+ neuesBild.setPixelArray(pixelNeu);
+ return neuesBild;
+ }
+}
diff --git a/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/util/HSB.java b/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/util/HSB.java
new file mode 100644
index 0000000..80e28f5
--- /dev/null
+++ b/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/util/HSB.java
@@ -0,0 +1,31 @@
+package io.gitlab.jfronny.ImgJava.util;
+
+import java.awt.*;
+
+
+/**
+ * Write a description of class PixelColor here.
+ *
+ * @author (your name)
+ * @version (a version number or a date)
+ */
+public class HSB {
+ public static double getHue(Color c) {
+ float[] hsb = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null);
+ return hsb[0];
+ }
+
+ public static double getSaturation(Color c) {
+ float[] hsb = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null);
+ return hsb[1];
+ }
+
+ public static double getBrightness(Color c) {
+ float[] hsb = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null);
+ return hsb[2];
+ }
+
+ public static Color getColor(double h, double s, double b) {
+ return new Color(Color.HSBtoRGB((float) h, (float) s, (float) b));
+ }
+}
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
new file mode 100644
index 0000000..500b18b
--- /dev/null
+++ b/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/util/Picture.java
@@ -0,0 +1,831 @@
+package io.gitlab.jfronny.ImgJava.util;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * Bildklasse fuer die Simulation von Processing-Befehlen
+ *
+ * Diese Klasse stellt ein BufferedImage bereit, in das mit Processing-Befehlen gezeichnet
+ * werden kann.
+ * Zusaetzlich kann ein Bildanzeiger ueber jede Aenderung des Bildes informiert werden,
+ * um "Zurueck"-Befehle zu ermoeglichen. Der Bildanzeiger ist entweder eine normale Java
+ * ScrollPane oder ein Actor aus Greenfoot.
+ * Die Dokumentation der einzelnen Zeichenmethoden ist der Processing-Reference
+ * (https://processing.org/reference/ steht unter CC-Lizenz: https://creativecommons.org/)
+ * entnommen und mit Deepl.com ins Deutsche uebersetzt.
+ *
+ * @author Thomas Schaller (ZPG Informatik Klasse 9)
+ * @version 1.2 from 06.12.2019
+ */
+
+public class Picture {
+
+ // Einstellungmoeglichkeiten fuer das Zeichnen von Rechtecken und Ellipsen
+ // RADIUS = Mittelpunkt+Radius wird gegeben, CENTER = Mittelpunkt und Breite/Hoehe wird gegeben,
+ // CORNER = Linke obere Ecke + Breite/Hoehe, CORNERS = Linke obere und rechte untere Ecke
+ public static final int RADIUS = 1;
+ public static final int CENTER = 2;
+ public static final int CORNER = 3;
+ public static final int CORNERS = 4;
+
+ // gespeichertes Bild,
+ private BufferedImage image;
+ private Graphics2D g;
+ private boolean antialiasing;
+
+ // aktuelle Farbeinstellungen
+ private Color background;
+ private Color pencolor;
+ private Color fillcolor;
+
+ // aktuelle Stiftdicke
+ private double stroke;
+
+ // aktueller Koordinatenmodus von Rechtecken und Ellipsen
+ private int ellipseMode = CENTER;
+ private int rectMode = CORNER;
+
+ // aktueller Font
+ private Font textfont = null;
+
+ // muss ein Bildanzeiger benachrichtigt werden
+ private PictureViewer observer = null;
+ private boolean autorefresh = true;
+
+ /**
+ * Erzeugt ein Bild mit Standardgroesse 500x400
+ */
+ public Picture() {
+ this(500, 400);
+ }
+
+ /**
+ * Erzeugt ein Bild der angegeben Groesse
+ *
+ * @param width Breite des Bildes
+ * @param height Hoehe des Bildes
+ */
+ public Picture(int width, int height) {
+ this(width, height, "D0D0D0");
+ }
+
+ /**
+ * Erzeugt ein Bild aus einer Datei
+ *
+ * @param file Dateiname des Bildes
+ */
+ public Picture(Path file) throws IOException {
+ this.antialiasing = true;
+ load(file);
+ showInFrame();
+ }
+
+ /**
+ * Erzeugt ein Bild aus einer Ressource im images/ Ordner
+ *
+ * @param resourceName Name der Ressource
+ */
+ public Picture(String resourceName) throws IOException {
+ this.antialiasing = true;
+ loadResource("images/" + resourceName);
+ showInFrame();
+ }
+
+ /**
+ * Erzeugt ein Bild der angegebenen Groesse mit festgelegtem Hintergrund
+ *
+ * @param width Breite des Bildes
+ * @param height Hoehe des Bildes
+ * @param background Farbe des Hintergrunds
+ */
+ public Picture(int width, int height, String background) {
+ this.antialiasing = true;
+ this.background = decode(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.setColor(this.background);
+ g.fillRect(0, 0, width - 1, height - 1);
+ }
+
+ protected void antialise() {
+ // Antialiasing
+ g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ // Rendering
+ g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+ // Text
+ 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;
+ }
+
+ /**
+ * Legt fest, wer das Bild anzeigt.
+ * Diese ermoeglicht die Benachrichtung des Observers, wenn sich das Bild aendert.
+ *
+ * @param observer Anzeiger des Bildes
+ */
+ public void setObserver(PictureViewer observer) {
+ this.observer = observer;
+ }
+
+ /**
+ * Direktes Abfragen des Bildes (fuer interne Zwecke)
+ *
+ * @return Bild, das gerade gespeichert ist.
+ */
+ public BufferedImage getImage() {
+ return image;
+ }
+
+ /**
+ * Direktes Setzen des Bildes (fuer interne Zwecke)
+ *
+ * @param b Bild, das gespeichert werden soll.
+ */
+ public void setImage(BufferedImage b) {
+ image = b;
+ }
+
+ /**
+ * Definiert die Dimension der Breite und Hoehe des Anzeigefensters in Pixeleinheiten.
+ * Die eingebauten Variablen Breite und Hoehe werden durch die an diese Funktion uebergebenen Parameter festgelegt. So weist beispielsweise
+ * der Befehl size(640, 480) der Variablen Breite 640 und der Variablen Hoehe 480 zu.
+ *
+ * @param width Breite des Bildes
+ * @param height Hoehe des Bildes
+ */
+ public void size(int width, int height) {
+ pushImage();
+ makeImage(width, height);
+
+ g.setColor(background);
+ g.fillRect(0, 0, width - 1, height - 1);
+ if (observer != null) observer.resize();
+ repaint();
+ }
+
+ /**
+ * Liefert die Breite des Bildes zurueck.
+ *
+ * @return Breite des Bildes
+ */
+ public int getWidth() {
+ return image.getWidth();
+ }
+
+ /**
+ * Liefert die Hoehe des Bildes zurueck.
+ *
+ * @return Hoehe des Bildes
+ */
+ public int getHeight() {
+ 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
+ * das Zeichnen aufwaendiger Bilder und verhindert "Flackern".
+ * Das Neuzeichnen kann durch die Methode "refresh" gezielt ausgeloest werden.
+ *
+ * @param autoRefresh true = nach jedem Zeichenbefehl die Anzeige aktualisieren, false= nur durch die Methode refresh neu zeichnen
+ */
+ public void setAutoRefresh(boolean autoRefresh) {
+ this.autorefresh = autoRefresh;
+ }
+
+ /**
+ * Auch die anzeigenden Klasse wird zum Neuzeichnen aufgefordert.
+ */
+ private void repaint() {
+ if (observer != null && autorefresh) {
+ observer.repaint();
+ }
+ }
+
+ /**
+ * Ein repaint() (das Neuzeichnen) kann manuell erzwungen werden.
+ */
+ public void forceRepaint() {
+ if (observer != null) {
+ observer.repaint();
+ }
+ }
+
+ // ----------------------------------------- Zeichenfunktionen -----------------------------------------------
+
+ /**
+ * Loescht den Inhalt des Bildes.
+ * Der Hintergrund wird mit der Hintergrundfarbe neu gefuellt.
+ */
+
+ public void clear() {
+ pushImage();
+ makeImage(image.getWidth(), image.getHeight());
+
+ g.setColor(background);
+ g.fillRect(0, 0, image.getWidth() - 1, image.getHeight() - 1);
+ repaint();
+ }
+
+ /**
+ * Konvertiert die in einem bestimmten Modus gegebenen Koordinaten in die Java-uebliche Links_Oben_Breite_Hoehe Version
+ * Die Aenderungen werden direkt im Array vorgenommen
+ *
+ * @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) {
+ switch (mode) {
+ case CORNER:
+ break;
+ case CORNERS:
+ coord[2] -= coord[0];
+ coord[3] -= coord[1];
+ break;
+ case RADIUS:
+ coord[2] *= 2;
+ coord[3] *= 2;
+ case CENTER:
+ coord[0] -= coord[2] / 2;
+ coord[1] -= coord[3] / 2;
+ }
+ }
+
+ /**
+ * Aendert den Koordinaten-Modus beim Zeichnen von Rechtecken.
+ * Aendert die Position, von der aus Rechtecke gezeichnet werden, indem es die Art und Weise aendert, wie Parameter, die an rect() uebergeben werden, interpretiert werden.
+ * Der Standardmodus ist rectMode(Bild.CORNER), der die ersten beiden Parameter von rect() als die linke obere Ecke der Form interpretiert,
+ * waehrend der dritte und vierte Parameter seine Breite und Hoehe sind.
+ * rectMode(Bild.CORNERS) interpretiert die ersten beiden Parameter von rect() als die Position einer Ecke
+ * und die dritten und vierten Parameter als die Position der gegenueberliegenden Ecke.
+ * rectMode(Bild.CENTER) interpretiert die ersten beiden Parameter von rect() als Mittelpunkt der Form,
+ * waehrend der dritte und vierte Parameter seine Breite und Hoehe sind.
+ * rectMode(RADIUS) verwendet auch die ersten beiden Parameter von rect() als Mittelpunkt der Form,
+ * verwendet aber den dritten und vierten Parameter, um die Haelfte der Breite und Hoehe der Formen festzulegen.
+ *
+ * @param mode Modus der Koordinateninterpretation (CORNER, CORNERS, CENTER oder RADIUS)
+ */
+ public void rectMode(int mode) {
+ rectMode = mode;
+ }
+
+ /**
+ * Aendert den Koordinaten-Modus beim Zeichnen von Kreisen/Ellipsen.
+ * Aendert die Position, von der aus Kreise/Ellipsen gezeichnet werden, indem es die Art und Weise aendert, wie Parameter, die an ellipse() uebergeben werden, interpretiert werden.
+ * Der Standardmodus ist ellipseMode(Bild.CENTER), der die ersten beiden Parameter von ellipse() als Mittelpunkt der Form interpretiert,
+ * waehrend der dritte und vierte Parameter seine Breite und Hoehe sind.
+ * ellipseMode(Bild.CORNER) interpretiert die ersten beiden Parameter von ellipse() als die Position einer Ecke
+ * und die dritten und vierten Parameter als Breite und Hoehe der Form.
+ * ellipseMode(Bild.CORNERS) interpretiert die ersten beiden Parameter von ellipse() als die Position einer Ecke
+ * und die dritten und vierten Parameter als die Position der gegenueberliegenden Ecke.
+ * ellipseMode(RADIUS) verwendet auch die ersten beiden Parameter von ellipse() als Mittelpunkt der Form,
+ * verwendet aber den dritten und vierten Parameter, um die Haelfte der Breite und Hoehe der Formen festzulegen.
+ *
+ * @param mode Modus der Koordinateninterpretation (CORNER, CORNERS, CENTER oder RADIUS)
+ */
+ public void ellipseMode(int mode) {
+ ellipseMode = mode;
+ }
+
+ /**
+ * Zeichnet eine Linie (einen direkten Weg zwischen zwei Punkten) auf den Bildschirm.
+ * Um eine Linie einzufaerben, verwenden Sie die {@link #stroke(int, int, int) stroke()} Funktion. Eine Zeile kann nicht gefuellt werden, daher hat die Funktion fill() keinen
+ * Einfluss auf die Farbe einer Zeile. Linien werden standardmaessig mit einer Breite von einem Pixel gezeichnet, dies kann jedoch mit der Funktion
+ * {@link #strokeWeight(double) strokeWeight()} geaendert werden.
+ *
+ * @param x1 x-Koordinate des 1. Punktes
+ * @param y1 y-Koordinate des 1. Punktes
+ * @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();
+
+ if (stroke > 0) {
+ g.setColor(pencolor);
+ g.setStroke(new BasicStroke((float) stroke));
+ // if(antialiasing) antialise();
+ g.drawLine(x1, y1, x2, y2);
+ }
+ repaint();
+ }
+
+ /**
+ * Zeichnet ein Rechteck auf das Bild.
+ * Standardmaessig legen die ersten beiden Parameter die Position der linken oberen Ecke fest, der dritte die Breite und der vierte die Hoehe.
+ * Die Art und Weise, wie diese Parameter interpretiert werden, kann jedoch mit der Funktion {@link #rectMode(int) rectMode()} geaendert werden.
+ * Durch den Befehl {@link #fill(int, int, int) fill()} /{@link #noFill() noFill()} kann die Fuellfarbe des Rechtecks gewaehlt werden, durch {@link #stroke(int, int, int) stroke()}/{@link #noStroke() noStroke()} die Rahmenfarbe.
+ *
+ * @param a meist die x-Koordinate der linken oberen Ecke (kann durch rectMode() geaendert werden).
+ * @param b meist die y-Koordinate der linken oberen Ecke (kann durch rectMode() geaendert werden).
+ * @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();
+
+ int[] coord = {a, b, c, d};
+ convert(coord, rectMode);
+ if (fillcolor != null) {
+ g.setColor(fillcolor);
+ g.fillRect(coord[0], coord[1], coord[2], coord[3]);
+ }
+ if (pencolor != null) {
+ g.setColor(pencolor);
+ g.setStroke(new BasicStroke((float) stroke));
+ g.drawRect(coord[0], coord[1], coord[2], coord[3]);
+ }
+ repaint();
+ }
+
+ /**
+ * Zeichnet eine Ellipse/Kreis auf das Bild.
+ * Standardmaessig legen die ersten beiden Parameter die Position des Mittelpunkts fest, der dritte die Breite und der vierte die Hoehe.
+ * Die Art und Weise, wie diese Parameter interpretiert werden, kann jedoch mit der Funktion {@link #ellipseMode(int) ellipseMode()} geaendert werden.
+ * Durch den Befehl {@link #fill(int, int, int) fill()} /{@link #noFill() noFill()} kann die Fuellfarbe des Rechtecks gewaehlt werden, durch {@link #stroke(int, int, int) stroke()}/{@link #noStroke() noStroke()} die Rahmenfarbe.
+ *
+ * @param a meist die x-Koordinate des Mittelpunkts (kann durch ellipseMode() geaendert werden).
+ * @param b meist die y-Koordinate des Mittelpunkts (kann durch ellipseMode() geaendert werden).
+ * @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();
+
+ int[] coord = {a, b, c, d};
+ convert(coord, ellipseMode);
+ if (fillcolor != null) {
+ g.setColor(fillcolor);
+ g.fillOval(coord[0], coord[1], coord[2], coord[3]);
+ }
+ if (pencolor != null) {
+ g.setColor(pencolor);
+ g.setStroke(new BasicStroke((float) stroke));
+ // if(antialiasing) antialise();
+ g.drawOval(coord[0], coord[1], coord[2], coord[3]);
+ }
+ repaint();
+ }
+
+ /**
+ * Zeichnet ein Dreieck auf das Bild.
+ * Ein Dreieck ist eine Ebene, die durch die Verbindung von drei Punkten entsteht. Die ersten beiden Argumente spezifizieren den
+ * ersten Punkt, die mittleren beiden Argumente spezifizieren den zweiten Punkt und die letzten beiden Argumente spezifizieren den dritten Punkt.
+ * Durch den Befehl {@link #fill(int, int, int) fill()} /{@link #noFill() noFill()} kann die Fuellfarbe des Rechtecks gewaehlt werden, durch {@link #stroke(int, int, int) stroke()}/{@link #noStroke() noStroke()} die Rahmenfarbe.
+ *
+ * @param x1 meist die x-Koordinate des 1. Punkts.
+ * @param y1 meist die y-Koordinate des 1. Punkts.
+ * @param x2 meist die x-Koordinate des 2. Punkts.
+ * @param y2 meist die y-Koordinate des 2. Punkts.
+ * @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) {
+ int[] px = {x1, x2, x3};
+ int[] py = {y1, y2, y3};
+ polygon(px, py);
+ }
+
+ /**
+ * Zeichnet ein Viereck auf das Bild.
+ * Ein Viereck ist ein vierseitiges Polygon. Es ist aehnlich wie ein Rechteck, aber die Winkel zwischen seinen Kanten
+ * sind nicht auf neunzig Grad beschraenkt. Das erste Paar von Parametern (x1,y1) setzt den ersten Scheitelpunkt und die nachfolgenden
+ * Paare sollten im Uhrzeigersinn oder gegen den Uhrzeigersinn um die definierte Form herum verlaufen.
+ * Durch den Befehl {@link #fill(int, int, int) fill()} /{@link #noFill() noFill()} kann die Fuellfarbe des Rechtecks gewaehlt werden, durch {@link #stroke(int, int, int) stroke()}/{@link #noStroke() noStroke()} die Rahmenfarbe.
+ *
+ * @param x1 meist die x-Koordinate des 1. Punkts.
+ * @param y1 meist die y-Koordinate des 1. Punkts.
+ * @param x2 meist die x-Koordinate des 2. Punkts.
+ * @param y2 meist die y-Koordinate des 2. Punkts.
+ * @param x3 meist die x-Koordinate des 3. Punkts.
+ * @param y3 meist die y-Koordinate des 3. Punkts.
+ * @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) {
+ int[] px = {x1, x2, x3, x4};
+ int[] py = {y1, y2, y3, y4};
+ polygon(px, py);
+ }
+
+ /**
+ * Zeichnet ein Polygon auf das Bild.
+ * Gleich lange Listen von x und y-Koordinaten bestimmen die Eckpunkte des Polygons.
+ * Durch den Befehl {@link #fill(int, int, int) fill()} /{@link #noFill() noFill()} kann die Fuellfarbe des Rechtecks gewaehlt werden, durch {@link #stroke(int, int, int) stroke()}/{@link #noStroke() noStroke()} die Rahmenfarbe.
+ *
+ * @param x Liste der x-Koordinaten der Punkte.
+ * @param y Liste der y-Koordinaten der Punkte.
+ */
+
+ public void polygon(int[] x, int[] y) {
+ pushImage();
+
+ if (fillcolor != null) {
+ g.setColor(fillcolor);
+ g.fillPolygon(x, y, y.length);
+ }
+ if (pencolor != null) {
+ g.setColor(pencolor);
+ g.setStroke(new BasicStroke((float) stroke));
+ // if(antialiasing) antialise();
+ g.drawPolygon(x, y, x.length);
+ }
+ repaint();
+ }
+
+ /**
+ * Zeichnet einen Punkt, d.h. einen Kreis in der Dimension eines Pixels.
+ * Der erste Parameter ist der x-Wert fuer den Punkt, der zweite Wert ist der y-Wert fuer den Punkt.
+ *
+ * @param x x-Koordinate des Punktes
+ * @param y y-Koordinate des Punktes
+ */
+ public void point(int x, int y) {
+ ellipse(x, y, 1, 1);
+ }
+
+ // ----------------------------------------- Schriftdarstellung -----------------------------------------------
+
+ /**
+ * Gibt einen Text an den gegebenen Koordinaten aus
+ * Zur Ausgabe des Textes wird der ausgewaehlte Font verwendet. Dieser muss vorher mit {@link #textFont(Font) textFont() } festgelegt.
+ *
+ * @param s Text, der angezeigt werden soll
+ * @param x x-Koordinate des Textanfangs
+ * @param y y-Koordinate der Grundlinie des Textes.
+ */
+ public void text(String s, int x, int y) {
+ pushImage();
+
+ if (pencolor != null) {
+ if (fillcolor == null)
+ g.setColor(Color.black);
+ else
+ g.setColor(fillcolor);
+ g.setStroke(new BasicStroke((float) stroke));
+ g.setFont(textfont);
+ // if(antialiasing)g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+ g.drawString(s, x, y);
+ }
+ repaint();
+ }
+
+ /**
+ * Legt die Schriftart fuer Textausgaben fest.
+ * Jeder uebliche Java-Font kann verwendet werden. Er kann mit z.B. Font f = new Font( "Arial", Font.PLAIN, 14 ); definiert werden.
+ *
+ * @param font ein Font-Objekt
+ */
+ public void textFont(Font font) {
+ this.textfont = font;
+ }
+
+ // ----------------------------------------- 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.
+ * Diese Farbe wird hexadezimal in Form der RGB angegeben: z.B. "CCFFAA" oder "004E23". Die Syntax verwendet sechs Ziffern - je zwei fuer die roten, gruenen und blauen Komponenten,
+ * um eine Farbe anzugeben (genau wie Farben typischerweise in HTML und CSS angegeben werden).
+ *
+ * @param pencolor Stiftfarbe in Hexadezimaldarstellung
+ */
+ public void stroke(String pencolor) {
+ this.pencolor = decode(pencolor);
+ }
+
+ /**
+ * Legt die Farbe fest, mit der Linien und Raender um Formen gezeichnet werden.
+ * Diese Farbe wird entweder als Graustufe (0-255) oder als 3-Byte RGB-Wert angegeben
+ *
+ * @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);
+ }
+
+ /**
+ * Legt die Farbe fest, mit der Linien und Raender um Formen gezeichnet werden.
+ * Diese Farbe wird komponentenweise als RGB-Wert angegeben
+ *
+ * @param r Rotanteil (0-255) der Stiftfarbe
+ * @param g Gruenanteil (0-255) der Stiftfarbe
+ * @param b Blauanteil (0-255) der Stiftfarbe
+ */
+ public void stroke(int r, int g, int b) {
+ this.pencolor = new Color(r, g, b);
+ }
+
+ /**
+ * Legt fest, dass keine Linien oder Raender um Formen gezeichnet werden soll.
+ */
+ public void noStroke() {
+ this.pencolor = null;
+ }
+
+ /**
+ * Legt die Breite des Strichs fuer Linien, Punkte und den Rand um Formen fest.
+ * Alle Breiten werden in Pixeleinheiten angegeben.
+ *
+ * @param width Breite in Pixel
+ */
+ public void strokeWeight(double width) {
+ this.stroke = width;
+ }
+
+ /**
+ * Legt die Farbe fest, mit der Formen gefuellt werden.
+ * Diese Farbe wird hexadezimal in Form der RGB angegeben: z.B. "CCFFAA" oder "004E23". Die Syntax verwendet sechs Ziffern - je zwei fuer die roten, gruenen und blauen Komponenten,
+ * um eine Farbe anzugeben (genau wie Farben typischerweise in HTML und CSS angegeben werden).
+ *
+ * @param fillcolor Fuellfarbe in Hexadezimaldarstellung
+ */
+ public void fill(String fillcolor) {
+ this.fillcolor = decode(fillcolor);
+ }
+
+ /**
+ * Legt die Farbe fest, mit der Formen gefuellt werden.
+ * Diese Farbe wird entweder als Graustufe (0-255) oder als 3-Byte RGB-Wert angegeben.
+ *
+ * @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);
+ }
+
+ /**
+ * Legt die Farbe fest, mit der Formen gefuellt werden.
+ * Diese Farbe wird komponentenweise als RGB-Wert angegeben.
+ *
+ * @param r Rotanteil (0-255) der Fuellfarbe
+ * @param g Gruenanteil (0-255) der Fuellfarbe
+ * @param b Blauanteil (0-255) der Fuellfarbe
+ */
+ public void fill(int r, int g, int b) {
+ this.fillcolor = new Color(r, g, b);
+ }
+
+ /**
+ * Legt fest, dass die Formen nicht gefuellt werden sollen.
+ */
+ public void noFill() {
+ this.fillcolor = null;
+ }
+
+ /**
+ * Die Funktion background() setzt die Farbe, die fuer den Hintergrund des Bildes verwendet wird. Der Standardhintergrund ist hellgrau.
+ * Es ist nicht moeglich, den Alpha-Parameter Transparenz mit Hintergrundfarben auf der Hauptzeichnungsoberflaeche zu verwenden.
+ *
+ * @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) {
+ 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.clear();
+ }
+
+ /**
+ * Die Funktion background() setzt die Farbe, die fuer den Hintergrund des Bildes verwendet wird. Der Standardhintergrund ist hellgrau.
+ * Es ist nicht moeglich, den Alpha-Parameter Transparenz mit Hintergrundfarben auf der Hauptzeichnungsoberflaeche zu verwenden.
+ *
+ * @param r Rotanteil (0-255) der Hintergrundfarbe
+ * @param g Gruenanteil (0-255) der Hintergrundfarbe
+ * @param b Blauanteil (0-255) der Hintergrundfarbe
+ */
+ public void background(int r, int g, int b) {
+ this.background = new Color(r, g, b);
+ this.clear();
+ }
+
+ /**
+ * Die Funktion background() setzt die Farbe, die fuer den Hintergrund des Bildes verwendet wird. Der Standardhintergrund ist hellgrau.
+ * Es ist nicht moeglich, den Alpha-Parameter Transparenz mit Hintergrundfarben auf der Hauptzeichnungsoberflaeche zu verwenden.
+ *
+ * @param hex String Farbe in Hexadezimalangabe
+ */
+ public void background(String hex) {
+ this.background = decode(hex);
+ this.clear();
+ }
+
+ // ----------------------------------------- Dateioperationen -----------------------------------------------
+
+ /**
+ * Laedt ein Bild aus dem Dateisystem.
+ * Laedt ein Bild von einem Datentraeger und setzt Stiftfarbe und Fuellfarbe auf Standardwerte zurueck.
+ *
+ * @param file Dateipfad
+ */
+ public void load(String file) throws IOException {
+ load(Files.newInputStream(Paths.get(".").toAbsolutePath().normalize().resolve(file)));
+ }
+
+ /**
+ * Laedt ein Bild aus dem Dateisystem.
+ * Laedt ein Bild von einem Datentraeger und setzt Stiftfarbe und Fuellfarbe auf Standardwerte zurueck.
+ *
+ * @param file Dateipfad
+ */
+ public void load(Path file) throws IOException {
+ load(Files.newInputStream(file));
+ }
+
+ /**
+ * Laedt ein Bild aus dem Dateisystem.
+ * Laedt ein Bild von einem Datentraeger und setzt Stiftfarbe und Fuellfarbe auf Standardwerte zurueck.
+ *
+ * @param stream Bildquelle
+ */
+ public void load(InputStream stream) throws IOException {
+ this.image = ImageIO.read(stream);
+ this.g = (Graphics2D) image.getGraphics();
+ this.background = decode("D0D0D0");
+ this.pencolor = new Color(0, 0, 0);
+ this.fillcolor = null;
+ this.stroke = 1;
+ if (observer != null) observer.resize();
+ this.repaint();
+ }
+
+ /**
+ * Laedt ein Bild aus einer Ressource.
+ *
+ * @param resource Ressourcenpfad
+ */
+ public void loadResource(String resource) throws IOException {
+ load(Thread.currentThread().getContextClassLoader().getResourceAsStream(resource));
+ }
+
+ /**
+ * Speichert ein Bild.
+ * Speichert ein Bild auf einem Datentraeger. Zulaessig sind die Dateiformate PNG und GIF. Die Dateiendung legt den Typ fest.
+ * Standardmaessig wird die Dateiendung .png ergaenzt, wenn keine angegeben ist.
+ *
+ * @param file Neuer Dateipfad
+ */
+ public void save(Path file) throws IOException {
+ String[] fn = file.getFileName().toString().split("\\.");
+ if (fn.length == 0) {
+ save(file.resolve("unnamed.png"));
+ }
+ else if (fn.length < 2) {
+ save(file.getParent().resolve(fn[0] + ".png"));
+ }
+ else {
+ ImageIO.write(image, fn[fn.length - 1].toUpperCase(), Files.newOutputStream(file));
+ }
+ }
+
+ /**
+ * Speichert ein Bild.
+ * Speichert ein Bild auf einem Datentraeger. Der Pfad ist relativ zum aktuellen.
+ * Standardmaessig wird die Dateiendung .png ergaenzt, wenn keine angegeben ist.
+ *
+ * @param file Neuer Dateipfad
+ */
+ public void save(String file) throws IOException {
+ save(Paths.get(".").toAbsolutePath().normalize().resolve(file));
+ }
+
+ // ----------------------------------------- Sonstiges -----------------------------------------------
+
+ /**
+ * Liefert das Bild als zweidimensionales Pixel-Array.
+ *
+ * @return zweidimensionales Array von Color-Objekten, die den Pixeln des Bildes entsprechen.
+ */
+
+ public Color[][] getPixelArray() {
+ Color[][] pixel = new Color[image.getWidth()][image.getHeight()];
+ for (int x = 0; x < image.getWidth(); x++) {
+ for (int y = 0; y < image.getHeight(); y++) {
+ pixel[x][y] = new java.awt.Color(image.getRGB(x, y));
+ }
+ }
+ return pixel;
+ }
+
+ /**
+ * Setzt das Bild neu auf Basis des Pixel-Arrays.
+ * Die Groesse des Bildes wird nicht automatisch an das Array angepasst.
+ *
+ * @param pixel zweidimensionales Array von Color-Objekten
+ */
+ public void setPixelArray(Color[][] pixel) {
+ size(pixel.length, pixel[0].length);
+
+ for (int x = 0; x < image.getWidth(); x++) {
+ for (int y = 0; y < image.getHeight(); y++) {
+ g.setColor(pixel[x][y]);
+ g.fillRect(x, y, 1, 1);
+ }
+ }
+ 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");
+ }
+ }
+}
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
new file mode 100644
index 0000000..4bee87f
--- /dev/null
+++ b/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/util/PictureViewer.java
@@ -0,0 +1,220 @@
+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);
+ }
+ }
+}
diff --git a/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/util/Table.java b/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/util/Table.java
new file mode 100644
index 0000000..37af253
--- /dev/null
+++ b/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/util/Table.java
@@ -0,0 +1,871 @@
+package io.gitlab.jfronny.ImgJava.util;
+
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jdom.output.Format;
+import org.jdom.output.XMLOutputter;
+
+import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Scanner;
+
+/**
+ * Die Klasse Table vereinfacht den Zugriff auf CSV-Dateien.
+ * Die Klassen Table und TableRow ermöglichen einen einfachen Zugriff auf tabellenbasierte
+ * Dokumente.
+ *
+ * @author Thomas Schaller
+ * @version 1.0 vom 01.02.2019
+ */
+public class Table {
+ // Standardtrennzeichen für Spalten
+ private static final char DEFAULT_SEPARATOR = ';';
+ // Standardmarkierung für Texte
+ private static final char DEFAULT_QUOTE = '"';
+ // Standardtrennzeichen für Dezimalzahlen
+ private static final char DEFAULT_COMMA = ',';
+
+ // mögliche Spaltentypen
+ private static final String UNKNOWN = "UNKOWN";
+ private static final String INT = "INTEGER";
+ private static final String DOUBLE = "DOUBLE";
+ private static final String FLOAT = "FLOAT";
+
+ // interne Verwaltung des Dokuments als JDOM-Document-Objekt
+ private Document doc;
+ // Verweis auf Element für Kopfzeile
+ private Element header;
+ // Ende Attribute
+
+ /**
+ * Erzeugt leeres Tabellen-Dokument.
+ */
+ public Table() {
+ this.doc = new Document();
+ doc.setRootElement(new Element("CSV-Data"));
+ this.header = new Element("Header");
+ doc.getRootElement().addContent(header);
+ }
+
+
+ /**
+ * Erzeugt Tabellen-Dokument aus einer CSV-Datei.
+ * Liest den Inhalt einer Datei und erstellt ein Tabellenobjekt mit seinen Werten.
+ * Wenn die Datei eine Kopfzeile enthält, fügen Sie "header" in den Parameter options ein. Wenn die Datei keine Kopfzeile hat,
+ * dann lassen Sie einfach die Option "header" weg.
+ * @param file Dateiname der CSV-Datei.
+ * @param options Geben Sie hier "header" an, wenn die Datei eine Kopfzeile enthält.
+ * @param separator Trennzeichen für Spalten (meist ';' oder ',' oder '\t' für Tab)
+ * @param quote Kennung für Texte (meist '"').
+ */
+ public Table(Path file, String options, char separator, char quote) throws IOException {
+ loadCSV(file, options, separator, quote);
+ }
+
+ /**
+ * Erzeugt Tabellen-Dokument aus einer CSV-Datei.
+ * Liest den Inhalt einer Datei und erstellt ein Tabellenobjekt mit seinen Werten (Separator = ';', Kennung für Text = '"').
+ * Wenn die Datei eine Kopfzeile enthält, fügen Sie "header" in den Parameter options ein. Wenn die Datei keine Kopfzeile hat,
+ * dann lassen Sie einfach die Option "header" weg.
+ * @param file Dateiname der CSV-Datei.
+ * @param options Geben Sie hier "header" an, wenn die Datei eine Kopfzeile enthält.
+ */
+ public Table(Path file, String options) throws IOException {
+ loadCSV(file, options);
+ }
+
+ /**
+ * Erzeugt Tabellen-Dokument aus einer CSV-Datei.
+ * Liest den Inhalt einer Datei ohne Kopfzeile und erstellt ein Tabellenobjekt mit seinen Werten (Separator = ';', Kennung für Text = '"').
+ * @param file Dateiname der CSV-Datei.
+ */
+ public Table(Path file) throws IOException {
+ loadCSV(file);
+ }
+
+ // Anfang Methoden
+
+ /**
+ * Liest den Inhalt einer CSV-Datei ohne Kopfzeile (Separator = ';', Kennung für Text = '"').
+ * @param file Dateiname der CSV-Datei.
+ */
+ public void loadCSV(Path file) throws IOException {
+ loadCSV(file, "");
+ }
+
+ /**
+ * Liest den Inhalt einer CSV-Datei (Separator = ';', Kennung für Text = '"').
+ * Wenn die Datei eine Kopfzeile enthält, fügen Sie "header" in den Parameter options ein. Wenn die Datei keine Kopfzeile hat,
+ * dann lassen Sie einfach die Option "header" weg.
+ * @param file Dateiname der CSV-Datei.
+ * @param options Geben Sie hier "header" an, wenn die Datei eine Kopfzeile enthält.
+ */
+ public void loadCSV(Path file, String options) throws IOException {
+ loadCSV(file, options, DEFAULT_SEPARATOR, DEFAULT_QUOTE);
+ }
+
+ /**
+ * Liest den Inhalt einer CSV-Datei.
+ * Wenn die Datei eine Kopfzeile enthält, fügen Sie "header" in den Parameter options ein. Wenn die Datei keine Kopfzeile hat,
+ * dann lassen Sie einfach die Option "header" weg.
+ * @param file Dateiname der CSV-Datei.
+ * @param options Geben Sie hier "header" an, wenn die Datei eine Kopfzeile enthält.
+ * @param separator Trennzeichen für Spalten (meist ';' oder ',' oder '\t' für Tab)
+ * @param quote Kennung für Texte (meist '"').
+ */
+ public void loadCSV(Path file, String options, char separator, char quote) throws IOException {
+ doc = new Document();
+ doc.setRootElement(new Element("CSV-Data"));
+ header = new Element("Header");
+ doc.getRootElement().addContent(header);
+ Scanner scanner = new Scanner(file);
+ if (options.toLowerCase().contains("header") && scanner.hasNext()) {
+ List entries = parseLine(scanner.nextLine(), separator, quote);
+ int i = 0;
+ for (String s : entries) {
+ Element entry = new Element("Column");
+ header.addContent(entry);
+ entry.setText(s);
+ entry.setAttribute("type", "unknown");
+ i++;
+ }
+ }
+
+ List cols = header.getChildren();
+
+ while (scanner.hasNext()) {
+ Element line = new Element("Row");
+ doc.getRootElement().addContent(line);
+ List entries = parseLine(scanner.nextLine(), separator, quote);
+ int i = 0;
+
+ for (String s : entries) {
+
+ if (i == cols.size()) {
+ Element entry = new Element("Column");
+ entry.setAttribute("type", "unknown");
+ header.addContent(entry);
+ cols = header.getChildren();
+ }
+
+ Element entry = new Element("Entry");
+ entry.setText(s);
+ line.addContent(entry);
+ i++;
+ }
+ }
+ scanner.close();
+ }
+
+ /**
+ * Speichert das aktuelle Dokument als CSV-Datei ohne Kopfzeile (Separator = ';', Kennung für Text = '"').
+ * @param file Dateiname der CSV-Datei.
+ */
+ public void saveCSV(Path file) throws IOException {
+ saveCSV(file, "");
+ }
+
+ /**
+ * Speichert das aktuelle Dokument als CSV-Datei (Separator = ';', Kennung für Text = '"').
+ * Wenn die Datei eine Kopfzeile enthalten, fügen Sie "header" in den Parameter options ein. Wenn die Datei keine Kopfzeile haben soll,
+ * dann lassen Sie einfach die Option "header" weg.
+ * @param options Geben Sie hier "header" an, wenn die Datei eine Kopfzeile haben soll.
+ * @param file Dateiname der CSV-Datei.
+ */
+ public void saveCSV(Path file, String options) throws IOException {
+ saveCSV(file, options, DEFAULT_SEPARATOR, DEFAULT_QUOTE);
+ }
+
+ /**
+ * Speichert das aktuelle Dokument als CSV-Datei.
+ * Wenn die Datei eine Kopfzeile enthalten, fügen Sie "header" in den Parameter options ein. Wenn die Datei keine Kopfzeile haben soll,
+ * dann lassen Sie einfach die Option "header" weg.
+ * @param options Geben Sie hier "header" an, wenn die Datei eine Kopfzeile haben soll.
+ * @param file Dateiname der CSV-Datei.
+ * @param separator Trennzeichen für Spalten (meist ';' oder ',' oder '\t' für Tab)
+ * @param quote Kennung für Texte (meist '"').
+ */
+ public void saveCSV(Path file, String options, char separator, char quote) throws IOException {
+ PrintStream outputFile = new PrintStream(Files.newOutputStream(file));
+ System.out.println("Speicher in : " + file.toAbsolutePath());
+ List columns = header.getChildren();
+ String sq = "" + quote;
+ String ss = "" + separator;
+ if (quote == '"') sq = "\"";
+ if (separator == '"') ss = "\"";
+
+ if (options.toLowerCase().contains("header")) {
+ String h = "";
+ for (Element c : columns) {
+ h += ss + sq + c.getText() + sq;
+ }
+ outputFile.println(h.substring(1));
+ }
+ for (int i = 0; i < getRowCount(); i++) {
+ String l = "";
+ for (String s : getStringRow(i)) {
+
+ if (s.contains("" + separator)) {
+ if (quote == '"' && s.contains("\"")) {
+ s = s.replace("\"", "\"\"");
+ }
+ l += ss + sq + s + sq;
+ } else {
+ l += ss + s;
+ }
+
+ }
+ outputFile.println(l.substring(1));
+ }
+ outputFile.close();
+ }
+
+ /** Speichert die Tabelle als XML-Dokument.
+ * @param file Dateiname des XML-Files
+ */
+ public void saveXML(Path file) throws IOException {
+ // new XMLOutputter().output(doc, System.out);
+ XMLOutputter xmlOutput = new XMLOutputter();
+
+ // display nice nice
+ xmlOutput.setFormat(Format.getPrettyFormat());
+ OutputStream outputFile = Files.newOutputStream(file);
+ System.out.println("Speicher in : " + file.toAbsolutePath());
+ xmlOutput.output(doc, outputFile);
+ outputFile.close();
+ System.out.println("File Saved!");
+ }
+
+ //----------------------------------------------- Zeigerbewegungen --------------------------------------------------
+
+ /** HIlfsfunktion für die Analyse einer Dateizeile
+ * @param cvsLine Zeile aus der Datei
+ * @return Liste von String für die einzelnen Spalten
+ */
+ private List parseLine(String cvsLine) {
+ return parseLine(cvsLine, DEFAULT_SEPARATOR, DEFAULT_QUOTE);
+ }
+
+ /** HIlfsfunktion für die Analyse einer Dateizeile
+ * @param cvsLine Zeile aus der Datei
+ * @param separator Trennzeichen für die Spalten
+ * @return Liste von String für die einzelnen Spalten
+ */
+ private List parseLine(String cvsLine, char separator) {
+ return parseLine(cvsLine, separator, DEFAULT_QUOTE);
+ }
+
+ /** HIlfsfunktion für die Analyse einer Dateizeile
+ * @param cvsLine Zeile aus der Datei
+ * @param separator Trennzeichen für die Spalten
+ * @param customQuote Kennung für Strings
+ * @return Liste von String für die einzelnen Spalten
+ */
+ private List parseLine(String cvsLine, char separator, char customQuote) {
+
+ List result = new ArrayList<>();
+
+ //if empty, return!
+ if (cvsLine == null && cvsLine.isEmpty()) {
+ return result;
+ }
+
+ //ggf. Default-Value laden
+ if (customQuote == ' ') {
+ customQuote = DEFAULT_QUOTE;
+ }
+
+ if (separator == ' ') {
+ separator = DEFAULT_SEPARATOR;
+ }
+
+ StringBuffer curVal = new StringBuffer();
+ boolean inQuotes = false;
+ boolean startCollectChar = false;
+ boolean doubleQuotesInColumn = false;
+
+ char[] chars = cvsLine.toCharArray();
+
+ for (char ch : chars) {
+
+ if (inQuotes) { // aktueller Text ist in Quotes eingeschlossen
+ startCollectChar = true;
+
+ if (ch == customQuote) { // Quotes werden beendet, aber Achtung bei "" => Metazeichen
+ inQuotes = false;
+ if (ch == '\"') {
+ doubleQuotesInColumn = true;
+ }
+
+ } else {
+
+ if (ch == '\"' && !doubleQuotesInColumn) {
+ doubleQuotesInColumn = true;
+ } else {
+ curVal.append(ch);
+ doubleQuotesInColumn = false;
+ }
+
+ }
+ } else {
+ if (ch == customQuote) {
+
+ inQuotes = true;
+
+ //Fixed : allow "" in empty quote enclosed
+ if (ch == '\"') {
+ if (doubleQuotesInColumn) {
+ curVal.append('"');
+ doubleQuotesInColumn = false;
+ } else doubleQuotesInColumn = true;
+
+
+ }
+ } else {
+ doubleQuotesInColumn = false;
+ if (ch == separator) {
+
+ result.add(curVal.toString());
+
+ curVal = new StringBuffer();
+ startCollectChar = false;
+
+ } else if (ch == '\r') {
+ //ignore LF characters
+ continue;
+ } else if (ch == '\n') {
+ //the end, break!
+ break;
+ } else {
+ curVal.append(ch);
+ }
+ }
+ }
+
+ }
+ result.add(curVal.toString());
+ return result;
+ }
+
+ /**
+ * Sucht die Nummer einer durch Namen gegebenen Spalte.
+ * @param name Name der Spalte
+ * @return Nummer der Spalte
+ */
+
+ private int findColumnNumber(String name) {
+ List columns = header.getChildren();
+ int i = 0;
+ for (Element c : columns) {
+ if (c.getText().equalsIgnoreCase(name)) {
+ return i;
+
+ }
+ i++;
+ }
+ return -1;
+ }
+
+ /**
+ * Fügt eine neue Spalte am Ende der Tabelle an.
+ */
+ public void addColumn() {
+ Element entry = new Element("Column");
+ entry.setAttribute("type", Table.UNKNOWN);
+ header.addContent(entry);
+ }
+
+ /**
+ * Fügt eine neue Spalte am Ende der Tabelle an und benennt sie.
+ * @param title Bezeichnung der Spalte
+ */
+ public void addColumn(String title) {
+ addColumn();
+ Element nc = ((List) (header.getChildren())).get(header.getChildren().size() - 1);
+ nc.setText(title);
+ }
+
+ /**
+ * Fügt eine neue Spalte am Ende der Tabelle an und benennt und typisiert sie.
+ * @param title Bezeichnung der Spalte
+ * @param type Typ der Spalte (UNKNOWN, DOUBLE, INTEGER, FLOAT)
+ */
+ public void addColumn(String title, String type) {
+ addColumn(title);
+ Element nc = ((List) (header.getChildren())).get(header.getChildren().size() - 1);
+ nc.setAttribute("type", type);
+ }
+
+ /**
+ * Löscht eine Spalte.
+ * @param i Nummer der Spalte.
+ */
+ public void removeColumn(int i) {
+ List lines = doc.getRootElement().getChildren();
+ for (Element l : lines) {
+ if (l.getChildren().size() > i) l.removeContent(i);
+ }
+ }
+
+ /**
+ * Löscht eine Spalte
+ * @param name Name der Spalte
+ */
+ public void removeColumn(String name) {
+ removeColumn(findColumnNumber(name));
+ }
+
+ /**
+ * Liefert die Anzahl der Spalten in der Tabelle
+ * @return Anzahl der Spalten
+ */
+ public int getColumnCount() {
+ return header.getChildren().size();
+ }
+
+ /**
+ * Liefert die Anzahl der Zeilen in der Tabelle
+ * @return Anzahl der Zeilen
+ */
+ public int getRowCount() {
+ return doc.getRootElement().getChildren().size() - 1;
+ }
+
+ /**
+ * Löscht alle Zeilen der Tabelle.
+ * Die Spaltenüberschriften und Typen bleiben erhalten.
+ */
+ public void clearRows() {
+ doc.getRootElement().removeChildren("Row");
+ }
+
+ /**
+ * Fügt eine neue Zeile an das Ende der Tabelle an.
+ * @return ein TableRow-Objekt für diese neue Zeile
+ */
+ public TableRow addRow() {
+ Element row = new Element("Row");
+ doc.getRootElement().addContent(row);
+ return new TableRow(doc, row);
+ }
+
+ /**
+ * Löscht eine Zeile
+ * @param i Nummer der Zeile
+ */
+ public void removeRow(int i) {
+ if (i < getRowCount()) {
+ doc.getRootElement().removeContent(i);
+ }
+ }
+
+ /**
+ * Liefert eine Zeile der Tabelle
+ * @param i Nummer der Zeile
+ * @return TableRow-Objekt für diese Zeile
+ */
+ public TableRow getRow(int i) {
+ if (i < getRowCount()) {
+ List rows = doc.getRootElement().getChildren();
+ return new TableRow(doc, rows.get(i + 1));
+ }
+ return null;
+ }
+
+ /**
+ * Liefert die ganze Tabelle als Array von TableRow-Objekten
+ * @return Array von TableRow-Objekten
+ */
+ public TableRow[] rows() {
+ TableRow[] rows = new TableRow[getRowCount()];
+ for (int i = 0; i < getRowCount(); i++) {
+ rows[i] = getRow(i);
+ }
+ return rows;
+ }
+
+ /**
+ * Liefert den Wert einer Zelle als Integer-Zahl
+ * @param row Zeilennummer
+ * @param column Spaltennummer
+ * @return Wert der Zelle
+ */
+ public int getInt(int row, int column) {
+ return getRow(row).getInt(column);
+ }
+
+ /**
+ * Liefert den Wert einer Zelle als Integer-Zahl
+ * @param row Zeilennummer
+ * @param name Name der Spalte
+ * @return Wert der Zelle
+ */
+ public int getInt(int row, String name) {
+ return getRow(row).getInt(name);
+ }
+
+ /**
+ * Setzt den Wert einer Zelle als Integer-Zahl
+ * @param row Zeilennummer
+ * @param column Spaltennummer
+ * @param value neuer Wert der Zelle
+ */
+ public void setInt(int row, int column, int value) {
+ getRow(row).setInt(column, value);
+ }
+
+ /**
+ * Setzt den Wert einer Zelle als Integer-Zahl
+ * @param row Zeilennummer
+ * @param name Name der Spalte
+ * @param value neuer Wert der Zelle
+ */
+ public void setInt(int row, String name, int value) {
+ getRow(row).setInt(name, value);
+ }
+
+ /**
+ * Liefert alle Werte einer Zeile als Integer-Array.
+ * @param row Nummer der Zeile
+ * @return int-Array, dass alle Werte der Zeile enthält
+ */
+ public int[] getIntRow(int row) {
+ try {
+ TableRow trow = getRow(row);
+ int anz = getColumnCount();
+ int[] r = new int[anz];
+ for (int i = 0; i < anz; i++) {
+ r[i] = trow.getInt(i);
+ }
+ return r;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Liefert alle Werte einer Spalte als Integer-Array.
+ * @param column Nummer der Spalte
+ * @return int-Array, dass alle Werte der Spalte enthält
+ */
+ public int[] getIntColumn(int column) {
+ try {
+ int anz = getRowCount();
+ int[] r = new int[anz];
+ for (int i = 0; i < anz; i++) {
+ r[i] = getInt(i, column);
+ }
+ return r;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Liefert alle Werte einer Spalte als Integer-Array.
+ * @param name Name der Spalte
+ * @return int-Array, dass alle Werte der Spalte enthält
+ */
+ public int[] getIntColumn(String name) {
+ return getIntColumn(findColumnNumber(name));
+ }
+
+
+ /**
+ * Liefert den Wert einer Zelle als Float-Zahl
+ * @param row Zeilennummer
+ * @param column Spaltennummer
+ * @return Wert der Zelle
+ */
+ public float getFloat(int row, int column) {
+ return getRow(row).getFloat(column);
+ }
+
+ /**
+ * Liefert den Wert einer Zelle als Float-Zahl
+ * @param row Zeilennummer
+ * @param name Name der Spalte
+ * @return Wert der Zelle
+ */
+ public float getFloat(int row, String name) {
+ return getRow(row).getFloat(name);
+ }
+
+ /**
+ * Setzt den Wert einer Zelle als Float-Zahl
+ * @param row Zeilennummer
+ * @param column Spaltennummer
+ * @param value neuer Wert der Zelle
+ */
+ public void setFloat(int row, int column, float value) {
+ getRow(row).setFloat(column, value);
+ }
+
+ /**
+ * Setzt den Wert einer Zelle als Float-Zahl
+ * @param row Zeilennummer
+ * @param name Name der Spalte
+ * @param value neuer Wert der Zelle
+ */
+ public void setFloat(int row, String name, float value) {
+ getRow(row).setFloat(name, value);
+ }
+
+ /**
+ * Liefert alle Werte einer Zeile als Float-Array.
+ * @param row Nummer der Zeile
+ * @return int-Array, dass alle Werte der Zeile enthält
+ */
+ public float[] getFloatRow(int row) {
+ try {
+ TableRow trow = getRow(row);
+ int anz = getColumnCount();
+ float[] r = new float[anz];
+ for (int i = 0; i < anz; i++) {
+ r[i] = trow.getFloat(i);
+ }
+ return r;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Liefert alle Werte einer Spalte als Float-Array.
+ * @param column Nummer der Spalte
+ * @return int-Array, dass alle Werte der Spalte enthält
+ */
+ public float[] getFloatColumn(int column) {
+ try {
+ int anz = getRowCount();
+ float[] r = new float[anz];
+ for (int i = 0; i < anz; i++) {
+ r[i] = getFloat(i, column);
+ }
+ return r;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Liefert alle Werte einer Spalte als Float-Array.
+ * @param name Name der Spalte
+ * @return int-Array, dass alle Werte der Spalte enthält
+ */
+ public float[] getFloatColumn(String name) {
+ return getFloatColumn(findColumnNumber(name));
+ }
+
+ /**
+ * Liefert den Wert einer Zelle als Double-Zahl
+ * @param row Zeilennummer
+ * @param column Spaltennummer
+ * @return Wert der Zelle
+ */
+ public double getDouble(int row, int column) {
+ return getRow(row).getDouble(column);
+ }
+
+ /**
+ * Liefert den Wert einer Zelle als Double-Zahl
+ * @param row Zeilennummer
+ * @param name Name der Spalte
+ * @return Wert der Zelle
+ */
+ public double getDouble(int row, String name) {
+ return getRow(row).getDouble(name);
+ }
+
+ /**
+ * Setzt den Wert einer Zelle als Double-Zahl
+ * @param row Zeilennummer
+ * @param column Spaltennummer
+ * @param value neuer Wert der Zelle
+ */
+ public void setDouble(int row, int column, double value) {
+ getRow(row).setDouble(column, value);
+ }
+
+ /**
+ * Setzt den Wert einer Zelle als Double-Zahl
+ * @param row Zeilennummer
+ * @param name Name der Spalte
+ * @param value neuer Wert der Zelle
+ */
+ public void setDouble(int row, String name, double value) {
+ getRow(row).setDouble(name, value);
+ }
+
+ /**
+ * Liefert alle Werte einer Spalte als Double-Array.
+ * @param row Nummer der Spalte
+ * @return int-Array, dass alle Werte der Spalte enthält
+ */
+ public double[] getDoubleRow(int row) {
+ try {
+ TableRow trow = getRow(row);
+ int anz = getColumnCount();
+ double[] r = new double[anz];
+ for (int i = 0; i < anz; i++) {
+ r[i] = trow.getDouble(i);
+ }
+ return r;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Liefert alle Werte einer Spalte als Double-Array.
+ * @param column Nummer der Spalte
+ * @return int-Array, dass alle Werte der Spalte enthält
+ */
+ public double[] getDoubleColumn(int column) {
+ try {
+ int anz = getRowCount();
+ double[] r = new double[anz];
+ for (int i = 0; i < anz; i++) {
+ r[i] = getDouble(i, column);
+ }
+ return r;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Liefert alle Werte einer Spalte als Double-Array.
+ * @param name Name der Spalte
+ * @return int-Array, dass alle Werte der Spalte enthält
+ */
+ public double[] getDoubleColumn(String name) {
+ return getDoubleColumn(findColumnNumber(name));
+ }
+
+ /**
+ * Liefert den Wert einer Zelle als String
+ * @param row Zeilennummer
+ * @param column Spaltennummer
+ * @return Wert der Zelle
+ */
+ public String getString(int row, int column) {
+ return getRow(row).getString(column);
+ }
+
+ /**
+ * Liefert den Wert einer Zelle als String
+ * @param row Zeilennummer
+ * @param name Name der Spalte
+ * @return Wert der Zelle
+ */
+ public String getString(int row, String name) {
+ return getRow(row).getString(name);
+ }
+
+ /**
+ * Setzt den Wert einer Zelle als String
+ * @param row Zeilennummer
+ * @param column Spaltennummer
+ * @param text neuer Wert der Zelle
+ */
+ public void setString(int row, int column, String text) {
+ getRow(row).setString(column, text);
+ }
+
+ /**
+ * Setzt den Wert einer Zelle als String
+ * @param row Zeilennummer
+ * @param name Name der Spalte
+ * @param text neuer Wert der Zelle
+ */
+ public void setString(int row, String name, String text) {
+ getRow(row).setString(name, text);
+ }
+
+ /**
+ * Liefert alle Werte einer Spalte als String-Array.
+ * @param row Nummer der Spalte
+ * @return int-Array, dass alle Werte der Spalte enthält
+ */
+ public String[] getStringRow(int row) {
+ try {
+ TableRow trow = getRow(row);
+ int anz = getColumnCount();
+ String[] r = new String[anz];
+ for (int i = 0; i < anz; i++) {
+ r[i] = trow.getString(i);
+ }
+ return r;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Liefert alle Werte einer Spalte als String-Array.
+ * @param column Nummer der Spalte
+ * @return int-Array, dass alle Werte der Spalte enthält
+ */
+ public String[] getStringColumn(int column) {
+ try {
+ int anz = getRowCount();
+ String[] r = new String[anz];
+ for (int i = 0; i < anz; i++) {
+ r[i] = getString(i, column);
+ }
+ return r;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Liefert alle Werte einer Spalte als String-Array.
+ * @param name Name der Spalte
+ * @return int-Array, dass alle Werte der Spalte enthält
+ */
+ public String[] getStringColumn(String name) {
+ return getStringColumn(findColumnNumber(name));
+ }
+
+
+ /**
+ * Sucht nach einem bestimmtem Wert in einer Zeile.
+ * @param value Wert der gesucht werden soll
+ * @param column Nummer der Spalte, die durchsucht werden soll
+ * @return TableRow-Objekt der Zeile, wenn der Wert gefunden wurde, sonst null
+ */
+ public TableRow findRow(String value, int column) {
+ for (int i = 0; i < getRowCount(); i++) {
+ if (getString(i, column).equals(value)) {
+ return getRow(i);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Sucht nach einem bestimmtem Wert in einer Zeile.
+ * @param value Wert der gesucht werden soll
+ * @param name Name der Spalte, die durchsucht werden soll
+ * @return TableRow-Objekt der Zeile, wenn der Wert gefunden wurde, sonst null
+ */
+ public TableRow findRow(String value, String name) {
+ return findRow(value, findColumnNumber(name));
+ }
+
+ /**
+ * Kürzt alle Einträge der Tabelle um unnötige Leerzeichen am Anfang oder Ende
+ */
+ public void trim() {
+ for (int y = 0; y < getRowCount(); y++) {
+ for (int x = 0; x < getColumnCount(); x++) {
+ setString(y, x, getString(y, x).trim());
+ }
+ }
+ }
+}
diff --git a/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/util/TableRow.java b/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/util/TableRow.java
new file mode 100644
index 0000000..81f05b3
--- /dev/null
+++ b/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/util/TableRow.java
@@ -0,0 +1,304 @@
+package io.gitlab.jfronny.ImgJava.util;
+
+import org.jdom.Document;
+import org.jdom.Element;
+
+import java.text.NumberFormat;
+import java.util.List;
+
+/**
+ * Repräsentiert eine Zeile eines Table-Objekts.
+ * Erlaubt einen einfachen Zugriff auf die einzelnen Einträge in dieser Zeile.
+ *
+ * @author Thomas Schaller
+ * @version V1.0 vom 01.02.2019
+ */
+public class TableRow {
+ // Für die Interpretation von Zahlenwerten
+ NumberFormat format = NumberFormat.getInstance();
+ // Verweis auf das ganze Dokument
+ private final Document doc;
+ // Verweis auf die Zeile, für die dieses Objekt steht
+ private final Element current;
+ // Verweis auf die Kopfzeile
+ private final Element header;
+
+ // Ende Attribute
+
+ /**
+ * Erzeugt ein TableRow-Objekt.
+ * Diese Methode ist für den internen Gebraucht. Einige Methode der Table-Klasse erzeugen mit diesem Konstruktor TableRow-Objekte.
+ * @param doc JDOM-Dokument, das für die ganze Tabelle steht.
+ * @param row JDOM-Element, das für die aktuelle Zeile steht.
+ */
+ public TableRow(Document doc, Element row) {
+ this.doc = doc;
+ this.current = row;
+ this.header = doc.getRootElement().getChild("Header");
+ }
+
+ /**
+ * Liefert die Anzahl der Spalten der Zeile.
+ * @return Anzahl der Spalten
+ */
+ public int getColumnCount() {
+ return header.getChildren().size();
+ }
+
+ /**
+ * Liefert den Titel einer Spalte
+ * @param i Nummer der Spalte
+ * @return Name der Spalte
+ */
+ public String getColumnTitle(int i) {
+ if (i < getColumnCount()) {
+ return ((List) (header.getChildren())).get(i).getText();
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * Liefert die Nummer einer Spalte
+ * @param name Name der Spalte
+ * @return Nummer der Spalte
+ */
+ public int getColumn(String name) {
+ List columns = header.getChildren();
+ int i = 0;
+ while (i < columns.size()) {
+ if (columns.get(i).getText().equalsIgnoreCase(name)) {
+ return i;
+ }
+ i++;
+ } // end of while
+ return -1;
+ }
+
+
+ /**
+ * Erzeugt eine neue Zeile mit i Spalten
+ * Wenn bisher nicht genügend Spalten vorhanden sind, werden automatisch neue Spalten hinzugefügt (auch zum Header)
+ * @param i Anzahl der Spalten
+ */
+ private Element buildRow(int i) {
+ List columns = header.getChildren();
+ Element entry = null;
+ for (int j = 0; j <= i; j++) {
+
+ if (j == columns.size()) {
+ Element h = new Element("Column");
+ h.setAttribute("type", "unknown");
+ header.addContent(h);
+ columns = header.getChildren();
+ }
+ if (j == current.getChildren().size()) {
+ entry = new Element("Entry");
+ current.addContent(entry);
+
+ }
+
+ }
+ return entry;
+
+ }
+
+ /**
+ * Erzeugt eine neue Zeile.
+ * Es werden genügend Spalten erzeugt, dass ein Wert in Spalte "name" eingetragen werden kann
+ * @param name Name der Spalte
+ */
+ private Element buildRow(String name) {
+ List columns = header.getChildren();
+ int i = 0;
+ for (Element c : columns) {
+
+ if (c.getText().equalsIgnoreCase(name)) {
+ return buildRow(i);
+ }
+ i++;
+ }
+ return null;
+
+ }
+
+ /**
+ * Liefert den Wert einer Zelle als String
+ * @param i Nummer der Spalte
+ * @return Wert der Zelle
+ */
+ public String getString(int i) {
+ if (i >= current.getContent().size()) return "";
+ Element e = (Element) current.getContent(i);
+ if (e != null) {
+ return e.getText();
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * Liefert den Wert einer Zelle als String
+ * @param name Name der Spalte
+ * @return Wert der Zelle
+ */
+ public String getString(String name) {
+ return getString(getColumn(name));
+ }
+
+ /**
+ * Setzt den Wert einer Zelle als String
+ * @param i Nummer der Spalte
+ * @param text neuer Wert der Zelle
+ */
+ public void setString(int i, String text) {
+
+ Element e = buildRow(i);
+ if (e != null) e.setText(text);
+ }
+
+ /**
+ * Setzt den Wert einer Zelle als String
+ * @param name Name der Spalte
+ * @param text neuer Wert der Zelle
+ */
+ public void setString(String name, String text) {
+ Element e = buildRow(name);
+ if (e != null) e.setText(text);
+ }
+
+
+ /**
+ * Liefert den Wert einer Zelle als Int-Zahl
+ * @param i Nummer der Spalte
+ * @return Wert der Zelle
+ */
+ public int getInt(int i) {
+ try {
+ Element e = (Element) current.getContent(i);
+ return Integer.parseInt(e.getText());
+ } catch (Exception e) {
+ return 0;
+ }
+ }
+
+ /**
+ * Liefert den Wert einer Zelle als Int-Zahl
+ * @param name Name der Spalte
+ * @return Wert der Zelle
+ */
+ public int getInt(String name) {
+ return getInt(getColumn(name));
+ }
+
+ /**
+ * Setzt den Wert einer Zelle als Int-Zahl
+ * @param i Nummer der Spalte
+ * @param value neuer Wert der Zelle
+ */
+ public void setInt(int i, int value) {
+
+ Element e = buildRow(i);
+ if (e != null) e.setText("" + value);
+ }
+
+ /**
+ * Setzt den Wert einer Zelle als Int-Zahl
+ * @param name Name der Spalte
+ * @param value neuer Wert der Zelle
+ */
+ public void setInt(String name, int value) {
+ Element e = buildRow(name);
+ if (e != null) e.setText("" + value);
+ }
+
+ /**
+ * Liefert den Wert einer Zelle als Float-Zahl
+ * @param i Nummer der Spalte
+ * @return Wert der Zelle
+ */
+ public float getFloat(int i) {
+ try {
+ Element e = (Element) current.getContent(i);
+ return Float.parseFloat(e.getText().replace(",", "."));
+ } catch (Exception e) {
+ return 0;
+ }
+ }
+
+ /**
+ * Liefert den Wert einer Zelle als Float-Zahl
+ * @param name Name der Spalte
+ * @return Wert der Zelle
+ */
+ public float getFloat(String name) {
+ return getFloat(getColumn(name));
+ }
+
+ /**
+ * Setzt den Wert einer Zelle als Float-Zahl
+ * @param i Nummer der Spalte
+ * @param value neuer Wert der Zelle
+ */
+ public void setFloat(int i, float value) {
+
+ Element e = buildRow(i);
+ if (e != null) e.setText(format.format(value));
+ }
+
+ /**
+ * Setzt den Wert einer Zelle als Float-Zahl
+ * @param name Name der Spalte
+ * @param value neuer Wert der Zelle
+ */
+ public void setFloat(String name, float value) {
+ Element e = buildRow(name);
+ if (e != null) e.setText(format.format(value));
+ }
+
+ /**
+ * Liefert den Wert einer Zelle als Double-Zahl
+ * @param i Nummer der Spalte
+ * @return Wert der Zelle
+ */
+ public double getDouble(int i) {
+ try {
+ Element e = (Element) current.getContent(i);
+ return Double.parseDouble(e.getText().replace(",", "."));
+
+ } catch (Exception e) {
+ return 0;
+ }
+ }
+
+ /**
+ * Liefert den Wert einer Zelle als Double-Zahl
+ * @param name Name der Spalte
+ * @return Wert der Zelle
+ */
+ public double getDouble(String name) {
+ return getDouble(getColumn(name));
+ }
+
+ /**
+ * Setzt den Wert einer Zelle als Double-Zahl
+ * @param i Nummer der Spalte
+ * @param value neuer Wert der Zelle
+ */
+ public void setDouble(int i, double value) {
+
+ Element e = buildRow(i);
+ if (e != null) e.setText(format.format(value));
+ }
+
+ /**
+ * Setzt den Wert einer Zelle als Double-Zahl
+ * @param name Name der Spalte
+ * @param value neuer Wert der Zelle
+ */
+ public void setDouble(String name, double value) {
+ Element e = buildRow(name);
+ if (e != null) e.setText(format.format(value));
+ }
+
+}
diff --git a/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/util/XML.java b/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/util/XML.java
new file mode 100644
index 0000000..1a46e70
--- /dev/null
+++ b/ImgJava/src/main/java/io/gitlab/jfronny/ImgJava/util/XML.java
@@ -0,0 +1,699 @@
+package io.gitlab.jfronny.ImgJava.util;
+
+import org.jdom.Attribute;
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jdom.JDOMException;
+import org.jdom.input.SAXBuilder;
+import org.jdom.output.Format;
+import org.jdom.output.XMLOutputter;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+
+/**
+ * Klasse zum Vereinfachten Zugriff auf XML-Dokumente
+ * Diese Klasse ist für den Einsatz in der Schule gedacht und soll den Schülern
+ * einen einfachen Zugriff auf XML-Dokumente ermöglichen. Die zur Verfügung
+ * stehenden Befehle sind wie in Processing realisiert.
+ * Dabei ist jeder Teilbaum des Dokuments wieder als XML-Objekt zugreifbar, das
+ * intern auf die gleiche XML-Dokumentstruktur zugreift.
+ * Dies ermöglicht bei unsachgemäßem Gebrauch die XML-Struktur zu zerstören. Im
+ * normalen Gebrauch sollte dies aber nicht relevant sein.
+ *
+ * Benötigt: jdom-1.1.3.jar
+ *
+ * @author Thomas Schaller
+ * @version 1.0 vom 31.01.2019
+ */
+public class XML {
+ // Anfang Attribute
+ // XML-Dokumentstruktur
+ private Document doc;
+ // Zeiger auf das aktuelle Element
+ private Element current;
+ // Ende Attribute
+
+ /**
+ * Erzeugt ein leeres XMLDokument
+ */
+ public XML() {
+ this.doc = new Document();
+ this.current = null;
+ }
+
+ /**
+ * Erzeugt ein XML-Dokument aus einer Datei
+ *
+ * @param file Dateiname der XML-Datei
+ */
+ public XML(Path file) throws IOException, JDOMException {
+ loadXML(file);
+ }
+
+ /**
+ * interner Konstruktor, um ein XML Objekt zu erzeugen, das auf einen bestimmten Knoten verweist
+ *
+ * @param doc die XML-Dokumentstruktur
+ * @param current Zeiger auf das aktuelle Element
+ */
+ private XML(Document doc, Element current) {
+ this.doc = doc;
+ this.current = current;
+ }
+
+ // Anfang Methoden
+
+ /**
+ * Öffnet das durch den Dateinamen gegebene Dokument
+ *
+ * @param file Dateiname des XML-Files
+ */
+ public void loadXML(Path file) throws IOException, JDOMException {
+ doc = null;
+ // Das Dokument erstellen
+ SAXBuilder builder = new SAXBuilder();
+ doc = builder.build(Files.newInputStream(file));
+ // Zeiger im Baum auf Root-Element
+ current = doc.getRootElement();
+ }
+
+ /**
+ * Speichert den XML-Baum im angegebenen Dateinamen
+ *
+ * @param file Dateiname des XML-Files
+ */
+ public void saveXML(Path file) throws IOException {
+ // new XMLOutputter().output(doc, System.out);
+ XMLOutputter xmlOutput = new XMLOutputter();
+
+ // display nice nice
+ xmlOutput.setFormat(Format.getPrettyFormat());
+ OutputStream outputFile = Files.newOutputStream(file);
+ System.out.println("Speicher in : " + file.toAbsolutePath());
+ xmlOutput.output(doc, outputFile);
+ outputFile.close();
+ System.out.println("File Saved!");
+ }
+
+ //----------------------------------------------- Zeigerbewegungen --------------------------------------------------
+
+ /**
+ * liefert ein XML-Objekt, das auf den Vaterknoten des aktuellen Elements zeigt.
+ *
+ * @return Vater des aktuellen Objekts.
+ */
+ public XML getParent() {
+ if (current != null) {
+ Element parent = current.getParentElement();
+ if (parent == null) {
+ return null;
+ } else {
+ return new XML(doc, parent);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Überprüft, ob das Element irgendwelche Kinder hat oder nicht, und gibt das Ergebnis als boolean zurück.
+ *
+ * @return true, wenn Kinder vorhanden sind, sonst false
+ */
+ public boolean hasChildren() {
+ if (current == null) {
+ return doc.hasRootElement();
+ } else {
+ return current.getChildren().size() > 0;
+ }
+ }
+
+ /**
+ * Ermittelt die Namen aller Kinder des Elements und gibt die Namen als ein Array von Strings zurück.
+ * Dies ist dasselbe wie das Durchlaufen und Aufrufen von getName() auf jedem untergeordneten Element einzeln.
+ *
+ * @return Liste aller Namen der Kinder
+ */
+ public String[] listChildren() {
+ if (current == null) {
+ if (doc.hasRootElement()) {
+ String[] names = new String[0];
+ names[0] = doc.getRootElement().getName();
+ return names;
+ } else {
+ return null;
+ }
+ } else {
+ List ch_element = current.getChildren();
+ String[] names = new String[ch_element.size()];
+ for (int i = 0; i < ch_element.size(); i++) {
+ names[i] = ch_element.get(i).getName();
+ }
+ return names;
+ }
+ }
+
+ /**
+ * Liefert alle Kinder des Elements als Array von XML-Objekten.
+ *
+ * @return Array der Kinder als XML-Objekte
+ */
+ public XML[] getChildren() {
+ if (current == null) {
+ if (doc.hasRootElement()) {
+ XML[] ch_xml = new XML[1];
+ ch_xml[0] = new XML(doc, doc.getRootElement());
+ return ch_xml;
+ } else {
+ return null;
+ }
+ } else {
+ List ch_element = current.getChildren();
+ XML[] ch_xml = new XML[ch_element.size()];
+ for (int i = 0; i < ch_element.size(); i++) {
+ ch_xml[i] = new XML(doc, ch_element.get(i));
+ }
+ return ch_xml;
+ }
+ }
+
+ /**
+ * Liefert bestimmte Kinder des Elements als Array von XML-Objekten.
+ * Die Methode gibt dabei alle Kinder zurück, die dem angegebenen Namen entsprechen.
+ *
+ * @param name Name der gesuchten Kind-Objekte
+ * @return Array der Kinder als XML-Objekte
+ */
+ public XML[] getChildren(String name) {
+ if (current == null) {
+ if (doc.hasRootElement()) {
+ XML[] ch_xml = new XML[1];
+ ch_xml[0] = new XML(doc, doc.getRootElement());
+ if (doc.getRootElement().getName().equals(name)) {
+ return ch_xml;
+ } else {
+ return null;
+ }
+ } else {
+ return null;
+ }
+ } else {
+ List ch_element = current.getChildren(name);
+ XML[] ch_xml = new XML[ch_element.size()];
+ for (int i = 0; i < ch_element.size(); i++) {
+ ch_xml[i] = new XML(doc, ch_element.get(i));
+ }
+ return ch_xml;
+ }
+ }
+
+ /**
+ * Liefert das erste Kind des Elements mit einem bestimmten Namen.
+ * Die Methode gibt das erste Kind zurück, das dem angegebenen Namen entsprechen.
+ *
+ * @param name Name des gesuchten Kind-Objektes
+ * @return Kind als XML-Objekt
+ */
+
+ public XML getChild(String name) {
+ if (current == null) {
+ Element e = doc.getRootElement();
+ if (e.getName().equals(name)) {
+ return new XML(doc, e);
+ } else {
+ return null;
+ }
+ } else {
+ String[] names = name.split("/");
+ Element e = current;
+ int i = 0;
+ while (i < names.length) {
+ e = e.getChild(names[i]);
+ if (e == null) return null;
+ i++;
+ }
+ return new XML(doc, e);
+ }
+ }
+
+ /**
+ * Liefert das i. Kind des Elements.
+ * Die Methode gibt das i. Kind des aktuellen Elements zurück.
+ *
+ * @param i Nummer des Kindes
+ * @return Kind als XML-Objekt
+ */
+ public XML getChild(int i) {
+ if (current == null) {
+ return new XML(doc, doc.getRootElement());
+ } else {
+ List ch_element = current.getChildren();
+ if (i >= ch_element.size()) return null;
+ return new XML(doc, ch_element.get(i));
+ }
+ }
+
+ //--------------------------------------------------- Methoden für das aktuelle Element -------------------------------------------------
+
+ /**
+ * Frage den Namen des aktuellen Elements ab
+ *
+ * @return Namen des Elements
+ */
+ public String getName() {
+ if (current == null) return "";
+ return current.getName();
+ }
+
+ /**
+ * Setze den Namen des aktuellen Elements.
+ *
+ * @param name Neuer Name des Elements
+ */
+ public void setName(String name) {
+ if (current == null) return;
+ current.setName(name);
+ }
+
+ /**
+ * liefert die Anzahl der Attribute eines Elements.
+ *
+ * @return Anzahl des Attribute
+ */
+ public int getAttributeCount() {
+ if (current == null) return 0;
+ return current.getAttributes().size();
+ }
+
+ /**
+ * liefert zurück, ob das aktuelle Element Attribute hat .
+ *
+ * @return true, wenn es Attribute gibt
+ */
+ public boolean hasAttribute() {
+ if (current == null) return false;
+ return current.getAttributes().size() > 0;
+ }
+
+ /**
+ * Ruft alle Attribute des angegebenen Elements ab und gibt sie als Array von Strings zurück.
+ *
+ * @return Liste der Attributnamen
+ */
+ public String[] listAttributes() {
+ if (current == null) return null;
+ List attr = current.getAttributes();
+ String[] names = new String[attr.size()];
+ for (int i = 0; i < attr.size(); i++) {
+ names[i] = attr.get(i).getName();
+ }
+ return names;
+ }
+
+ /**
+ * Fragt einen Attributwert des aktuellen Elements ab
+ *
+ * @param attribute Name des Attributs
+ * @return Wert des Attributs
+ */
+ public String getString(String attribute) {
+ if (current == null) return "";
+ return current.getAttributeValue(attribute);
+ }
+
+ /**
+ * Fragt einen Attributwert des aktuellen Elements ab
+ * Sollte es das Attribut nicht geben, wird ein default-Wert zurückgegeben
+ *
+ * @param attribute Name des Attributs
+ * @param defaultValue Standardwert, falls es das Attribut nicht gibt
+ * @return Wert des Attributs
+ */
+ public String getString(String attribute, String defaultValue) {
+ if (current == null) return defaultValue;
+ return current.getAttributeValue(attribute, defaultValue);
+ }
+
+ /**
+ * Setzt einen Attributwert des aktuellen Elements
+ *
+ * @param attribute Name des Attributs
+ * @param text neuer Wert des Attributs
+ */
+ public void setString(String attribute, String text) {
+ if (current == null) return;
+ current.setAttribute(attribute, text);
+ }
+
+ /**
+ * Fragt einen Attributwert des aktuellen Elements ab
+ *
+ * @param attribute Name des Attributs
+ * @return Wert des Attributs als Integer-Zahl
+ */
+ public int getInt(String attribute) {
+ if (current == null) return 0;
+ try {
+ int i = Integer.parseInt(current.getAttributeValue(attribute));
+ return i;
+ } catch (Exception e) {
+ return 0;
+ }
+
+ }
+
+ /**
+ * Fragt einen Attributwert des aktuellen Elements ab
+ * Sollte es das Attribut nicht geben, wird ein default-Wert zurückgegeben
+ *
+ * @param attribute Name des Attributs
+ * @param defaultValue Standardwert, falls es das Attribut nicht gibt
+ * @return Wert des Attributs als Integer-Zahl
+ */
+ public int getInt(String attribute, int defaultValue) {
+ if (current == null) return defaultValue;
+ try {
+ int i = Integer.parseInt(current.getAttributeValue(attribute));
+ return i;
+ } catch (Exception e) {
+ return defaultValue;
+ }
+
+ }
+
+ /**
+ * Setzt einen Attributwert des aktuellen Elements
+ *
+ * @param attribute Name des Attributs
+ * @param value neuer Wert des Attributs
+ */
+ public void setInt(String attribute, int value) {
+ if (current == null) return;
+ current.setAttribute(attribute, "" + value);
+ }
+
+ /**
+ * Fragt einen Attributwert des aktuellen Elements ab
+ *
+ * @param attribute Name des Attributs
+ * @return Wert des Attributs als Float-Zahl
+ */
+ public float getFloat(String attribute) {
+ if (current == null) return 0;
+ try {
+ float i = Float.parseFloat(current.getAttributeValue(attribute));
+ return i;
+ } catch (Exception e) {
+ return 0;
+ }
+
+ }
+
+ /**
+ * Fragt einen Attributwert des aktuellen Elements ab
+ * Sollte es das Attribut nicht geben, wird ein default-Wert zurückgegeben
+ *
+ * @param attribute Name des Attributs
+ * @param defaultValue Standardwert, falls es das Attribut nicht gibt
+ * @return Wert des Attributs als Float-Zahl
+ */
+ public float getFloat(String attribute, float defaultValue) {
+ if (current == null) return defaultValue;
+ try {
+ float i = Float.parseFloat(current.getAttributeValue(attribute));
+ return i;
+ } catch (Exception e) {
+ return defaultValue;
+ }
+
+ }
+
+ /**
+ * Setzt einen Attributwert des aktuellen Elements
+ *
+ * @param attribute Name des Attributs
+ * @param value neuer Wert des Attributs
+ */
+ public void setFloat(String attribute, float value) {
+ if (current == null) return;
+ current.setAttribute(attribute, "" + value);
+ }
+
+ /**
+ * Fragt einen Attributwert des aktuellen Elements ab
+ *
+ * @param attribute Name des Attributs
+ * @return Wert des Attributs als Double-Zahl
+ */
+ public double getDouble(String attribute) {
+ if (current == null) return 0;
+ try {
+ double i = Double.parseDouble(current.getAttributeValue(attribute));
+ return i;
+ } catch (Exception e) {
+ return 0;
+ }
+
+ }
+
+ /**
+ * Fragt einen Attributwert des aktuellen Elements ab
+ * Sollte es das Attribut nicht geben, wird ein default-Wert zurückgegeben
+ *
+ * @param attribute Name des Attributs
+ * @param defaultValue Standardwert, falls es das Attribut nicht gibt
+ * @return Wert des Attributs als double-Zahl
+ */
+ public double getDouble(String attribute, double defaultValue) {
+ if (current == null) return defaultValue;
+ try {
+ double i = Double.parseDouble(current.getAttributeValue(attribute));
+ return i;
+ } catch (Exception e) {
+ return defaultValue;
+ }
+
+ }
+
+ /**
+ * Setzt einen Attributwert des aktuellen Elements
+ *
+ * @param attribute Name des Attributs
+ * @param value neuer Wert des Attributs
+ */
+ public void setDouble(String attribute, double value) {
+ if (current == null) return;
+ current.setAttribute(attribute, "" + value);
+ }
+
+ /**
+ * Fragt den Inhalt/Text des aktuellen Elements ab
+ *
+ * @return Inhalt des Elements
+ */
+ public String getContent() {
+ if (current == null) return "";
+
+ return current.getText();
+ }
+
+ /**
+ * Setzt den Inhalt/Text des aktuellen Elements
+ *
+ * @param text Neuer Inhalt des Elements
+ */
+ public void setContent(String text) {
+ if (current == null) return;
+ current.setText(text);
+ }
+
+ /**
+ * Fragt den Inhalt/Text des aktuellen Elements ab
+ * Hat das Element keinen Inhalt wird der defaultValue zurückgegeben.
+ *
+ * @param defaultValue Standardtext
+ * @return Inhalt des Elements
+ */
+ public String getContent(String defaultValue) {
+ if (current == null) return defaultValue;
+ String t = current.getText();
+ if (t.equals("")) t = defaultValue;
+ return t;
+ }
+
+ /**
+ * Fragt den Inhalt des aktuellen Elements als Integerzahl ab
+ * Hat das Element keinen Inhalt wird der defaultValue zurückgegeben.
+ *
+ * @param defaultValue Standardwert
+ * @return Inhalt des Elements
+ */
+ public int getIntContent(int defaultValue) {
+ if (current == null) return defaultValue;
+ try {
+ int i = Integer.parseInt(current.getText());
+ return i;
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+ /**
+ * Fragt den Inhalt des aktuellen Elements als Integerzahl ab
+ *
+ * @return Inhalt des Elements
+ */
+ public int getIntContent() {
+ if (current == null) return 0;
+ try {
+ int i = Integer.parseInt(current.getText());
+ return i;
+ } catch (Exception e) {
+ return 0;
+ }
+ }
+
+ /**
+ * Setzt den Inhalt des aktuellen Elements
+ *
+ * @param value Neuer Inhalt des Elements
+ */
+ public void setIntContent(int value) {
+ if (current == null) return;
+ current.setText("" + value);
+ }
+
+
+ /**
+ * Fragt den Inhalt des aktuellen Elements als Floatzahl ab
+ * Hat das Element keinen Inhalt wird der defaultValue zurückgegeben.
+ *
+ * @param defaultValue Standardwert
+ * @return Inhalt des Elements
+ */
+ public float getFloatContent(float defaultValue) {
+ if (current == null) return defaultValue;
+ try {
+ float i = Float.parseFloat(current.getText());
+ return i;
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+ /**
+ * Fragt den Inhalt des aktuellen Elements als Floatzahl ab
+ *
+ * @return Inhalt des Elements
+ */
+ public float getFloatContent() {
+ if (current == null) return 0;
+ try {
+ float i = Float.parseFloat(current.getText());
+ return i;
+ } catch (Exception e) {
+ return 0;
+ }
+ }
+
+ /**
+ * Setzt den Inhalt des aktuellen Elements
+ *
+ * @param value Neuer Inhalt des Elements
+ */
+ public void setFloatContent(float value) {
+ if (current == null) return;
+ current.setText("" + value);
+ }
+
+ /**
+ * Fragt den Inhalt des aktuellen Elements als Doublezahl ab
+ * Hat das Element keinen Inhalt wird der defaultValue zurückgegeben.
+ *
+ * @param defaultValue Standardwert
+ * @return Inhalt des Elements
+ */
+ public double getDoubleContent(double defaultValue) {
+ if (current == null) return defaultValue;
+ try {
+ double i = Double.parseDouble(current.getText());
+ return i;
+ } catch (Exception e) {
+ return defaultValue;
+ }
+ }
+
+ /**
+ * Fragt den Inhalt des aktuellen Elements als Doublezahl ab
+ *
+ * @return Inhalt des Elements
+ */
+ public double getDoubleContent() {
+ if (current == null) return 0;
+ try {
+ double i = Double.parseDouble(current.getText());
+ return i;
+ } catch (Exception e) {
+ return 0;
+ }
+ }
+
+ /**
+ * Setzt den Inhalt des aktuellen Elements
+ *
+ * @param value Neuer Inhalt des Elements
+ */
+ public void setDoubleContent(double value) {
+ if (current == null) return;
+ current.setText("" + value);
+ }
+
+
+ // ----------------------------------------------- XML-Struktur aufbauen ------------------------------------------------
+
+ /**
+ * Erzeuge neues Element nach der aktuellen Position und setze dieses als aktuelles Element
+ *
+ * @param name Name des neuen Elements
+ * @return neues Element als XML-Objekt
+ */
+ public XML addChild(String name) {
+ Element e = new Element(name);
+ if (current == null) { // man ist auf Root-Ebene
+ doc.setRootElement(e);
+
+ } else {
+ current.addContent(e);
+ } // end of if-else
+ return new XML(doc, e);
+ }
+
+ /**
+ * liefert das aktuelle Element als jdom-Element-Objekt
+ *
+ * @return aktuelles Element
+ */
+ private Element getCurrent() {
+ return current;
+ }
+
+ /**
+ * löscht ein Kind des aktuellen Knotens.
+ * Ist kid kein Kind des aktuellen Elements passiert gar nichts.
+ *
+ * @param kid XML-Objekt des Kindes
+ */
+ public void removeChild(XML kid) {
+ if (current == null) return;
+ Element e = kid.getCurrent();
+ int index = current.indexOf(e);
+ if (index >= 0) {
+ current.removeContent(e);
+ }
+ }
+
+}
diff --git a/ImgJava/src/main/resources/images/baum1.jpg b/ImgJava/src/main/resources/images/baum1.jpg
new file mode 100644
index 0000000..7b35aab
Binary files /dev/null and b/ImgJava/src/main/resources/images/baum1.jpg differ
diff --git a/ImgJava/src/main/resources/images/baum2.jpg b/ImgJava/src/main/resources/images/baum2.jpg
new file mode 100644
index 0000000..eec8a6d
Binary files /dev/null and b/ImgJava/src/main/resources/images/baum2.jpg differ
diff --git a/ImgJava/src/main/resources/images/bildnachweise.txt b/ImgJava/src/main/resources/images/bildnachweise.txt
new file mode 100644
index 0000000..23b723c
--- /dev/null
+++ b/ImgJava/src/main/resources/images/bildnachweise.txt
@@ -0,0 +1,20 @@
+Eigenes Werk:
+Baum1.jpg
+Baum2.jpg
+Iris.jpg
+Katze.jpg
+maske1.jpg
+maske2.jpg
+rosen_normal.jpg
+rosen_ueberbelichtet.jpg
+rosen_unterbelichtet.jpg
+
+Pixabay Licence:
+https://pixabay.com/de/illustations/haus-häuser-finde-den-unterschied-3208132/
+unterschiedfinden1.png
+unterschiedfinden2.png
+
+CC-BY-SA 2.5 (https://creativecommons.org/licenses/by-sa/2.5/deed.de)
+Frenelsche Zonenplatte,
+Georg Wiora via Wikimedia Commons
+https://commons.wikimedia.org/wiki/File:Zonenplatte_Cosinus.png
diff --git a/ImgJava/src/main/resources/images/bildnachweise2.txt b/ImgJava/src/main/resources/images/bildnachweise2.txt
new file mode 100644
index 0000000..c448230
--- /dev/null
+++ b/ImgJava/src/main/resources/images/bildnachweise2.txt
@@ -0,0 +1,21 @@
+Eigenes Werk:
+Baum1.jpg
+Baum2.jpg
+Iris.jpg
+Katze.jpg
+maske1.jpg
+maske2.jpg
+rosen_normal.jpg
+rosen_ueberbelichtet.jpg
+rosen_unterbelichtet.jpg
+testbild.png
+
+Pixabay Licence:
+https://pixabay.com/de/illustations/haus-häuser-finde-den-unterschied-3208132/
+unterschiedfinden1.png
+unterschiedfinden2.png
+
+CC-BY-SA 2.5 (https://creativecommons.org/licenses/by-sa/2.5/deed.de)
+Frenelsche Zonenplatte,
+Georg Wiora via Wikimedia Commons
+https://commons.wikimedia.org/wiki/File:Zonenplatte_Cosinus.png
diff --git a/ImgJava/src/main/resources/images/iris.jpg b/ImgJava/src/main/resources/images/iris.jpg
new file mode 100644
index 0000000..94a072f
Binary files /dev/null and b/ImgJava/src/main/resources/images/iris.jpg differ
diff --git a/ImgJava/src/main/resources/images/katze.jpg b/ImgJava/src/main/resources/images/katze.jpg
new file mode 100644
index 0000000..9215552
Binary files /dev/null and b/ImgJava/src/main/resources/images/katze.jpg differ
diff --git a/ImgJava/src/main/resources/images/maske1.jpg b/ImgJava/src/main/resources/images/maske1.jpg
new file mode 100644
index 0000000..0014f30
Binary files /dev/null and b/ImgJava/src/main/resources/images/maske1.jpg differ
diff --git a/ImgJava/src/main/resources/images/maske2.jpg b/ImgJava/src/main/resources/images/maske2.jpg
new file mode 100644
index 0000000..caf22ae
Binary files /dev/null and b/ImgJava/src/main/resources/images/maske2.jpg differ
diff --git a/ImgJava/src/main/resources/images/rosen_normal.jpg b/ImgJava/src/main/resources/images/rosen_normal.jpg
new file mode 100644
index 0000000..76ebf34
Binary files /dev/null and b/ImgJava/src/main/resources/images/rosen_normal.jpg differ
diff --git a/ImgJava/src/main/resources/images/rosen_ueberbelichtet.jpg b/ImgJava/src/main/resources/images/rosen_ueberbelichtet.jpg
new file mode 100644
index 0000000..e99fc12
Binary files /dev/null and b/ImgJava/src/main/resources/images/rosen_ueberbelichtet.jpg differ
diff --git a/ImgJava/src/main/resources/images/rosen_unterbelichtet.jpg b/ImgJava/src/main/resources/images/rosen_unterbelichtet.jpg
new file mode 100644
index 0000000..8802f29
Binary files /dev/null and b/ImgJava/src/main/resources/images/rosen_unterbelichtet.jpg differ
diff --git a/ImgJava/src/main/resources/images/testbild.png b/ImgJava/src/main/resources/images/testbild.png
new file mode 100644
index 0000000..c2dadda
Binary files /dev/null and b/ImgJava/src/main/resources/images/testbild.png differ
diff --git a/ImgJava/src/main/resources/images/unterschiedfinden1.png b/ImgJava/src/main/resources/images/unterschiedfinden1.png
new file mode 100644
index 0000000..29c6c7e
Binary files /dev/null and b/ImgJava/src/main/resources/images/unterschiedfinden1.png differ
diff --git a/ImgJava/src/main/resources/images/unterschiedfinden2.png b/ImgJava/src/main/resources/images/unterschiedfinden2.png
new file mode 100644
index 0000000..3e2ba53
Binary files /dev/null and b/ImgJava/src/main/resources/images/unterschiedfinden2.png differ
diff --git a/ImgJava/src/main/resources/images/zonenplatte_cosinus.png b/ImgJava/src/main/resources/images/zonenplatte_cosinus.png
new file mode 100644
index 0000000..43d2dfe
Binary files /dev/null and b/ImgJava/src/main/resources/images/zonenplatte_cosinus.png differ