Skip to content

Commit 6897ead

Browse files
committed
#584 the bitmap/font tool now works when packaged on macos.
1 parent 83191f8 commit 6897ead

13 files changed

Lines changed: 513 additions & 55 deletions

File tree

.github/workflows/test.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ jobs:
99
test:
1010

1111
runs-on: ubuntu-latest
12+
env:
13+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
1214

1315
steps:
1416
- uses: actions/checkout@v4

.idea/compiler.xml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

font-bmp-editor/pom.xml

Lines changed: 111 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,11 @@
4848
<groupId>com.thecoderscorner.tcmenu</groupId>
4949
<artifactId>tcMenuJavaAPI</artifactId>
5050
<version>4.5.2</version>
51-
<scope>compile</scope>
5251
</dependency>
5352
<dependency>
5453
<groupId>com.thecoderscorner.tcmenu</groupId>
5554
<artifactId>embedCONTROLCore</artifactId>
5655
<version>4.5.2</version>
57-
<scope>compile</scope>
5856
</dependency>
5957
<dependency>
6058
<groupId>org.junit.jupiter</groupId>
@@ -68,8 +66,15 @@
6866
<version>3.27.7</version>
6967
<scope>test</scope>
7068
</dependency>
69+
<dependency>
70+
<groupId>org.mockito</groupId>
71+
<artifactId>mockito-core</artifactId>
72+
<version>5.23.0</version>
73+
<scope>test</scope>
74+
</dependency>
7175
</dependencies>
7276
<build>
77+
<finalName>FontBitmapEditor</finalName>
7378
<resources>
7479
<resource>
7580
<directory>src/main/resources</directory>
@@ -87,6 +92,110 @@
8792
</resource>
8893
</resources>
8994
<plugins>
95+
<plugin>
96+
<groupId>org.apache.maven.plugins</groupId>
97+
<artifactId>maven-dependency-plugin</artifactId>
98+
<executions>
99+
<execution>
100+
<id>copy-dependencies</id>
101+
<phase>prepare-package</phase>
102+
<goals>
103+
<goal>copy-dependencies</goal>
104+
</goals>
105+
<configuration>
106+
<outputDirectory>${project.build.directory}/lib</outputDirectory>
107+
<overWriteReleases>false</overWriteReleases>
108+
<overWriteSnapshots>false</overWriteSnapshots>
109+
<overWriteIfNewer>true</overWriteIfNewer>
110+
</configuration>
111+
</execution>
112+
<execution>
113+
<id>copy-deps-to-package</id>
114+
<phase>prepare-package</phase>
115+
<goals>
116+
<goal>copy-dependencies</goal>
117+
</goals>
118+
<configuration>
119+
<outputDirectory>${project.build.directory}/jfx/deps</outputDirectory>
120+
<includeScope>runtime</includeScope>
121+
<overWriteReleases>false</overWriteReleases>
122+
<overWriteSnapshots>false</overWriteSnapshots>
123+
<overWriteIfNewer>true</overWriteIfNewer>
124+
</configuration>
125+
</execution>
126+
</executions>
127+
</plugin>
128+
<plugin>
129+
<artifactId>maven-resources-plugin</artifactId>
130+
<version>3.3.1</version>
131+
<executions>
132+
<execution>
133+
<id>copy-resources-logging</id>
134+
<phase>validate</phase>
135+
<goals>
136+
<goal>copy-resources</goal>
137+
</goals>
138+
<configuration>
139+
<outputDirectory>${basedir}/target/jfx/app/</outputDirectory>
140+
<resources>
141+
<resource>
142+
<directory>${project.basedir}/../xmlPlugins</directory>
143+
<includes>
144+
<include>core-display/**</include>
145+
<include>core-remote/**</include>
146+
<include>core-themes/**</include>
147+
</includes>
148+
<filtering>false</filtering>
149+
</resource>
150+
<resource>
151+
<directory>${project.basedir}/../tcMenuNative/packaged</directory>
152+
<includes>
153+
<include>mac/*.dylib</include>
154+
<include>win/*.dll</include>
155+
<include>ubu/*.so</include>
156+
</includes>
157+
<filtering>false</filtering>
158+
</resource>
159+
</resources>
160+
</configuration>
161+
</execution>
162+
<execution>
163+
<id>copy-resources-plugins</id>
164+
<phase>validate</phase>
165+
<goals>
166+
<goal>copy-resources</goal>
167+
</goals>
168+
<configuration>
169+
<outputDirectory>${basedir}/target/jfx/app/plugins</outputDirectory>
170+
<resources>
171+
<resource>
172+
<directory>${project.basedir}/../builtPlugins</directory>
173+
<filtering>false</filtering>
174+
</resource>
175+
</resources>
176+
</configuration>
177+
</execution>
178+
<execution>
179+
<id>copy-resources-jar</id>
180+
<phase>install</phase>
181+
<goals>
182+
<goal>copy-resources</goal>
183+
</goals>
184+
<configuration>
185+
<outputDirectory>${basedir}/target/jfx/deps</outputDirectory>
186+
<resources>
187+
<resource>
188+
<directory>${project.basedir}/target</directory>
189+
<filtering>false</filtering>
190+
<includes>
191+
<include>FontBitmapEditor.jar</include>
192+
</includes>
193+
</resource>
194+
</resources>
195+
</configuration>
196+
</execution>
197+
</executions>
198+
</plugin>
90199
<plugin>
91200
<groupId>org.apache.maven.plugins</groupId>
92201
<artifactId>maven-compiler-plugin</artifactId>
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# How to build the bitmap and font editor into a native package using OpenJDK 21 onwards.
2+
3+
**For most users, we recommend using our pre-packaged software.** However, should you wish to build it yourself, follow these instructions, you'll end up with a native executable for Windows, a disk image for macOS, or an archive for Linux. Please only use these steps to build a UI for you own purposes.
4+
5+
Firstly, ensure that you have the most recent OpenJDK and a recent version of maven on your system, without these it will not be possible to build.
6+
7+
* All OpenJDK's that we've tested work for this, we've tried: Liberica, Adoptium, Amazon Corretto and Microsoft JDK.
8+
* For Apache maven we recommend using [https://maven.apache.org/]
9+
10+
Using git or zip download, get the contents of the tcMenu repository locally, for example:
11+
12+
git clone https://github.com/TcMenu/tcMenu.git
13+
git checkout <release-branch-name>
14+
15+
## Optional step - building a non-released version (advanced users)
16+
17+
It is far easier and safer to build a released version. But if you build a non-released version, you'll need to build the API too, here's how.
18+
19+
Drop to a command-line, in the `tcMenu/api/tcMenuJavaApi` directory.
20+
21+
mvn clean install -Dgpg.skip=true
22+
23+
Drop to a command-line, in the `tcMenu/api/embedCONTROLCore` directory.
24+
25+
mvn clean install -Dgpg.skip=true
26+
27+
## Building the app itself
28+
29+
Drop to a command-line, in the `tcMenu/font-bmp-editor` directory and run a maven build, the tests will not run from the command line as they include a full UI test suite, so we need to skip them
30+
31+
mvn clean install -DskipTests
32+
33+
## Packaging - Check the archive worked and versioning is right
34+
35+
Run and smoke test, ensure you are in the `font-bmp-editor/target/jfx/app` directory:
36+
37+
java --module-path ../deps "-Dprism.lcdtext=false" "-Doverride.core.plugin.dir=." \
38+
--enable-native-access=javafx.graphics,com.thecoderscorner.bmped "-Djava.library.path=win/" \
39+
--add-modules com.thecoderscorner.bmped com.thecoderscorner.bmped.BitMapEditApp
40+
41+
## Packaging - Build the package - Windows all versions
42+
43+
Ensure you are in the `font-bmp-editor/target` directory.
44+
45+
cp classes/img/tcMenuDesigner.ico .
46+
47+
jpackage --type app-image -n BitMapEdit -p jfx/deps --input jfx/app --win-console \
48+
--resource-dir .\classes\img\ --icon tcMenuDesigner.ico --app-version 4.5.0 --verbose \
49+
--java-options "-Dprism.lcdtext=false -Djava.library.path=$APPDIR/win" \
50+
--add-modules "jdk.crypto.cryptoki" \
51+
-m com.thecoderscorner.bmped/com.thecoderscorner.bmped.BitMapEditApp
52+
53+
54+
## Packaging - macOS build all versions (without notarization)
55+
56+
Ensure you are in the `font-bmp-editor/target` directory.
57+
58+
jpackage -n BitMapEdit -p jfx/deps --input jfx/app --icon ./classes/img/AppIcon.icns \
59+
--app-version 4.5.0 --verbose \
60+
--java-options '-Djava.library.path=$APPDIR/mac -Dprism.lcdtext=false' \
61+
--add-modules "jdk.crypto.cryptoki" \
62+
-m com.thecoderscorner.bmped/com.thecoderscorner.bmped.BitMapEditApp
63+

font-bmp-editor/src/main/java/com/thecoderscorner/bmped/BitMapEditApp.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.thecoderscorner.bmped;
22

33
import com.thecoderscorner.bmped.controller.MainWindowController;
4+
import com.thecoderscorner.bmped.util.AppDirectories;
45
import javafx.application.Application;
56
import javafx.fxml.FXMLLoader;
67
import javafx.scene.Scene;
@@ -9,6 +10,9 @@
910
import javafx.stage.Screen;
1011
import javafx.stage.Stage;
1112

13+
import java.io.ByteArrayInputStream;
14+
import java.io.IOException;
15+
import java.nio.charset.StandardCharsets;
1216
import java.nio.file.Files;
1317
import java.nio.file.Path;
1418
import java.nio.file.Paths;
@@ -42,17 +46,15 @@ public void start(Stage primaryStage) throws Exception {
4246

4347
}
4448

45-
private void startUpLogging() {
46-
var tcMenuHome = Paths.get(System.getProperty("user.home"), ".tcmenu");
49+
private void startUpLogging() throws IOException {
50+
var logDirectory = AppDirectories.logDirectory("BmpFontEd");
4751
var logName = System.getProperty("devlog") != null ? "dev-logging" : "logging";
48-
var inputStream = getClass().getResourceAsStream("/logconf/" + logName + ".properties");
49-
try
50-
{
51-
Path menuDir = tcMenuHome.resolve(".tcmenu/logs");
52-
if(!Files.exists(menuDir)) {
53-
Files.createDirectories(menuDir);
54-
}
5552

53+
try(var logConfData = getClass().getResourceAsStream("/logconf/" + logName + ".properties")){
54+
byte[] logConfBytes = logConfData.readAllBytes();
55+
var logData = new String(logConfBytes, StandardCharsets.UTF_8);
56+
logData = logData.replace("%EXPECTED_DIR%", logDirectory.toString());
57+
var inputStream = new ByteArrayInputStream(logData.getBytes(StandardCharsets.UTF_8));
5658
LogManager.getLogManager().readConfiguration(inputStream);
5759
}
5860
catch (Exception e)

font-bmp-editor/src/main/java/com/thecoderscorner/bmped/TcNativeLibrary.java

Lines changed: 15 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,15 @@
66
import java.lang.foreign.SymbolLookup;
77
import java.lang.foreign.ValueLayout;
88
import java.lang.invoke.MethodHandle;
9-
import java.nio.file.Path;
10-
import java.util.concurrent.atomic.AtomicReference;
9+
10+
import static java.lang.System.Logger.Level.ERROR;
1111

1212
/**
1313
* TcNative wraps the tcNativeLibrary functions to make it easier to use in more than one place in the code, and remove
1414
* native specific code from the main code area.
1515
*/
1616
public class TcNativeLibrary {
1717
private final static System.Logger logger = System.getLogger(TcNativeLibrary.class.getSimpleName());
18-
private final static AtomicReference<TcNativeLibrary> theInstance = new AtomicReference<>(null);
1918

2019
private final MethodHandle fontLibInit;
2120
private final MethodHandle fontLibDestroy;
@@ -25,7 +24,7 @@ public class TcNativeLibrary {
2524
private final MethodHandle canDisplayFn;
2625
private final MethodHandle setPixelsPerInch;
2726

28-
private TcNativeLibrary() {
27+
public TcNativeLibrary() throws IllegalStateException {
2928
logger.log(System.Logger.Level.INFO, "Loading TcNative Library");
3029
loadLibrary();
3130
logger.log(System.Logger.Level.INFO, "Creating native linker");
@@ -68,37 +67,19 @@ private TcNativeLibrary() {
6867
);
6968
}
7069

71-
private static void loadLibrary() {
72-
String os = System.getProperty("os.name");
73-
if(System.getProperty("devlog") != null) {
74-
logger.log(System.Logger.Level.INFO, "Assuming native library on LD_LIBRARY_PATH already");
75-
System.loadLibrary("tcMenuNative");
76-
}else if (os != null && os.startsWith ("Mac")) {
77-
var path = findPluginDir().resolve("mac").resolve("libtcMenuNative.dylib");
78-
System.load(path.toString());
79-
} else if(os != null && os.startsWith("Win")) {
80-
var path = findPluginDir().resolve("win").resolve("tcMenuNative.dll");
81-
System.load(path.toString());
82-
} else if(os != null && os.startsWith("Linux")) {
83-
var path = findPluginDir().resolve("ubu").resolve("libtcMenuNative.so");
84-
System.load(path.toString());
85-
}
86-
87-
}
88-
89-
private static Path findPluginDir() {
90-
//TODO: Implement plugin directory resolution logic when we have a jfx/jpackage build
91-
//TODO: for now just use -Ddevlog and manually set the library location in -Djava.library.path=...
92-
throw new UnsupportedOperationException("todo");
93-
}
94-
95-
public static TcNativeLibrary getInstance() {
96-
var ret = theInstance.get();
97-
if(ret == null) {
98-
ret = new TcNativeLibrary();
99-
theInstance.set(ret);
70+
private void loadLibrary() {
71+
if(System.getProperty("java.library.path") != null) {
72+
try {
73+
logger.log(System.Logger.Level.INFO, "Assuming native library on LD_LIBRARY_PATH already");
74+
System.loadLibrary("tcMenuNative");
75+
} catch(Exception e) {
76+
logger.log(ERROR,"Failed to load native library, please set java.library.path to the path of the native library");
77+
throw new IllegalStateException("Failed to load native library, please set java.library.path to the path of the native library");
78+
}
79+
} else {
80+
logger.log(ERROR,"java.library.path was not set, please set it to the path of the native library");
81+
throw new IllegalStateException("java.library.path was not set, please set it to the path of the native library");
10082
}
101-
return ret;
10283
}
10384

10485
public MethodHandle getFontLibInit() {

font-bmp-editor/src/main/java/com/thecoderscorner/bmped/gfxui/CreateBitmapWidgetController.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.io.IOException;
2727
import java.io.PrintStream;
2828
import java.nio.file.Path;
29+
import java.time.Clock;
2930
import java.util.ArrayList;
3031
import java.util.List;
3132
import java.util.Map;
@@ -192,7 +193,7 @@ public void onCreateWidget(ActionEvent ignoredActionEvent) {
192193
}
193194

194195
private void writeOutTitleWidget(PrintStream fileOut) throws IOException {
195-
var exporter = new NativeBitmapExporter();
196+
var exporter = new NativeBitmapExporter(Clock.systemDefaultZone());
196197
for(var li : loadedImages) {
197198
exporter.addImageToExport(li);
198199
}
@@ -206,7 +207,7 @@ public void onCreateBitmaps(ActionEvent ignoredActionEvent) {
206207
return;
207208
}
208209

209-
var exporter = new NativeBitmapExporter();
210+
var exporter = new NativeBitmapExporter(Clock.systemDefaultZone());
210211
for(var li : loadedImages) {
211212
exporter.addImageToExport(li);
212213
}

font-bmp-editor/src/main/java/com/thecoderscorner/bmped/gfxui/NativeFreeFontGlyphGenerator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public class NativeFreeFontGlyphGenerator implements FontGlyphGenerator, AutoClo
2525
private final Path fontPath;
2626
private int fontHandle;
2727

28-
private final TcNativeLibrary tcNative = TcNativeLibrary.getInstance();
28+
private final TcNativeLibrary tcNative = new TcNativeLibrary();
2929

3030
/**
3131
* Construct an instance of the generator based on a particular font file and the DPI of the display. This will

0 commit comments

Comments
 (0)