commit d8b6a654c70679a26c364b630187656690b9722b Author: JFronny <33260128+jfronny@users.noreply.github.com> Date: Wed May 5 09:35:18 2021 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..15b7b45 --- /dev/null +++ b/.gitignore @@ -0,0 +1,131 @@ + +# Created by https://www.toptal.com/developers/gitignore/api/rider,java,gradle,dotnetcore +# Edit at https://www.toptal.com/developers/gitignore?templates=rider,java,gradle,dotnetcore + +### DotnetCore ### +# .NET Core build folders +bin/ +obj/ + +# Common node modules locations +/node_modules +/wwwroot/node_modules + +### Java ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +### Rider ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Gradle ### +.gradle +build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Cache of project +.gradletasknamecache + +# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 +# gradle/wrapper/gradle-wrapper.properties + +### Gradle Patch ### +**/build/ + +# End of https://www.toptal.com/developers/gitignore/api/rider,java,gradle,dotnetcore diff --git a/IMPImg/.gitignore b/IMPImg/.gitignore new file mode 100644 index 0000000..add57be --- /dev/null +++ b/IMPImg/.gitignore @@ -0,0 +1,5 @@ +bin/ +obj/ +/packages/ +riderModule.iml +/_ReSharper.Caches/ \ No newline at end of file diff --git a/IMPImg/.idea/.idea.IMPImg/.idea/.gitignore b/IMPImg/.idea/.idea.IMPImg/.idea/.gitignore new file mode 100644 index 0000000..3254faf --- /dev/null +++ b/IMPImg/.idea/.idea.IMPImg/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/modules.xml +/contentModel.xml +/projectSettingsUpdater.xml +/.idea.IMPImg.iml diff --git a/IMPImg/.idea/.idea.IMPImg/.idea/encodings.xml b/IMPImg/.idea/.idea.IMPImg/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/IMPImg/.idea/.idea.IMPImg/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/IMPImg/.idea/.idea.IMPImg/.idea/indexLayout.xml b/IMPImg/.idea/.idea.IMPImg/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/IMPImg/.idea/.idea.IMPImg/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/IMPImg/.idea/.idea.IMPImg/.idea/vcs.xml b/IMPImg/.idea/.idea.IMPImg/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/IMPImg/.idea/.idea.IMPImg/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/IMPImg/IMPImg.sln b/IMPImg/IMPImg.sln new file mode 100644 index 0000000..16603ab --- /dev/null +++ b/IMPImg/IMPImg.sln @@ -0,0 +1,16 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IMPImg", "IMPImg\IMPImg.csproj", "{CCC714D7-2728-42A7-BB95-A710291584AE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CCC714D7-2728-42A7-BB95-A710291584AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CCC714D7-2728-42A7-BB95-A710291584AE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CCC714D7-2728-42A7-BB95-A710291584AE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CCC714D7-2728-42A7-BB95-A710291584AE}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/IMPImg/IMPImg/IMPImg.csproj b/IMPImg/IMPImg/IMPImg.csproj new file mode 100644 index 0000000..481dc45 --- /dev/null +++ b/IMPImg/IMPImg/IMPImg.csproj @@ -0,0 +1,12 @@ + + + + Exe + net5.0 + + + + + + + diff --git a/IMPImg/IMPImg/Program.cs b/IMPImg/IMPImg/Program.cs new file mode 100644 index 0000000..9666d7f --- /dev/null +++ b/IMPImg/IMPImg/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace IMPImg +{ + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Hello World!"); + } + } +} \ No newline at end of file diff --git a/ImgJava/.idea/.gitignore b/ImgJava/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/ImgJava/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/ImgJava/.idea/compiler.xml b/ImgJava/.idea/compiler.xml new file mode 100644 index 0000000..b73660a --- /dev/null +++ b/ImgJava/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/ImgJava/.idea/gradle.xml b/ImgJava/.idea/gradle.xml new file mode 100644 index 0000000..1fdf7d2 --- /dev/null +++ b/ImgJava/.idea/gradle.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/ImgJava/.idea/jarRepositories.xml b/ImgJava/.idea/jarRepositories.xml new file mode 100644 index 0000000..fdc392f --- /dev/null +++ b/ImgJava/.idea/jarRepositories.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/ImgJava/.idea/misc.xml b/ImgJava/.idea/misc.xml new file mode 100644 index 0000000..1700c77 --- /dev/null +++ b/ImgJava/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/ImgJava/.idea/uiDesigner.xml b/ImgJava/.idea/uiDesigner.xml new file mode 100644 index 0000000..e96534f --- /dev/null +++ b/ImgJava/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ImgJava/build.gradle.kts b/ImgJava/build.gradle.kts new file mode 100644 index 0000000..5b78a64 --- /dev/null +++ b/ImgJava/build.gradle.kts @@ -0,0 +1,26 @@ +plugins { + java + id("com.github.johnrengelman.shadow") version "6.0.0" +} + +group = "io.gitlab.jfronny" +version = "1.0" + +repositories { + mavenCentral() +} + +dependencies { + fun dependency(dependencyNotation: Any) { + implementation(dependencyNotation) + shadow(dependencyNotation) + } + + testImplementation("org.junit.jupiter:junit-jupiter-api:5.6.0") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") + dependency("org.jdom:jdom:1.1") +} + +tasks.getByName("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