├── jfxtools-awtimage
├── .gitignore
├── pom.xml
└── src
│ └── main
│ └── java
│ └── de
│ └── mpmediasoft
│ └── jfxtools
│ └── awtimage
│ └── AWTImage.java
├── jfxtools-canvas
├── .gitignore
├── src
│ └── main
│ │ ├── java
│ │ └── de
│ │ │ └── mpmediasoft
│ │ │ └── jfxtools
│ │ │ └── canvas
│ │ │ ├── ScrollAction.java
│ │ │ ├── NativeColorModel.java
│ │ │ ├── NativeRenderer.java
│ │ │ ├── Viewport.java
│ │ │ └── NativeRenderingCanvas.java
│ │ └── c
│ │ └── de_mpmediasoft_jfxtools_canvas_NativeRenderer.c
├── pom.xml
├── build-native.sh
└── docs
│ └── NativeRenderingCanvas.adoc
├── jfxtools-skiafx
├── .gitignore
├── pom.xml
└── src
│ └── main
│ └── java
│ └── de
│ └── mpmediasoft
│ └── jfxtools
│ └── skiafx
│ └── SkiaSurfaceFX.java
├── jfxtools-vlcjfx
├── .gitignore
├── pom.xml
└── src
│ └── main
│ └── java
│ └── de
│ └── mpmediasoft
│ └── jfxtools
│ └── vlcjfx
│ └── VLCJFXVideoPlayer.java
├── jfxtools-awtimage-demos
├── .gitignore
├── pom.xml
└── src
│ └── main
│ └── java
│ └── de
│ └── mpmediasoft
│ └── jfxtools
│ └── awtimage
│ └── demo
│ ├── AWTImageDemo.java
│ ├── PDFViewerDemo.java
│ └── PDFViewerDemo2.java
├── jfxtools-canvas-demos
├── .gitignore
├── src
│ └── main
│ │ └── java
│ │ └── de
│ │ └── mpmediasoft
│ │ └── jfxtools
│ │ └── canvas
│ │ └── demo
│ │ └── NativeRenderingCanvasDemo.java
└── pom.xml
├── jfxtools-jarprocessor
├── .gitignore
├── src
│ └── main
│ │ └── java
│ │ └── de
│ │ └── mpmediasoft
│ │ └── jfxtools
│ │ └── jarprocessor
│ │ ├── JARProcessor.java
│ │ ├── JARProcessorException.java
│ │ ├── AbstractJARProcessor.java
│ │ ├── processors
│ │ ├── NativeArtifactChecker.java
│ │ ├── FXMLChecker.java
│ │ └── ModuleChecker.java
│ │ └── main
│ │ └── JARProcessorRunner.java
├── pom.xml
└── doc
│ └── example_output_modulechecker.txt
├── jfxtools-skiafx-demos
├── .gitignore
├── demo1.png
├── pom.xml
└── src
│ └── main
│ └── java
│ └── de
│ └── mpmediasoft
│ └── jfxtools
│ └── skiafx
│ └── demo
│ └── SkiaSurfaceFXDemo1.java
├── jfxtools-vlcjfx-demos
├── .gitignore
├── src
│ └── main
│ │ ├── resources
│ │ └── video_player.css
│ │ └── java
│ │ └── de
│ │ └── mpmediasoft
│ │ └── jfxtools
│ │ └── vlcjfx
│ │ └── demo
│ │ ├── VLCJFXVideoPlayerDemo1.java
│ │ └── VLCJFXVideoPlayerDemo2.java
└── pom.xml
├── docs
└── articles
│ ├── JFX-Android
│ ├── .gitignore
│ ├── images
│ │ ├── 001l-mpcopilotapp2.png
│ │ ├── 001p-mpcopilotapp2.png
│ │ ├── 002-mpcopilotapp2.png
│ │ ├── 003-mpcopilotapp2.png
│ │ ├── 004-mpcopilotapp2.png
│ │ ├── 005-mpcopilotapp2.png
│ │ └── 006-mpcopilotapp2.png
│ ├── Screenshots
│ │ ├── Screenshot_20200614-143510.jpg
│ │ ├── Screenshot_20200614-143532.jpg
│ │ ├── Screenshot_20200614-143553.jpg
│ │ ├── Screenshot_20200614-143624.jpg
│ │ ├── Screenshot_20200614-143700.jpg
│ │ ├── Screenshot_20200614-143811.jpg
│ │ ├── Screenshot_20200614-160151.jpg
│ │ └── Screenshot_20200621-133841.jpg
│ └── JFX-Android.adoc
│ ├── JFX-Bundles
│ ├── .gitignore
│ └── JFX-Bundles.adoc
│ ├── JFX-Native
│ ├── .gitignore
│ ├── images
│ │ └── 000_mac_DAeCAirspaceValidator.png
│ ├── ScreenShots
│ │ └── 000_mac_DAeCAirspaceValidator.png
│ ├── updates.txt
│ └── JFX-Native.adoc
│ └── index.adoc
├── .gitignore
├── .github
└── workflows
│ └── maven-publish.yml
├── pom.xml
├── README.md
└── LICENSE
/jfxtools-awtimage/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 |
--------------------------------------------------------------------------------
/jfxtools-canvas/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 |
--------------------------------------------------------------------------------
/jfxtools-skiafx/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 |
--------------------------------------------------------------------------------
/jfxtools-vlcjfx/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 |
--------------------------------------------------------------------------------
/jfxtools-awtimage-demos/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 |
--------------------------------------------------------------------------------
/jfxtools-canvas-demos/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 |
--------------------------------------------------------------------------------
/jfxtools-jarprocessor/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 |
--------------------------------------------------------------------------------
/jfxtools-skiafx-demos/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 |
--------------------------------------------------------------------------------
/jfxtools-vlcjfx-demos/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 |
--------------------------------------------------------------------------------
/docs/articles/JFX-Android/.gitignore:
--------------------------------------------------------------------------------
1 | /JFX-Android.html
2 |
--------------------------------------------------------------------------------
/docs/articles/JFX-Bundles/.gitignore:
--------------------------------------------------------------------------------
1 | /JFX-Bundles.html
2 |
--------------------------------------------------------------------------------
/docs/articles/JFX-Native/.gitignore:
--------------------------------------------------------------------------------
1 | /JFX-Native.html
2 |
--------------------------------------------------------------------------------
/jfxtools-vlcjfx-demos/src/main/resources/video_player.css:
--------------------------------------------------------------------------------
1 | .videoPane {
2 | -fx-background-color: black;
3 | }
4 |
--------------------------------------------------------------------------------
/jfxtools-skiafx-demos/demo1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mipastgt/JFXToolsAndDemos/HEAD/jfxtools-skiafx-demos/demo1.png
--------------------------------------------------------------------------------
/jfxtools-canvas/src/main/java/de/mpmediasoft/jfxtools/canvas/ScrollAction.java:
--------------------------------------------------------------------------------
1 | package de.mpmediasoft.jfxtools.canvas;
2 |
3 | enum ScrollAction {PAN, ZOOM}
--------------------------------------------------------------------------------
/docs/articles/JFX-Android/images/001l-mpcopilotapp2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mipastgt/JFXToolsAndDemos/HEAD/docs/articles/JFX-Android/images/001l-mpcopilotapp2.png
--------------------------------------------------------------------------------
/docs/articles/JFX-Android/images/001p-mpcopilotapp2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mipastgt/JFXToolsAndDemos/HEAD/docs/articles/JFX-Android/images/001p-mpcopilotapp2.png
--------------------------------------------------------------------------------
/docs/articles/JFX-Android/images/002-mpcopilotapp2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mipastgt/JFXToolsAndDemos/HEAD/docs/articles/JFX-Android/images/002-mpcopilotapp2.png
--------------------------------------------------------------------------------
/docs/articles/JFX-Android/images/003-mpcopilotapp2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mipastgt/JFXToolsAndDemos/HEAD/docs/articles/JFX-Android/images/003-mpcopilotapp2.png
--------------------------------------------------------------------------------
/docs/articles/JFX-Android/images/004-mpcopilotapp2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mipastgt/JFXToolsAndDemos/HEAD/docs/articles/JFX-Android/images/004-mpcopilotapp2.png
--------------------------------------------------------------------------------
/docs/articles/JFX-Android/images/005-mpcopilotapp2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mipastgt/JFXToolsAndDemos/HEAD/docs/articles/JFX-Android/images/005-mpcopilotapp2.png
--------------------------------------------------------------------------------
/docs/articles/JFX-Android/images/006-mpcopilotapp2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mipastgt/JFXToolsAndDemos/HEAD/docs/articles/JFX-Android/images/006-mpcopilotapp2.png
--------------------------------------------------------------------------------
/docs/articles/JFX-Native/images/000_mac_DAeCAirspaceValidator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mipastgt/JFXToolsAndDemos/HEAD/docs/articles/JFX-Native/images/000_mac_DAeCAirspaceValidator.png
--------------------------------------------------------------------------------
/jfxtools-canvas/src/main/java/de/mpmediasoft/jfxtools/canvas/NativeColorModel.java:
--------------------------------------------------------------------------------
1 | package de.mpmediasoft.jfxtools.canvas;
2 |
3 | public enum NativeColorModel {INT_ARGB_PRE, BYTE_BGRA_PRE}
--------------------------------------------------------------------------------
/docs/articles/JFX-Android/Screenshots/Screenshot_20200614-143510.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mipastgt/JFXToolsAndDemos/HEAD/docs/articles/JFX-Android/Screenshots/Screenshot_20200614-143510.jpg
--------------------------------------------------------------------------------
/docs/articles/JFX-Android/Screenshots/Screenshot_20200614-143532.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mipastgt/JFXToolsAndDemos/HEAD/docs/articles/JFX-Android/Screenshots/Screenshot_20200614-143532.jpg
--------------------------------------------------------------------------------
/docs/articles/JFX-Android/Screenshots/Screenshot_20200614-143553.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mipastgt/JFXToolsAndDemos/HEAD/docs/articles/JFX-Android/Screenshots/Screenshot_20200614-143553.jpg
--------------------------------------------------------------------------------
/docs/articles/JFX-Android/Screenshots/Screenshot_20200614-143624.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mipastgt/JFXToolsAndDemos/HEAD/docs/articles/JFX-Android/Screenshots/Screenshot_20200614-143624.jpg
--------------------------------------------------------------------------------
/docs/articles/JFX-Android/Screenshots/Screenshot_20200614-143700.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mipastgt/JFXToolsAndDemos/HEAD/docs/articles/JFX-Android/Screenshots/Screenshot_20200614-143700.jpg
--------------------------------------------------------------------------------
/docs/articles/JFX-Android/Screenshots/Screenshot_20200614-143811.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mipastgt/JFXToolsAndDemos/HEAD/docs/articles/JFX-Android/Screenshots/Screenshot_20200614-143811.jpg
--------------------------------------------------------------------------------
/docs/articles/JFX-Android/Screenshots/Screenshot_20200614-160151.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mipastgt/JFXToolsAndDemos/HEAD/docs/articles/JFX-Android/Screenshots/Screenshot_20200614-160151.jpg
--------------------------------------------------------------------------------
/docs/articles/JFX-Android/Screenshots/Screenshot_20200621-133841.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mipastgt/JFXToolsAndDemos/HEAD/docs/articles/JFX-Android/Screenshots/Screenshot_20200621-133841.jpg
--------------------------------------------------------------------------------
/docs/articles/JFX-Native/ScreenShots/000_mac_DAeCAirspaceValidator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mipastgt/JFXToolsAndDemos/HEAD/docs/articles/JFX-Native/ScreenShots/000_mac_DAeCAirspaceValidator.png
--------------------------------------------------------------------------------
/jfxtools-jarprocessor/src/main/java/de/mpmediasoft/jfxtools/jarprocessor/JARProcessor.java:
--------------------------------------------------------------------------------
1 | package de.mpmediasoft.jfxtools.jarprocessor;
2 |
3 | import java.util.spi.ToolProvider;
4 |
5 | public interface JARProcessor {
6 |
7 | public void initialize(ToolProvider jarToolProvider, boolean verbose);
8 |
9 | public void start();
10 |
11 | public void process(String arg) throws JARProcessorException;
12 |
13 | public void finish();
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled class file
2 | *.class
3 |
4 | # Log file
5 | *.log
6 |
7 | # BlueJ files
8 | *.ctxt
9 |
10 | # Mobile Tools for Java (J2ME)
11 | .mtj.tmp/
12 |
13 | # Package Files #
14 | *.jar
15 | *.war
16 | *.nar
17 | *.ear
18 | *.zip
19 | *.tar.gz
20 | *.rar
21 |
22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
23 | hs_err_pid*
24 |
25 | # IDE and Maven artifacts
26 | .project
27 | .settings/
28 | .classpath
29 | .idea/
30 | *.iml
31 | target/
32 |
33 |
34 | /.classpath
35 | /*.project
36 | /awtimage.png
37 |
--------------------------------------------------------------------------------
/jfxtools-jarprocessor/src/main/java/de/mpmediasoft/jfxtools/jarprocessor/JARProcessorException.java:
--------------------------------------------------------------------------------
1 | package de.mpmediasoft.jfxtools.jarprocessor;
2 |
3 | @SuppressWarnings("serial")
4 | public class JARProcessorException extends Exception {
5 |
6 | public JARProcessorException() {
7 | }
8 |
9 | public JARProcessorException(String message) {
10 | super(message);
11 | }
12 |
13 | public JARProcessorException(Throwable cause) {
14 | super(cause);
15 | }
16 |
17 | public JARProcessorException(String message, Throwable cause) {
18 | super(message, cause);
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/jfxtools-vlcjfx/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | de.mpmediasoft.jfxtools
8 | jfxtools
9 | 1.0.0-SNAPSHOT
10 |
11 | jfxtools-vlcjfx
12 |
13 |
14 |
15 | uk.co.caprica
16 | vlcj
17 | 4.7.0
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/jfxtools-jarprocessor/src/main/java/de/mpmediasoft/jfxtools/jarprocessor/AbstractJARProcessor.java:
--------------------------------------------------------------------------------
1 | package de.mpmediasoft.jfxtools.jarprocessor;
2 |
3 | import java.io.File;
4 |
5 | abstract public class AbstractJARProcessor implements JARProcessor {
6 |
7 | protected File jarFile(String arg) throws JARProcessorException {
8 | File jarFile = new File(arg);
9 | if (!jarFile.canRead()) {
10 | throw new JARProcessorException("File does not exist: " + jarFile);
11 | } else if (!jarFile.getName().toLowerCase().endsWith(".jar")) {
12 | throw new JARProcessorException("File does not seem to be a JAR file: " + jarFile);
13 | } else {
14 | return jarFile;
15 | }
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/jfxtools-canvas/src/main/java/de/mpmediasoft/jfxtools/canvas/NativeRenderer.java:
--------------------------------------------------------------------------------
1 | package de.mpmediasoft.jfxtools.canvas;
2 |
3 | import java.nio.ByteBuffer;
4 |
5 | /**
6 | * The JNI interface to the native renderer.
7 | *
8 | * @author Michael Paus
9 | */
10 | public class NativeRenderer {
11 |
12 | static {
13 | System.loadLibrary("nativerenderer");
14 | }
15 |
16 | // Initialization and disposal:
17 |
18 | public native void init();
19 |
20 | public native void dispose();
21 |
22 | // Canvas creation and rendering:
23 |
24 | public native ByteBuffer createCanvas(int width, int height, int numBuffers, int nativeColorModel);
25 |
26 | public native int render();
27 |
28 | // Actions, e.g., due to user input events:
29 |
30 | public native void moveTo(int x, int y);
31 |
32 | // TODO: zoom, rotate, ...
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/jfxtools-awtimage/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | de.mpmediasoft.jfxtools
8 | jfxtools
9 | 1.0.0-SNAPSHOT
10 |
11 | jfxtools-awtimage
12 |
13 |
14 |
15 |
16 | org.apache.maven.plugins
17 | maven-compiler-plugin
18 | ${maven-compiler-plugin.version}
19 |
20 | false
21 | false
22 | 17
23 | 17
24 | false
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/docs/articles/JFX-Native/updates.txt:
--------------------------------------------------------------------------------
1 | == Missing features for Gluon/GraalVM/native-image toolchain
2 |
3 | === Missing support for more than one locale
4 | * https://github.com/oracle/graal/issues/2908
5 |
6 | === Media
7 | * No media support on some platforms
8 |
9 | === NSMenuFX
10 | * The platform menu bar isn't supported yet. (VERIFY)
11 | * The new version has problems with the JNA library.
12 |
13 | === Configuration too complicated and error prone
14 | * Integrate native image agent into workflow.
15 | Seems to work perfectly well!
16 | (Does it conflict with the default config options?)
17 |
18 | === Native images far too big to be useful
19 | * UPX to the rescue
20 | * This could be a unique selling point for JavaFX, compared to other competing technologies such as Electron.
21 |
22 | === No option to create a proper application bundle
23 | * Seems to be easy on macOS. It's just a tiny wrapper plus one icon.
24 |
25 | === No option to create a platform installer bundle
26 | * Should be easy to do with jpackage. (VERIFY)
27 |
28 |
--------------------------------------------------------------------------------
/.github/workflows/maven-publish.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a package using Maven and then publish it to GitHub packages when a release is created
2 | # For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#apache-maven-with-a-settings-path
3 |
4 | name: Maven Package
5 |
6 | on: [push, workflow_dispatch]
7 |
8 | jobs:
9 | build:
10 |
11 | runs-on: ubuntu-latest
12 | permissions:
13 | contents: read
14 | packages: write
15 |
16 | steps:
17 | - uses: actions/checkout@v2
18 | - name: Set up JDK 16
19 | uses: actions/setup-java@v2
20 | with:
21 | java-version: '16'
22 | distribution: 'adopt'
23 | server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
24 | settings-path: ${{ github.workspace }} # location for the settings.xml file
25 |
26 | - name: Build with Maven
27 | run: mvn -B package --file pom.xml
28 |
29 | - name: Publish to GitHub Packages Apache Maven
30 | run: mvn deploy -s $GITHUB_WORKSPACE/settings.xml
31 | env:
32 | GITHUB_TOKEN: ${{ github.token }}
33 |
--------------------------------------------------------------------------------
/jfxtools-canvas/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | de.mpmediasoft.jfxtools
8 | jfxtools
9 | 1.0.0-SNAPSHOT
10 |
11 | jfxtools-canvas
12 |
13 |
14 |
15 |
16 | exec-maven-plugin
17 | org.codehaus.mojo
18 | ${exec-maven-plugin.version}
19 |
20 |
21 | Build native renderer
22 | install
23 |
24 | exec
25 |
26 |
27 |
28 |
29 | ${project.basedir}
30 | ./build-native.sh
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/jfxtools-jarprocessor/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | de.mpmediasoft.jfxtools
8 | jfxtools
9 | 1.0.0-SNAPSHOT
10 |
11 | jfxtools-jarprocessor
12 |
13 |
14 | de.mpmediasoft.jfxtools.jarprocessor.main.JARProcessorRunner
15 |
16 |
17 |
18 |
19 |
20 |
21 | org.codehaus.mojo
22 | exec-maven-plugin
23 | ${exec-maven-plugin.version}
24 |
25 |
26 |
27 | java
28 |
29 |
30 |
31 |
32 | ${mainClassName}
33 |
34 |
35 |
36 |
37 | org.apache.maven.plugins
38 | maven-jar-plugin
39 | ${maven-jar-plugin.version}
40 |
41 |
42 |
43 | ${mainClassName}
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/jfxtools-canvas-demos/src/main/java/de/mpmediasoft/jfxtools/canvas/demo/NativeRenderingCanvasDemo.java:
--------------------------------------------------------------------------------
1 | package de.mpmediasoft.jfxtools.canvas.demo;
2 |
3 | import de.mpmediasoft.jfxtools.canvas.NativeRenderingCanvas;
4 | import javafx.application.Application;
5 | import javafx.scene.Scene;
6 | import javafx.scene.control.Label;
7 | import javafx.scene.layout.StackPane;
8 | import javafx.stage.Stage;
9 |
10 | /**
11 | * A simple demo to show how the NativeRenderingCanvas class is supposed to be used.
12 | *
13 | * @author Michael Paus
14 | */
15 | public class NativeRenderingCanvasDemo extends Application {
16 |
17 | private NativeRenderingCanvas canvas;
18 |
19 | @Override
20 | public void init() {
21 | System.out.println("java.runtime.version: " + System.getProperty("java.runtime.version", "(undefined)"));
22 | System.out.println("javafx.runtime.version: " + System.getProperty("javafx.runtime.version", "(undefined)"));
23 | }
24 |
25 | @Override
26 | public void start(Stage primaryStage) throws Exception {
27 | StackPane root = new StackPane();
28 |
29 | canvas = new NativeRenderingCanvas();
30 |
31 | Label label = new Label("This is JavaFX");
32 | label.setMouseTransparent(true);
33 | label.setStyle("-fx-font-size: 64pt; -fx-font-family: Arial; -fx-font-weight: bold; -fx-text-fill: white; -fx-opacity: 0.8;");
34 |
35 | root.getChildren().addAll(canvas.getRoot(), label);
36 |
37 | Scene scene = new Scene(root, 1000, 800);
38 | primaryStage.setScene(scene);
39 | primaryStage.show();
40 | }
41 |
42 | @Override
43 | public void stop() {
44 | canvas.dispose();
45 | }
46 |
47 | public static void main(String[] args) {
48 | launch(args);
49 | }
50 |
51 | }
52 |
53 | class NativeRenderingCanvasDemoLauncher {public static void main(String[] args) {NativeRenderingCanvasDemo.main(args);}}
54 |
--------------------------------------------------------------------------------
/jfxtools-skiafx/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | de.mpmediasoft.jfxtools
8 | jfxtools
9 | 1.0.0-SNAPSHOT
10 |
11 | jfxtools-skiafx
12 |
13 |
14 |
15 | build-mac
16 |
17 | mac
18 |
19 |
20 | macos-x64
21 |
22 |
23 |
24 | build-linux
25 |
26 | linux
27 |
28 |
29 | linux-x64
30 |
31 |
32 |
33 | build-windows
34 |
35 | windows
36 |
37 |
38 | windows-x64
39 |
40 |
41 |
42 |
43 |
44 |
45 | io.github.humbleui
46 | skija-${skija.platform}
47 | 0.116.1
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/jfxtools-canvas-demos/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | de.mpmediasoft.jfxtools
8 | jfxtools
9 | 1.0.0-SNAPSHOT
10 |
11 | jfxtools-canvas-demos
12 |
13 |
14 |
15 |
16 | org.codehaus.mojo
17 | exec-maven-plugin
18 | ${exec-maven-plugin.version}
19 |
20 |
21 |
22 | exec
23 |
24 |
25 |
26 |
27 | ${JAVA_HOME}/bin/java
28 |
29 | -classpath
30 |
31 | -ea
32 | -Djava.library.path=../jfxtools-canvas/target/libs/
33 | de.mpmediasoft.jfxtools.canvas.demo.NativeRenderingCanvasDemoLauncher
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | de.mpmediasoft.jfxtools
43 | jfxtools-canvas
44 | ${jfxtools.version}
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/jfxtools-skiafx-demos/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | de.mpmediasoft.jfxtools
8 | jfxtools
9 | 1.0.0-SNAPSHOT
10 |
11 | jfxtools-skiafx-demos
12 |
13 |
14 |
15 |
16 | org.codehaus.mojo
17 | exec-maven-plugin
18 | ${exec-maven-plugin.version}
19 |
20 |
21 |
22 | exec
23 |
24 |
25 |
26 |
27 | ${JAVA_HOME}/bin/java
28 |
29 | -classpath
30 |
31 | -ea
32 | --enable-preview
33 | --add-opens=java.base/java.nio=ALL-UNNAMED
34 | de.mpmediasoft.jfxtools.skiafx.demo.SkiaSurfaceFXDemo1Launcher
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | de.mpmediasoft.jfxtools
44 | jfxtools-skiafx
45 | ${jfxtools.version}
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/jfxtools-vlcjfx-demos/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | de.mpmediasoft.jfxtools
8 | jfxtools
9 | 1.0.0-SNAPSHOT
10 |
11 | jfxtools-vlcjfx-demos
12 |
13 |
14 |
15 |
16 | org.codehaus.mojo
17 | exec-maven-plugin
18 | 1.6.0
19 |
20 |
21 | vlcjfx-demo1
22 |
23 | java
24 |
25 |
26 | de.mpmediasoft.jfxtools.vlcjfx.demo.VLCJFXVideoPlayerDemo1Launcher
27 |
28 |
29 |
30 |
31 | vlcjfx-demo2
32 |
33 | java
34 |
35 |
36 | de.mpmediasoft.jfxtools.vlcjfx.demo.VLCJFXVideoPlayerDemo2Launcher
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | de.mpmediasoft.jfxtools
47 | jfxtools-vlcjfx
48 | ${jfxtools.version}
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/docs/articles/index.adoc:
--------------------------------------------------------------------------------
1 | = Articles about various topics
2 | Dr.-Ing. Michael Paus, mpMediaSoft GmbH
3 | Version 1.0.0, 2021-01-23
4 | :doctype: article
5 | :encoding: utf-8
6 | :lang: en
7 | :toc: left
8 | :numbered:
9 | :ext-relative: .html
10 |
11 | [.lead]
12 | Articles about various software and aviation topics. The software articles are mostly related to Java, JavaFX and GraalVM/Native-image as well as Kotlin and Jetpack Compose. The aviation topics are about using the software in the air.
13 |
14 | [NOTE]
15 | ====
16 | Scroll down for the latest articles.
17 | ====
18 |
19 | == Software
20 |
21 | === Building native, AOT compiled, real-world JavaFX applications
22 |
23 | A summary of my lessons learned converting an existing JavaFX application to a native,
24 | AOT compiled, real-world application using the Gluon Client Maven plugin which is based
25 | on the GraalVM `native-image` toolchain.
26 |
27 | link:JFX-Native/JFX-Native{ext-relative}[Building native, AOT compiled, real-world JavaFX applications]
28 |
29 | === Bundling real-world JavaFX applications
30 |
31 | A summary of my lessons learned bundling real-world JavaFX application with
32 | various different techniques.
33 |
34 | link:JFX-Bundles/JFX-Bundles{ext-relative}[Bundling real-world JavaFX applications]
35 |
36 | === JavaFX on Android
37 |
38 | A summary of my lessons learned building a first, still simple, pure JavaFX Android
39 | application based on the components of an already existing JavaFX application using
40 | the Gluon Client Maven plugin which is based on the GraalVM `native-image` toolchain.
41 |
42 | link:JFX-Android/JFX-Android{ext-relative}[JavaFX on Android]
43 |
44 | == Aviation
45 |
46 | === Flight testing standard mobile cellular phone network technology in the lower airspace
47 |
48 | Flight test on 24.10.2021 in Hermuthausen to investigate the performance of standard mobile cellular phone network technology in the lower airspace.
49 |
50 | link:https://mpmediasoft.de/articles/FlightTest20211024/FlightTest20211024.html[Performance of standard mobile cellular phone network technology in the lower airspace]
51 |
--------------------------------------------------------------------------------
/jfxtools-canvas/build-native.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Building the native parts of the project.
4 | # It follows https://www.baeldung.com/jni
5 | # For Windows you will need to have http://www.mingw.org/ installed.
6 | # It should work for macOS out of the box but the script
7 | # is totally untested on Linux and Windows (with MinGW)
8 |
9 | cd `dirname $0`
10 |
11 | JSRC=src/main/java
12 | CSRC=src/main/c
13 | LIBS=target/libs
14 | TINC=target/include
15 | TTMP=target/tmp
16 |
17 | mkdir -p $LIBS
18 | mkdir -p $TINC
19 | mkdir -p $TTMP
20 |
21 | echo "Generate JNI C header file"
22 | javac -h $TINC $JSRC/de/mpmediasoft/jfxtools/canvas/NativeRenderer.java
23 | rm $JSRC/de/mpmediasoft/jfxtools/canvas/NativeRenderer.class
24 |
25 | if [[ "$OSTYPE" == "linux-gnu" ]]; then
26 | echo "Creating native library for Linux"
27 | gcc -c -fPIC -I${TINC} -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux \
28 | $CSRC/de_mpmediasoft_jfxtools_canvas_NativeRenderer.c \
29 | -o $TTMP/de_mpmediasoft_jfxtools_canvas_NativeRenderer.o
30 | gcc -shared -o $LIBS/libnativerenderer.so $TTMP/de_mpmediasoft_jfxtools_canvas_NativeRenderer.o -lc
31 |
32 | elif [[ "$OSTYPE" == "darwin"* ]]; then
33 | echo "Creating native library for macOS"
34 | gcc -c -fPIC -I${TINC} -I${JAVA_HOME}/include -I${JAVA_HOME}/include/darwin \
35 | $CSRC/de_mpmediasoft_jfxtools_canvas_NativeRenderer.c \
36 | -o $TTMP/de_mpmediasoft_jfxtools_canvas_NativeRenderer.o
37 | gcc -dynamiclib -o $LIBS/libnativerenderer.dylib $TTMP/de_mpmediasoft_jfxtools_canvas_NativeRenderer.o -lc
38 |
39 | elif [[ "$OSTYPE" == "cygwin" ]]; then
40 | # POSIX compatibility layer and Linux environment emulation for Windows
41 | echo "Currently unsupported OS"
42 |
43 | elif [[ "$OSTYPE" == "msys" ]]; then
44 | echo "Creating native library for Lightweight shell and GNU utilities compiled for Windows (part of MinGW)"
45 | gcc -c -I${TINC} -I%JAVA_HOME%\include -I%JAVA_HOME%\include\win32 $CSRC\de_mpmediasoft_jfxtools_canvas_NativeRenderer.c -o $TTMP\de_mpmediasoft_jfxtools_canvas_NativeRenderer.o
46 | gcc -shared -o $LIBS\libnativerenderer.dll $TTMP\de_mpmediasoft_jfxtools_canvas_NativeRenderer.o -Wl,--add-stdcall-alias
47 |
48 | elif [[ "$OSTYPE" == "win32" ]]; then
49 | # I'm not sure this can happen.
50 | echo "Currently unsupported OS"
51 |
52 | elif [[ "$OSTYPE" == "freebsd"* ]]; then
53 | # ...
54 | echo "Currently unsupported OS"
55 |
56 | else
57 | # Unknown.
58 | echo "Unknown OS"
59 | fi
60 |
61 |
--------------------------------------------------------------------------------
/jfxtools-vlcjfx-demos/src/main/java/de/mpmediasoft/jfxtools/vlcjfx/demo/VLCJFXVideoPlayerDemo1.java:
--------------------------------------------------------------------------------
1 | package de.mpmediasoft.jfxtools.vlcjfx.demo;
2 |
3 | import de.mpmediasoft.jfxtools.vlcjfx.VLCJFXVideoPlayer;
4 | import javafx.application.Application;
5 | import javafx.scene.Scene;
6 | import javafx.scene.image.ImageView;
7 | import javafx.scene.layout.StackPane;
8 | import javafx.stage.Stage;
9 |
10 | /**
11 | * A minimal demo program to show how the VLCJFXVideoPlayer class is supposed to be used.
12 | *
13 | * This should work on macOS and Linux but there currently seem to be problems with the VLC code
14 | * on Windows.
15 | *
16 | * In order to run the code, a recent version of the VLC player (3.0.x+) must be installed
17 | * on the system. Other dependencies can be found in the pom.xml.
18 | *
19 | * @author Michael Paus
20 | */
21 | public class VLCJFXVideoPlayerDemo1 extends Application {
22 |
23 | private static final String VIDEO_FILE =
24 | // "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4";
25 | "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/TearsOfSteel.mp4";
26 | // "http://ftp.nluug.nl/pub/graphics/blender/demo/movies/ToS/tearsofsteel_4k.mov";
27 |
28 | private final double WIDTH = 1200;
29 | private final double HEIGHT = 675;
30 |
31 | private VLCJFXVideoPlayer videoPlayer;
32 |
33 | private ImageView videoImageView;
34 |
35 | @Override
36 | public void init() {
37 | System.out.println("java.runtime.version: " + System.getProperty("java.runtime.version", "(undefined)"));
38 | System.out.println("javafx.runtime.version: " + System.getProperty("javafx.runtime.version", "(undefined)"));
39 | }
40 |
41 | @Override
42 | public void start(Stage primaryStage) throws Exception {
43 | videoPlayer = new VLCJFXVideoPlayer();
44 |
45 | StackPane root = new StackPane();
46 | root.getStyleClass().add("videoPane");
47 | videoImageView = new ImageView();
48 | videoImageView.setPreserveRatio(true);
49 | videoImageView.fitWidthProperty().bind(root.widthProperty());
50 | videoImageView.fitHeightProperty().bind(root.heightProperty());
51 | videoImageView.imageProperty().bind(videoPlayer.videoImageProperty());
52 | root.getChildren().add(videoImageView);
53 |
54 | Scene scene = new Scene(root, WIDTH, HEIGHT);
55 | scene.getStylesheets().add("/video_player.css");
56 | primaryStage.setScene(scene);
57 | primaryStage.show();
58 |
59 | videoPlayer.mediaResourceLocatorProperty().set(VIDEO_FILE);
60 | }
61 |
62 | @Override
63 | public void stop() throws Exception {
64 | videoPlayer.dispose();
65 | }
66 |
67 | public static void main(String[] args) {
68 | launch(args);
69 | }
70 |
71 | }
72 |
73 | //Launch via this class to avoid module system headaches.
74 | class VLCJFXVideoPlayerDemo1Launcher {public static void main(String[] args) {VLCJFXVideoPlayerDemo1.main(args);}}
75 |
--------------------------------------------------------------------------------
/jfxtools-awtimage-demos/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | de.mpmediasoft.jfxtools
8 | jfxtools
9 | 1.0.0-SNAPSHOT
10 |
11 | jfxtools-awtimage-demos
12 |
13 |
14 |
15 |
16 | org.codehaus.mojo
17 | exec-maven-plugin
18 | 1.6.0
19 |
20 |
21 | AWTImageDemo
22 |
23 | java
24 |
25 |
26 | de.mpmediasoft.jfxtools.awtimage.demo.AWTImageDemoLauncher
27 |
28 |
29 |
30 |
31 | PDFViewerDemo
32 |
33 | java
34 |
35 |
36 | de.mpmediasoft.jfxtools.awtimage.demo.PDFViewerDemo
37 |
38 |
39 |
40 |
41 | PDFViewerDemo2
42 |
43 | java
44 |
45 |
46 | de.mpmediasoft.jfxtools.awtimage.demo.PDFViewerDemo2
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | de.mpmediasoft.jfxtools
57 | jfxtools-awtimage
58 | ${jfxtools.version}
59 |
60 |
61 |
62 | org.openjfx
63 | javafx-swing
64 | ${openjfx.version}
65 |
66 |
67 |
68 | org.apache.pdfbox
69 | pdfbox
70 | ${pdfbox.version}
71 |
72 |
73 |
74 | org.apache.pdfbox
75 | io
76 | ${pdfbox-io.version}
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/jfxtools-canvas/src/main/java/de/mpmediasoft/jfxtools/canvas/Viewport.java:
--------------------------------------------------------------------------------
1 | package de.mpmediasoft.jfxtools.canvas;
2 |
3 | import java.util.Objects;
4 |
5 | /**
6 | * Immutable viewport class.
7 | *
8 | * @author Michael Paus
9 | */
10 | public class Viewport {
11 |
12 | private final int minX;
13 | private final int minY;
14 | private final int width;
15 | private final int height;
16 |
17 | public Viewport() {
18 | this(0, 0, -1, -1);
19 | }
20 |
21 | public Viewport(int minX, int minY, int width, int height) {
22 | this.minX = minX;
23 | this.minY = minY;
24 | this.width = width;
25 | this.height = height;
26 | }
27 |
28 | public Viewport withLocation(int minX, int minY) {
29 | return new Viewport(minX, minY, width, height);
30 | }
31 |
32 | public Viewport withDeltaLocation(int deltaX, int deltaY) {
33 | return new Viewport(minX + deltaX, minY + deltaY, width, height);
34 | }
35 |
36 | public Viewport withSize(int width, int height) {
37 | return new Viewport(minX, minY, width, height);
38 | }
39 |
40 | // Increment or decrement the view size in steps of view_incr.
41 | public Viewport withSizeIncrement(int width, int height, int sizeIncrement) {
42 | if (width > 0 && height > 0 && sizeIncrement > 0) {
43 | int newNrViewWidth = (width % sizeIncrement > 0) ? (width / sizeIncrement + 1) * sizeIncrement : (width / sizeIncrement) * sizeIncrement;
44 | int newNrViewHeight = (height % sizeIncrement > 0) ? (height / sizeIncrement + 1) * sizeIncrement : (height / sizeIncrement) * sizeIncrement;
45 |
46 | if (newNrViewWidth != this.width || newNrViewHeight != this.height) {
47 | return this.withSize(newNrViewWidth, newNrViewHeight);
48 | }
49 | }
50 | return this;
51 | }
52 |
53 | public Viewport withDeltaSize(int deltaWidth, int deltaHeight) {
54 | return new Viewport(minX, minY, width + deltaWidth, height + deltaHeight);
55 | }
56 |
57 | public int getMinX() {
58 | return minX;
59 | }
60 |
61 | public int getMinY() {
62 | return minY;
63 | }
64 |
65 | public int getWidth() {
66 | return width;
67 | }
68 |
69 | public int getHeight() {
70 | return height;
71 | }
72 |
73 | public boolean isEmpty() {
74 | return width < 0 || height < 0;
75 | }
76 |
77 | @Override
78 | public int hashCode() {
79 | return Objects.hash(height, minX, minY, width);
80 | }
81 |
82 | @Override
83 | public boolean equals(Object obj) {
84 | if (this == obj)
85 | return true;
86 | if (obj == null)
87 | return false;
88 | if (getClass() != obj.getClass())
89 | return false;
90 | Viewport other = (Viewport) obj;
91 | return height == other.height && minX == other.minX && minY == other.minY && width == other.width;
92 | }
93 |
94 | @Override
95 | public String toString() {
96 | return "Viewport [minX=" + minX + ", minY=" + minY + ", width=" + width + ", height=" + height + "]";
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/docs/articles/JFX-Bundles/JFX-Bundles.adoc:
--------------------------------------------------------------------------------
1 | = Bundling real-world JavaFX applications
2 | Dr.-Ing. Michael Paus, mpMediaSoft GmbH
3 | Version 2.0.1, 2021-01-31
4 | :doctype: article
5 | :encoding: utf-8
6 | :lang: en
7 | :toc: left
8 | :numbered:
9 |
10 | [.lead]
11 | A summary of my lessons learned bundling a real-world JavaFX application with
12 | various different techniques.
13 |
14 | == Bundle sizes
15 |
16 | The following table shows the resulting executable bundle sizes (application bundle and installer bundles) resulting from the various bundling techniques.
17 |
18 | .Bundle sizes for packaged application.
19 | |===
20 | |Technique |Size (.app) |Size (.dmg)
21 |
22 | |jpackage
23 | |210.9 MB
24 | |132.0 MB
25 |
26 | |jpackage + jlink
27 | |126.4 MB
28 | |109.2 MB
29 |
30 | |jpackage + jlink + +
31 | Maven shade with minimizeJar
32 | |<100 MB (currently not available)
33 | |<100 MB (currently not available)
34 | |===
35 |
36 | In this table the following techniques are compared:
37 |
38 | * jpackage
39 | ** Pure jpackage bundling the standard JRE (17-ea+6)
40 | * jpackage + jlink
41 | ** Jpackage bundling a custom JRE created via jlink (17-ea+6, customized via jdeps).
42 | * jpackage + jlink + Maven shade with minimizeJar
43 | ** Jpackage bundling a shrinked uber-jar with a custom JRE created via jlink (17-ea+6, customized via jdeps).
44 |
45 | The next table shows the resulting executable native-image sizes.
46 |
47 | .Native image sizes.
48 | |===
49 | |Technique |Size
50 |
51 | |Original
52 | |134.8 MB
53 |
54 | |UPX
55 | |44.9 MB
56 |
57 | |UPX --best
58 | |42.4 MB
59 | |===
60 |
61 | In this table the following techniques are compared:
62 |
63 | * Original
64 | ** GluonHQ client-maven-plugin + substrate building on GraalVM/native-image (21.0.0)
65 | * UPX
66 | ** Original compressed with UPX
67 | * UPX --best
68 | ** Original compressed with UPX --best (takes very long)
69 |
70 | == Discussion
71 |
72 | The jpackage variants could be further improved if one would also shrink the JDK part,
73 | which jlink does only on a whole module basis but not for individual classes or even methods.
74 |
75 | I will try to further shrink that via ProGuard but this is complicated by the fact
76 | that the JDK is not packaged as a JAR file anymore. I am pretty sure though that the total size can be brought down to less than 50 MB if all optimization potential is exploited.
77 |
78 | The original native variant is in this respect disappointing though. All the potential optimizations
79 | that a tool like ProGuard could still apply to the other variants are, according to the
80 | documentation, already done by the native variant, which leaves no more opportunity for
81 | further optimizations.
82 | In addition to that the native variant is not even feature complete. E.g., it only supports
83 | a single locale which of course reduces the size of the resulting bundle in a non-acceptable way.
84 | Some normally used code is also not included because it is currently not supported.
85 |
86 | A further possibility is to compress the native image with a tool like UPX (the Ultimate Packer for eXecutables, https://upx.github.io/). This brings down the native image size substantially and I haven't observed any noticable impact on the startup speed. So, this seems the way to go here for me. With UPX applied, this is currently the variant which provides the smallest image size and best startup speed.
--------------------------------------------------------------------------------
/jfxtools-canvas/docs/NativeRenderingCanvas.adoc:
--------------------------------------------------------------------------------
1 | = NativeRenderingCanvas
2 |
3 | This is an example to show how some native renderer can be integrated seemlessly into
4 | JavaFX. It uses the new WritableImage of JavaFX 13 with support for Buffers to improve performance.
5 |
6 | It consists of the following parts:
7 |
8 | * NativeRenderingCanvasDemo: A simple demo to show how the NativeRenderingCanvas class is supposed
9 | to be used.
10 | * NativeRenderingCanvas: A native rendering canvas. The assumption is that some native renderer
11 | produces an image provided as an IntBuffer or ByteBuffer. The PixelFormats
12 | must be IntArgbPre or ByteBgraPre respectively. For the API see NativeRenderer.
13 | This buffer is then used to create an Image which is bound to an ImageView.
14 | This class manages the direct display of this Image in a Pane and reacts to
15 | user input via mouse input or gestures on touch devices.
16 | * NativeRenderer: The JNI interface to the native renderer.
17 | * de_mpmediasoft_jfxtools_canvas_NativeRenderer.c: A C implementation of the JNI interface as defined in NativeRenderer.java.
18 | The code in here is not really relevant for the example. It just renders a map
19 | consisting of square red and green tiles on a blue background. It is
20 | basically just a placeholder for some real code which uses, e.g., OpenGL or
21 | some other rendering library to create an image representation in a memory buffer.
22 |
23 | The key points of this example are the following: The NativeRenderingCanvas provides a
24 | Pane which can be directly connected to some layout-pane of the JavaFX scene graph.
25 | Whenever this pane is resized it is decided whether the rendered image also has to be
26 | resized. For performance reasons this is only done in increments of 64 pixels. If the
27 | image size has to be changed, the native renderer is told to create a new canvas which
28 | is returned as a ByteBuffer. At this point the native renderer is also told how many
29 | buffers and which color model should be used.
30 |
31 | JavaFX currently does not support double-buffering but it can be emulated with a little
32 | trick. When we use two buffers, we actually create an image which has twice the hight
33 | of the actually required image. The renderer then renders intermittently into the upper
34 | and the lower half of this image. When the rendering completes the viewport of the internal
35 | ImageView is set according to the used buffer. The only prerequisite for this trick is
36 | that the native renderer does support double-buffering and can ensure that the two
37 | buffers reside in a contiguous piece of memory with the described layout.
38 |
39 | It is crucial for the performance that the native renderer always renders directly into the
40 | allocated buffer and does not create copies of the buffer other than getting the rendered
41 | image from the graphics hardware into main memory. This transfer into main memory is
42 | not ideal but is currently the most portable solution for a JavaFX integration and is
43 | sufficient for many applications. The nice thing is that this is a constant overhead which
44 | is independent of the complexity of the rendered graphics.
45 |
46 | The user can interact with the renderer via mouse input or gestures on touch devices.
47 | These events are mapped to corresponding application specific commands to update the
48 | rendering parameters. For this example I have implemented moving arround the graphics
49 | via dragging with the mouse or a scrolling gesture on a touch device, e.g., movement
50 | of two fingers on a touch pad. (The generated inertial events show nicely how smooth
51 | the movement is.)
52 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 4.0.0
5 | de.mpmediasoft.jfxtools
6 | jfxtools
7 | 1.0.0-SNAPSHOT
8 | pom
9 | JFXToolsAndDemos
10 | A collection of tools and demos for JavaFX.
11 |
12 |
13 |
14 |
15 | UTF-8
16 |
17 | 3.11.0
18 | 3.5.0
19 | 3.3.0
20 | 3.2.2
21 | 3.3.0
22 | 3.1.1
23 |
24 |
25 |
26 | 1.0.0-SNAPSHOT
27 | 3.0.0-RC1
28 | 3.0.0-alpha3
29 | 21
30 | 21.0.2
31 |
32 |
33 |
34 |
35 |
36 | org.apache.maven.plugins
37 | maven-compiler-plugin
38 | ${maven-compiler-plugin.version}
39 |
40 | false
41 | false
42 | ${openjdk.version}
43 | ${openjdk.version}
44 | true
45 |
46 |
47 |
48 | org.apache.maven.plugins
49 | maven-jar-plugin
50 | ${maven-jar-plugin.version}
51 |
52 |
53 |
54 |
55 | org.apache.maven.plugins
56 | maven-surefire-plugin
57 | ${maven-surefire-plugin.version}
58 |
59 |
60 | org.apache.maven.plugins
61 | maven-source-plugin
62 | ${maven-source-plugin.version}
63 |
64 |
65 | attach-sources
66 |
67 | jar
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | github
78 | GitHub mipastgt Apache Maven Packages
79 | https://maven.pkg.github.com/mipastgt/JFXToolsAndDemos
80 |
81 |
82 |
83 |
84 |
85 | org.openjfx
86 | javafx-base
87 | ${openjfx.version}
88 |
89 |
90 | org.openjfx
91 | javafx-graphics
92 | ${openjfx.version}
93 |
94 |
95 | org.openjfx
96 | javafx-controls
97 | ${openjfx.version}
98 |
99 |
100 |
101 |
102 | jfxtools-jarprocessor
103 | jfxtools-vlcjfx
104 | jfxtools-vlcjfx-demos
105 | jfxtools-awtimage
106 | jfxtools-awtimage-demos
107 | jfxtools-canvas
108 | jfxtools-canvas-demos
109 | jfxtools-skiafx
110 | jfxtools-skiafx-demos
111 |
112 |
113 |
--------------------------------------------------------------------------------
/jfxtools-awtimage/src/main/java/de/mpmediasoft/jfxtools/awtimage/AWTImage.java:
--------------------------------------------------------------------------------
1 | package de.mpmediasoft.jfxtools.awtimage;
2 |
3 | import java.awt.Graphics2D;
4 | import java.awt.image.BufferedImage;
5 | import java.awt.image.DataBuffer;
6 | import java.awt.image.DataBufferInt;
7 | import java.nio.IntBuffer;
8 |
9 | import javafx.geometry.Rectangle2D;
10 | import javafx.scene.image.Image;
11 | import javafx.scene.image.PixelBuffer;
12 | import javafx.scene.image.PixelFormat;
13 | import javafx.scene.image.WritableImage;
14 | import javafx.util.Callback;
15 |
16 | /**
17 | * A simple wrapper arround an AWT image which utilizes the new WritableImage
18 | * of JavaFX 13 with support for Buffers. Internally a JavaFX image is created
19 | * which directly uses the same memory as the AWT image. So if you render
20 | * into the AWT image with a AWT graphics context, the result will immediately
21 | * appear on the screen.
22 | *
23 | * @author Michael Paus
24 | */
25 | public class AWTImage {
26 |
27 | private BufferedImage awtImage;
28 | private Graphics2D g2d;
29 | private PixelBuffer pixelBuffer;
30 | private WritableImage fxImage;
31 | private Callback registeredUpdateCallback;
32 |
33 | /**
34 | * Constructs an internal BufferedImage with the given width and height.
35 | *
36 | * @param width image width
37 | * @param height image height
38 | */
39 | public AWTImage(int width, int height) {
40 | this(new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE));
41 | }
42 |
43 | /**
44 | * Wraps an already existing BufferedImage. (Must be of type TYPE_INT_ARGB_PRE).
45 | *
46 | * @param awtImage the image to be wrapped.
47 | */
48 | public AWTImage(BufferedImage awtImage) {
49 | this.awtImage = awtImage;
50 | g2d = (Graphics2D) awtImage.getGraphics();
51 |
52 | DataBuffer db = awtImage.getRaster().getDataBuffer();
53 | DataBufferInt dbi = (DataBufferInt) db;
54 | int[] rawInts = dbi.getData();
55 | IntBuffer ib = IntBuffer.wrap(rawInts);
56 | assert rawInts.length == awtImage.getWidth() * awtImage.getHeight();
57 |
58 | PixelFormat pixelFormat = PixelFormat.getIntArgbPreInstance();
59 | pixelBuffer = new PixelBuffer<>(awtImage.getWidth(), awtImage.getHeight(), ib, pixelFormat);
60 | fxImage = new WritableImage(pixelBuffer);
61 | pixelBuffer.updateBuffer(pb -> null);
62 | }
63 |
64 | /**
65 | * Get access to the internal JavaFX image.
66 | *
67 | * @return the internal JavaFX image.
68 | */
69 | public Image getFXImage() {return fxImage;}
70 |
71 | /**
72 | * Get access to the internal AWT image.
73 | *
74 | * @return the internal AWT image.
75 | */
76 | public BufferedImage getAWTImage() {return awtImage;}
77 |
78 | /**
79 | * Get the width of the image.
80 | *
81 | * @return the width of the image.
82 | */
83 | public int getWidth() {return awtImage.getWidth();}
84 |
85 | /**
86 | * Get the height of the image.
87 | *
88 | * @return the height of the image.
89 | */
90 | public int getHeight() {return awtImage.getHeight();}
91 |
92 | /**
93 | * Update the image via a one-time-callback.
94 | *
95 | * @param oneTimeUpdateCallback a one-time-callback.
96 | */
97 | public void update(Callback oneTimeUpdateCallback) {
98 | if (oneTimeUpdateCallback != null) {
99 | pixelBuffer.updateBuffer(pb -> {
100 | final java.awt.geom.Rectangle2D r = oneTimeUpdateCallback.call(g2d);
101 | return (r != null) ? (r.isEmpty() ? Rectangle2D.EMPTY : new Rectangle2D(r.getX(), r.getY(), r.getWidth(), r.getHeight())) : null;
102 | });
103 | }
104 | }
105 |
106 | /**
107 | * Register a call-back which is used every time the update() function is called.
108 | *
109 | * @param registeredUpdateCallback a call-back which is used every time the update() function is called.
110 | */
111 | public void setOnUpdate(Callback registeredUpdateCallback) {
112 | this.registeredUpdateCallback = registeredUpdateCallback;
113 | }
114 |
115 | /**
116 | * Update the image via the registerd call-back.
117 | */
118 | public void update() {
119 | update(registeredUpdateCallback);
120 | }
121 |
122 | }
123 |
--------------------------------------------------------------------------------
/jfxtools-jarprocessor/src/main/java/de/mpmediasoft/jfxtools/jarprocessor/processors/NativeArtifactChecker.java:
--------------------------------------------------------------------------------
1 | package de.mpmediasoft.jfxtools.jarprocessor.processors;
2 |
3 | import java.io.ByteArrayOutputStream;
4 | import java.io.File;
5 | import java.io.IOException;
6 | import java.io.PrintStream;
7 | import java.net.URI;
8 | import java.nio.file.FileSystem;
9 | import java.nio.file.FileSystems;
10 | import java.nio.file.Files;
11 | import java.nio.file.Path;
12 | import java.util.Collections;
13 | import java.util.HashSet;
14 | import java.util.Set;
15 | import java.util.spi.ToolProvider;
16 |
17 | import de.mpmediasoft.jfxtools.jarprocessor.AbstractJARProcessor;
18 | import de.mpmediasoft.jfxtools.jarprocessor.JARProcessorException;
19 |
20 | /**
21 | * This jar-processor analyzes a list of jar-files and lists all native artifacts
22 | * contained in each file. All files which end with ".o", ".a", ".so", ".dll", ".dylib"
23 | * or ".jnilib" are listed.
24 | *
25 | * This is useful to know if you want to strip unneeded files from a build or if you want
26 | * to check if all native artifacts in your build have been properly signed. This is, e.g,
27 | * necessary to get a bundled app notarized by Apple.
28 | *
29 | * This code needs Java 11+.
30 | *
31 | * @author mpaus
32 | */
33 | public class NativeArtifactChecker extends AbstractJARProcessor {
34 |
35 | private final static String indent = " ";
36 |
37 | private final Set fxmlClasses = new HashSet<>();
38 |
39 | private ToolProvider jar;
40 |
41 | private boolean verbose = false;
42 |
43 | private int errors = 0;
44 |
45 | private int counter = 0;
46 |
47 | @Override
48 | public void initialize(ToolProvider jarToolProvider, boolean verbose) {
49 | this.jar = jarToolProvider;
50 | this.verbose = verbose;
51 | }
52 |
53 | @Override
54 | public void start() {
55 | fxmlClasses.clear();
56 | errors = 0;
57 | }
58 |
59 | @Override
60 | public void process(String arg) throws JARProcessorException {
61 | File jarFile = jarFile(arg);
62 | if (verbose) System.out.println("JAR: " + jarFile);
63 |
64 | ByteArrayOutputStream baos = new ByteArrayOutputStream();
65 | PrintStream ps = new PrintStream(baos);
66 |
67 | String[] jarListArgs = { "--list", "--file", jarFile.getAbsolutePath() };
68 |
69 | int status = jar.run(ps, System.err, jarListArgs);
70 |
71 | if (status == 0) {
72 | String res = new String(baos.toByteArray());
73 | res.lines().filter(s -> {
74 | return
75 | s.endsWith(".o") ||
76 | s.endsWith(".a") ||
77 | s.endsWith(".so") ||
78 | s.endsWith(".dll") ||
79 | s.endsWith(".dylib") ||
80 | s.endsWith(".jnilib");
81 | }).forEach(l -> {
82 | try {
83 | processFXML(jarFile, l);
84 | } catch (JARProcessorException e) {
85 | ++errors;
86 | if (verbose) e.printStackTrace();
87 | }
88 | });
89 | if (errors > 0) throw new JARProcessorException("process terminated with errors.");
90 | } else {
91 | throw new JARProcessorException("jar tool terminated with errors.");
92 | }
93 | }
94 |
95 | @Override
96 | public void finish() {
97 | if (verbose) System.out.println(counter + " native artifacts found.");
98 | }
99 |
100 | private void processFXML(File jarFile, String line) throws JARProcessorException {
101 | ++counter;
102 | URI uri = URI.create(String.format("jar:" + jarFile.toURI()));
103 | try (FileSystem jfs = FileSystems.newFileSystem(uri, Collections.emptyMap())) {
104 | Path path = jfs.getPath(line);
105 | if (Files.isRegularFile(path)) {
106 | System.out.println(indent + path);
107 | } else {
108 | throw new JARProcessorException("No regular file: " + path);
109 | }
110 | } catch (IOException e) {
111 | throw new JARProcessorException("Error processing line: " + line);
112 | }
113 | }
114 |
115 | }
116 |
--------------------------------------------------------------------------------
/jfxtools-awtimage-demos/src/main/java/de/mpmediasoft/jfxtools/awtimage/demo/AWTImageDemo.java:
--------------------------------------------------------------------------------
1 | package de.mpmediasoft.jfxtools.awtimage.demo;
2 |
3 | import java.awt.BasicStroke;
4 | import java.awt.Color;
5 | import java.awt.geom.Path2D;
6 | import java.awt.image.BufferedImage;
7 | import java.io.File;
8 | import java.io.IOException;
9 |
10 | import javax.imageio.ImageIO;
11 |
12 | import de.mpmediasoft.jfxtools.awtimage.AWTImage;
13 | import javafx.application.Application;
14 | import javafx.embed.swing.SwingFXUtils;
15 | import javafx.scene.Scene;
16 | import javafx.scene.control.Button;
17 | import javafx.scene.control.ToolBar;
18 | import javafx.scene.image.Image;
19 | import javafx.scene.image.ImageView;
20 | import javafx.scene.layout.BorderPane;
21 | import javafx.stage.Stage;
22 |
23 | /**
24 | * A simple demo to show how the AWTImage class is supposed to be used.
25 | *
26 | * @author Michael Paus
27 | */
28 | public class AWTImageDemo extends Application {
29 |
30 | private AWTImage awtImage = new AWTImage(800, 600);
31 |
32 | @Override
33 | public void init() {
34 | System.out.println("java.runtime.version: " + System.getProperty("java.runtime.version", "(undefined)"));
35 | System.out.println("javafx.runtime.version: " + System.getProperty("javafx.runtime.version", "(undefined)"));
36 | }
37 |
38 | Color c1 = Color.red;
39 | Color c2 = Color.green;
40 | Color c3 = Color.blue;
41 |
42 | Color c;
43 |
44 | @Override
45 | public void start(Stage primaryStage) throws Exception {
46 | Button b1 = new Button("Full (RED)");
47 | b1.setOnAction(e -> {
48 | c = c1;
49 | awtImage.update();
50 | });
51 |
52 | Button b2 = new Button("Partial (GREEN)");
53 | b2.setOnAction(e -> {
54 | c = c2;
55 | awtImage.update();
56 | });
57 |
58 | Button b3 = new Button("Empty (BLUE)");
59 | b3.setOnAction(e -> {
60 | c = c3;
61 | awtImage.update();
62 | });
63 |
64 | Button b4 = new Button("Save to 'awtimage.png'");
65 | b4.setOnAction(e -> {
66 | try {
67 | ImageIO.write(awtImage.getAWTImage(), "png", new File("awtimage.png"));
68 | } catch (IOException e1) {
69 | e1.printStackTrace();
70 | }
71 | });
72 |
73 | Button b5 = new Button("Save to 'awtimage.jpg'");
74 | b5.setOnAction(e -> {
75 | try {
76 | // This is a work-around for a java bug if images with alpha are stored as JPEGs.
77 | Image fxImage = awtImage.getFXImage();
78 | BufferedImage awtImage = new BufferedImage((int) fxImage.getWidth(), (int) fxImage.getHeight(), BufferedImage.TYPE_INT_RGB);
79 | ImageIO.write(SwingFXUtils.fromFXImage(fxImage, awtImage), "jpeg", new File("awtimage.jpg"));
80 | } catch (IOException e1) {
81 | e1.printStackTrace();
82 | }
83 | });
84 |
85 | ToolBar toolbar = new ToolBar(b1, b2, b3, b4, b5);
86 |
87 | BorderPane root = new BorderPane();
88 | root.setTop(toolbar);
89 |
90 | root.setCenter(new ImageView(awtImage.getFXImage()));
91 | Scene scene = new Scene(root);
92 | primaryStage.setScene(scene);
93 | primaryStage.show();
94 |
95 | awtImage.setOnUpdate(g2d -> {
96 | // This is pure AWT.
97 |
98 | g2d.setBackground(Color.decode("#F0F0FF"));
99 | g2d.clearRect(0, 0, awtImage.getWidth(), awtImage.getHeight());
100 |
101 | Path2D p = new Path2D.Double();
102 | p.moveTo(100, 100);
103 | p.lineTo(700, 300);
104 | p.lineTo(200, 500);
105 | p.closePath();
106 |
107 | g2d.setColor(c);
108 | g2d.fill(p);
109 | g2d.setColor(new Color(50, 100, 150));
110 | g2d.setStroke(new BasicStroke(10));
111 | g2d.draw(p);
112 |
113 | if (c == c1) {
114 | System.out.println("Full update.");
115 | return null; // Full
116 | } else if (c == c2) {
117 | System.out.println("Partial update.");
118 | return new java.awt.geom.Rectangle2D.Double(0, 0, awtImage.getWidth() / 2, awtImage.getHeight()); // Partial
119 | } else {
120 | System.out.println("Empty update.");
121 | return new java.awt.geom.Rectangle2D.Double(); // Empty
122 | }
123 | });
124 | }
125 |
126 | public static void main(String[] args) {
127 | launch(args);
128 | }
129 |
130 | }
131 |
132 | class AWTImageDemoLauncher {public static void main(String[] args) {AWTImageDemo.main(args);}}
133 |
--------------------------------------------------------------------------------
/jfxtools-skiafx/src/main/java/de/mpmediasoft/jfxtools/skiafx/SkiaSurfaceFX.java:
--------------------------------------------------------------------------------
1 | package de.mpmediasoft.jfxtools.skiafx;
2 |
3 | import java.lang.foreign.MemorySegment; // new
4 | //import jdk.incubator.foreign.MemorySegment; // old
5 |
6 | import java.lang.reflect.Field;
7 | import java.nio.Buffer;
8 | import java.nio.ByteBuffer;
9 | import java.nio.IntBuffer;
10 |
11 | import io.github.humbleui.skija.Canvas;
12 | import io.github.humbleui.skija.ImageInfo;
13 | import io.github.humbleui.skija.Surface;
14 |
15 | import javafx.geometry.Rectangle2D;
16 | import javafx.scene.image.Image;
17 | import javafx.scene.image.PixelBuffer;
18 | import javafx.scene.image.PixelFormat;
19 | import javafx.scene.image.WritableImage;
20 | import javafx.util.Callback;
21 |
22 | /**
23 | * A JavaFX wrapper class for a Skia Surface.
24 | * You can draw into the Skia Canvas of it via the render method.
25 | * The rendering result is made directly available in an image via
26 | * a PixelBuffer.
27 | *
28 | * @author Michael Paus
29 | */
30 | public class SkiaSurfaceFX {
31 |
32 | // Uses the "Foreign Memory Access API" introduced in Java 14.
33 | // Needs --add-modules=jdk.incubator.foreign on the command line if set to true!
34 | private final static boolean AVOID_ILLEGAL_REFLECTION = true;
35 |
36 | public static interface RenderCallback extends Callback