From 5ae36a549fdc1336d932191ccd8af6f5924962f4 Mon Sep 17 00:00:00 2001 From: doblon8 Date: Wed, 8 Jul 2026 09:50:52 +0200 Subject: [PATCH] replace openpnp-capture-java dependency with ffm-based implementation --- build.gradle | 30 ++++---- .../sparrow/control/QRScanDialog.java | 2 +- .../sparrow/control/WebcamResolution.java | 4 +- .../sparrow/control/WebcamService.java | 70 +++++++++++-------- .../sparrow/control/WebcamView.java | 4 +- src/main/java/module-info.java | 3 +- 6 files changed, 57 insertions(+), 56 deletions(-) diff --git a/build.gradle b/build.gradle index 80ea6ca1..e4bf1e8b 100644 --- a/build.gradle +++ b/build.gradle @@ -73,7 +73,7 @@ dependencies { implementation('com.fasterxml.jackson.core:jackson-databind:2.21.1') implementation('com.sparrowwallet:hummingbird:1.7.4') implementation('co.nstant.in:cbor:0.9') - implementation('org.openpnp:openpnp-capture-java:0.0.30-1') + implementation('io.github.doblon8:openpnp-capture-java:0.0.3') implementation("io.matthewnelson.kmp-tor:runtime:2.5.0") implementation("io.matthewnelson.kmp-tor:resource-exec-tor-gpl:408.21.0") implementation('org.jetbrains.kotlinx:kotlinx-coroutines-javafx:1.10.2') { @@ -140,6 +140,7 @@ application { "--enable-native-access=com.fazecast.jSerialComm", "--enable-native-access=org.usb4java", "--enable-native-access=io.github.doblon8.jzbar", + "--enable-native-access=io.github.doblon8.openpnp.capture", "--add-opens=javafx.graphics/com.sun.javafx.css=org.controlsfx.controls", "--add-opens=javafx.graphics/javafx.scene=org.controlsfx.controls", "--add-opens=javafx.controls/com.sun.javafx.scene.control.behavior=org.controlsfx.controls", @@ -203,10 +204,8 @@ jlink { 'glob:/org.hid4java/darwin-*/**,' + 'glob:/org.hid4java/linux-*/**,' + 'glob:/org.hid4java/win32-*/**,' + - 'glob:/openpnp.capture.java/darwin-*/**,' + - 'glob:/openpnp.capture.java/linux-*/**,' + - 'glob:/openpnp.capture.java/win32-*/**,' + - 'glob:/io.github.doblon8.jzbar/native/**'] + 'glob:/io.github.doblon8.jzbar/native/**,' + + 'glob:/io.github.doblon8.openpnp.capture/native/**'] launcher { name = 'sparrow' jvmArgs = ["--enable-native-access=com.sparrowwallet.drongo", @@ -216,6 +215,7 @@ jlink { "--enable-native-access=com.fazecast.jSerialComm", "--enable-native-access=org.usb4java", "--enable-native-access=io.github.doblon8.jzbar", + "--enable-native-access=io.github.doblon8.openpnp.capture", "--enable-native-access=com.sparrowwallet.sparrow", "--add-opens=javafx.graphics/com.sun.javafx.css=org.controlsfx.controls", "--add-opens=javafx.graphics/javafx.scene=org.controlsfx.controls", @@ -394,13 +394,13 @@ def serialArch = osArch == "aarch64" ? "aarch64" : "x86_64" // Map of JAR name prefix to the include glob for platform-specific natives inside the JAR. def nativeLibJars = [ - 'jna-' : "com/sun/jna/${jnaPlatform}/*", - 'argon2-jvm-2' : "${jnaPlatform}/*", - 'hid4java-' : "${jnaPlatform}/*", - 'openpnp-capture-java': "${jnaPlatform}/*", - 'jSerialComm-' : "${serialOs}/${serialArch}/*", - 'usb4java-' : "org/usb4java/${jnaPlatform}/*", - 'jzbar-' : "native/${osName}/${osArch}/*", + 'jna-' : "com/sun/jna/${jnaPlatform}/*", + 'argon2-jvm-2' : "${jnaPlatform}/*", + 'hid4java-' : "${jnaPlatform}/*", + 'jSerialComm-' : "${serialOs}/${serialArch}/*", + 'usb4java-' : "org/usb4java/${jnaPlatform}/*", + 'jzbar-' : "native/${osName}/${osArch}/*", + 'openpnp-capture-java-': "native/${osName}/${osArch}/*", ] tasks.register('extractNativeLibraries') { @@ -477,12 +477,6 @@ extraJavaModuleInfo { requires('org.slf4j') requires('com.fasterxml.jackson.databind') } - module('org.openpnp:openpnp-capture-java', 'openpnp.capture.java') { - exports('org.openpnp.capture') - exports('org.openpnp.capture.library') - requires('java.desktop') - requires('com.sun.jna') - } module('net.sourceforge.javacsv:javacsv', 'net.sourceforge.javacsv') { exports('com.csvreader') } diff --git a/src/main/java/com/sparrowwallet/sparrow/control/QRScanDialog.java b/src/main/java/com/sparrowwallet/sparrow/control/QRScanDialog.java index 1198b479..7130b89a 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/QRScanDialog.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/QRScanDialog.java @@ -47,7 +47,7 @@ import javafx.scene.layout.*; import javafx.util.Duration; import javafx.util.StringConverter; import org.controlsfx.tools.Borders; -import org.openpnp.capture.CaptureDevice; +import io.github.doblon8.openpnp.capture.CaptureDevice; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/com/sparrowwallet/sparrow/control/WebcamResolution.java b/src/main/java/com/sparrowwallet/sparrow/control/WebcamResolution.java index 396606e2..6cdd4465 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/WebcamResolution.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/WebcamResolution.java @@ -1,6 +1,6 @@ package com.sparrowwallet.sparrow.control; -import org.openpnp.capture.CaptureFormat; +import io.github.doblon8.openpnp.capture.CaptureFormat; import java.util.Arrays; @@ -61,7 +61,7 @@ public enum WebcamResolution implements Comparable { public static WebcamResolution from(CaptureFormat captureFormat) { for(WebcamResolution resolution : values()) { - if(captureFormat.getFormatInfo().width == resolution.width && captureFormat.getFormatInfo().height == resolution.height) { + if(captureFormat.formatInfo().width() == resolution.width && captureFormat.formatInfo().height() == resolution.height) { return resolution; } } diff --git a/src/main/java/com/sparrowwallet/sparrow/control/WebcamService.java b/src/main/java/com/sparrowwallet/sparrow/control/WebcamService.java index 45e77ca6..1c332a07 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/WebcamService.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/WebcamService.java @@ -16,8 +16,7 @@ import javafx.concurrent.ScheduledService; import javafx.concurrent.Task; import javafx.embed.swing.SwingFXUtils; import javafx.scene.image.Image; -import org.openpnp.capture.*; -import org.openpnp.capture.library.OpenpnpCaptureLibrary; +import io.github.doblon8.openpnp.capture.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,6 +24,7 @@ import java.awt.*; import java.awt.geom.RoundRectangle2D; import java.awt.image.BufferedImage; import java.awt.image.WritableRaster; +import java.io.File; import java.util.*; import java.util.List; import java.util.concurrent.Semaphore; @@ -62,38 +62,46 @@ public class WebcamService extends ScheduledService { private final Bokmakierie bokmakierie; static { - if(log.isTraceEnabled()) { - OpenpnpCaptureLibrary.INSTANCE.Cap_setLogLevel(8); - } else if(log.isDebugEnabled()) { - OpenpnpCaptureLibrary.INSTANCE.Cap_setLogLevel(7); - } else if(log.isInfoEnabled()) { - OpenpnpCaptureLibrary.INSTANCE.Cap_setLogLevel(6); + String javaHome = System.getProperty("java.home"); + if(javaHome != null) { + File libFile = new File(new File(javaHome, "lib"), System.mapLibraryName("openpnp-capture")); + if(libFile.exists()) { + System.load(libFile.getAbsolutePath()); + } } - OpenpnpCaptureLibrary.INSTANCE.Cap_installCustomLogFunction((level, ptr) -> { + if(log.isTraceEnabled()) { + OpenPnpCapture.setLogLevel(LogLevel.VERBOSE); + } else if(log.isDebugEnabled()) { + OpenPnpCapture.setLogLevel(LogLevel.DEBUG); + } else if(log.isInfoEnabled()) { + OpenPnpCapture.setLogLevel(LogLevel.INFO); + } + + OpenPnpCapture.installCustomLogFunction((level, message) -> { switch(level) { - case 0: - case 1: - case 2: - case 3: - String err = ptr.getString(0).trim(); + case LogLevel.EMERGENCY: + case LogLevel.ALERT: + case LogLevel.CRITICAL: + case LogLevel.ERROR: + String err = message.trim(); if(err.equals("tjDecompressHeader2 failed: No error") || err.matches("getPropertyLimits.*failed on.*")) { //Safe to ignore log.debug(err); } else { log.error(err); } break; - case 4: - case 5: - case 6: - log.info(ptr.getString(0).trim()); + case LogLevel.WARNING: + case LogLevel.NOTICE: + case LogLevel.INFO: + log.info(message.trim()); break; - case 7: - log.debug(ptr.getString(0).trim()); + case LogLevel.DEBUG: + log.debug(message.trim()); break; - case 8: + case LogLevel.VERBOSE: default: - log.trace(ptr.getString(0).trim()); + log.trace(message.trim()); break; } }); @@ -167,8 +175,8 @@ public class WebcamService extends ScheduledService { //On macOS and Windows, camera pixel format is largely abstracted away if(OsType.getCurrent() == OsType.UNIX) { deviceFormats.sort((f1, f2) -> { - WebcamPixelFormat pf1 = WebcamPixelFormat.fromFourCC(f1.getFormatInfo().fourcc); - WebcamPixelFormat pf2 = WebcamPixelFormat.fromFourCC(f2.getFormatInfo().fourcc); + WebcamPixelFormat pf1 = WebcamPixelFormat.fromFourCC(f1.formatInfo().fourcc()); + WebcamPixelFormat pf2 = WebcamPixelFormat.fromFourCC(f2.formatInfo().fourcc()); return Integer.compare(WebcamPixelFormat.getPriority(pf1), WebcamPixelFormat.getPriority(pf2)); }); } @@ -185,17 +193,17 @@ public class WebcamService extends ScheduledService { format = supportedResolutions.get(resolution); } else { format = device.getFormats().getFirst(); - log.warn("Could not get standard capture resolution, using " + format.getFormatInfo().width + "x" + format.getFormatInfo().height); + log.warn("Could not get standard capture resolution, using " + format.formatInfo().width() + "x" + format.formatInfo().height()); } } //On Linux, formats not defined in WebcamPixelFormat are unsupported - if(OsType.getCurrent() == OsType.UNIX && WebcamPixelFormat.fromFourCC(format.getFormatInfo().fourcc) == null) { - log.warn("Unsupported camera pixel format " + WebcamPixelFormat.fourCCToString(format.getFormatInfo().fourcc)); + if(OsType.getCurrent() == OsType.UNIX && WebcamPixelFormat.fromFourCC(format.formatInfo().fourcc()) == null) { + log.warn("Unsupported camera pixel format " + WebcamPixelFormat.fourCCToString(format.formatInfo().fourcc())); } if(log.isDebugEnabled()) { - log.debug("Opening capture stream on " + device + " with format " + format.getFormatInfo().width + "x" + format.getFormatInfo().height + " (" + WebcamPixelFormat.fourCCToString(format.getFormatInfo().fourcc) + ")"); + log.debug("Opening capture stream on " + device + " with format " + format.formatInfo().width() + "x" + format.formatInfo().height() + " (" + WebcamPixelFormat.fourCCToString(format.formatInfo().fourcc()) + ")"); } opening.set(true); @@ -203,7 +211,7 @@ public class WebcamService extends ScheduledService { opening.set(false); try { - zoomLimits = stream.getPropertyLimits(CaptureProperty.Zoom); + zoomLimits = stream.getPropertyLimits(CaptureProperty.ZOOM); } catch(Throwable e) { log.debug("Error getting zoom limits on " + device + ", assuming no zoom function"); } @@ -285,7 +293,7 @@ public class WebcamService extends ScheduledService { public int getZoom() { if(stream != null && zoomLimits != null) { try { - return stream.getProperty(CaptureProperty.Zoom); + return stream.getProperty(CaptureProperty.ZOOM); } catch(Exception e) { log.error("Error getting zoom property on " + device, e); } @@ -297,7 +305,7 @@ public class WebcamService extends ScheduledService { public void setZoom(int value) { if(stream != null && zoomLimits != null) { try { - stream.setProperty(CaptureProperty.Zoom, value); + stream.setProperty(CaptureProperty.ZOOM, value); } catch(Exception e) { log.error("Error setting zoom property on " + device, e); } diff --git a/src/main/java/com/sparrowwallet/sparrow/control/WebcamView.java b/src/main/java/com/sparrowwallet/sparrow/control/WebcamView.java index 5e9b87f5..796d50c1 100644 --- a/src/main/java/com/sparrowwallet/sparrow/control/WebcamView.java +++ b/src/main/java/com/sparrowwallet/sparrow/control/WebcamView.java @@ -51,8 +51,8 @@ public class WebcamView { int currentZoom = service.getZoom(); if(currentZoom >= 0) { int newZoom = scrollEvent.getDeltaY() > 0 ? Math.round(currentZoom * 1.1f) : Math.round(currentZoom * 0.9f); - newZoom = Math.max(newZoom, service.getZoomLimits().getMin()); - newZoom = Math.min(newZoom, service.getZoomLimits().getMax()); + newZoom = Math.max(newZoom, service.getZoomLimits().min()); + newZoom = Math.min(newZoom, service.getZoomLimits().max()); if(newZoom != currentZoom) { service.setZoom(newZoom); } diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 0c92d2e9..d7020b94 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -33,7 +33,6 @@ open module com.sparrowwallet.sparrow { requires com.h2database; requires com.sparrowwallet.hummingbird; requires org.fxmisc.flowless; - requires openpnp.capture.java; requires nsmenufx; requires org.jcommander; requires jul.to.slf4j; @@ -55,6 +54,6 @@ open module com.sparrowwallet.sparrow { requires com.jcraft.jzlib; requires com.sparrowwallet.tern; requires com.sparrowwallet.lark; - requires com.sun.jna; requires io.github.doblon8.jzbar; + requires io.github.doblon8.openpnp.capture; } \ No newline at end of file