mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2025-03-17 13:22:40 +01:00
replace sarxos/openimaj library with openpnp-capture library
This commit is contained in:
parent
289a4453a4
commit
3b9551a8c6
24
build.gradle
24
build.gradle
@ -11,13 +11,11 @@ def osName = os.getFamilyName()
|
|||||||
if(os.macOsX) {
|
if(os.macOsX) {
|
||||||
osName = "osx"
|
osName = "osx"
|
||||||
}
|
}
|
||||||
def targetName = ""
|
|
||||||
def osArch = "x64"
|
def osArch = "x64"
|
||||||
def releaseArch = "x86_64"
|
def releaseArch = "x86_64"
|
||||||
if(System.getProperty("os.arch") == "aarch64") {
|
if(System.getProperty("os.arch") == "aarch64") {
|
||||||
osArch = "aarch64"
|
osArch = "aarch64"
|
||||||
releaseArch = "aarch64"
|
releaseArch = "aarch64"
|
||||||
targetName = "-" + osArch
|
|
||||||
}
|
}
|
||||||
def headless = "true".equals(System.getProperty("java.awt.headless"))
|
def headless = "true".equals(System.getProperty("java.awt.headless"))
|
||||||
|
|
||||||
@ -89,12 +87,7 @@ dependencies {
|
|||||||
implementation('com.fasterxml.jackson.core:jackson-databind:2.17.2')
|
implementation('com.fasterxml.jackson.core:jackson-databind:2.17.2')
|
||||||
implementation('com.sparrowwallet:hummingbird:1.7.4')
|
implementation('com.sparrowwallet:hummingbird:1.7.4')
|
||||||
implementation('co.nstant.in:cbor:0.9')
|
implementation('co.nstant.in:cbor:0.9')
|
||||||
implementation("com.nativelibs4java:bridj${targetName}:0.7-20140918-3") {
|
implementation('org.openpnp:openpnp-capture-java:0.0.28-2')
|
||||||
exclude group: 'com.google.android.tools', module: 'dx'
|
|
||||||
}
|
|
||||||
implementation("com.github.sarxos:webcam-capture${targetName}:0.3.13-SNAPSHOT") {
|
|
||||||
exclude group: 'com.nativelibs4java', module: 'bridj'
|
|
||||||
}
|
|
||||||
implementation("io.matthewnelson.kotlin-components:kmp-tor:${vTor}-${vKmpTor}") {
|
implementation("io.matthewnelson.kotlin-components:kmp-tor:${vTor}-${vKmpTor}") {
|
||||||
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-common'
|
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-common'
|
||||||
}
|
}
|
||||||
@ -378,18 +371,11 @@ extraJavaModuleInfo {
|
|||||||
requires('org.slf4j')
|
requires('org.slf4j')
|
||||||
requires('com.fasterxml.jackson.databind')
|
requires('com.fasterxml.jackson.databind')
|
||||||
}
|
}
|
||||||
module("com.nativelibs4java:bridj${targetName}", 'com.nativelibs4java.bridj') {
|
module('org.openpnp:openpnp-capture-java', 'openpnp.capture.java') {
|
||||||
exports('org.bridj')
|
exports('org.openpnp.capture')
|
||||||
exports('org.bridj.cpp')
|
exports('org.openpnp.capture.library')
|
||||||
requires('java.logging')
|
|
||||||
}
|
|
||||||
module("com.github.sarxos:webcam-capture${targetName}", 'com.github.sarxos.webcam.capture') {
|
|
||||||
exports('com.github.sarxos.webcam')
|
|
||||||
exports('com.github.sarxos.webcam.ds.buildin')
|
|
||||||
exports('com.github.sarxos.webcam.ds.buildin.natives')
|
|
||||||
requires('java.desktop')
|
requires('java.desktop')
|
||||||
requires('com.nativelibs4java.bridj')
|
requires('com.sun.jna')
|
||||||
requires('org.slf4j')
|
|
||||||
}
|
}
|
||||||
module('de.codecentric.centerdevice:centerdevice-nsmenufx', 'centerdevice.nsmenufx') {
|
module('de.codecentric.centerdevice:centerdevice-nsmenufx', 'centerdevice.nsmenufx') {
|
||||||
exports('de.codecentric.centerdevice')
|
exports('de.codecentric.centerdevice')
|
||||||
|
2
drongo
2
drongo
@ -1 +1 @@
|
|||||||
Subproject commit 2468578e723653344579aac857ee76d1a69fecde
|
Subproject commit e42931cd55bb99b19472499d27f13c7b5b6f6f82
|
@ -1,6 +1,6 @@
|
|||||||
package com.sparrowwallet.sparrow.control;
|
package com.sparrowwallet.sparrow.control;
|
||||||
|
|
||||||
import com.github.sarxos.webcam.*;
|
import com.google.common.base.Throwables;
|
||||||
import com.sparrowwallet.drongo.*;
|
import com.sparrowwallet.drongo.*;
|
||||||
import com.sparrowwallet.drongo.address.Address;
|
import com.sparrowwallet.drongo.address.Address;
|
||||||
import com.sparrowwallet.drongo.address.P2PKHAddress;
|
import com.sparrowwallet.drongo.address.P2PKHAddress;
|
||||||
@ -47,6 +47,7 @@ import javafx.util.Duration;
|
|||||||
import javafx.util.StringConverter;
|
import javafx.util.StringConverter;
|
||||||
import org.controlsfx.glyphfont.Glyph;
|
import org.controlsfx.glyphfont.Glyph;
|
||||||
import org.controlsfx.tools.Borders;
|
import org.controlsfx.tools.Borders;
|
||||||
|
import org.openpnp.capture.CaptureDevice;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -80,7 +81,7 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
|||||||
|
|
||||||
private final DoubleProperty percentComplete = new SimpleDoubleProperty(0.0);
|
private final DoubleProperty percentComplete = new SimpleDoubleProperty(0.0);
|
||||||
|
|
||||||
private final ObjectProperty<WebcamDevice> webcamDeviceProperty = new SimpleObjectProperty<>();
|
private final ObjectProperty<CaptureDevice> webcamDeviceProperty = new SimpleObjectProperty<>();
|
||||||
|
|
||||||
public QRScanDialog() {
|
public QRScanDialog() {
|
||||||
this.urDecoder = new URDecoder();
|
this.urDecoder = new URDecoder();
|
||||||
@ -91,7 +92,7 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
|||||||
webcamResolutionProperty.set(WebcamResolution.HD);
|
webcamResolutionProperty.set(WebcamResolution.HD);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.webcamService = new WebcamService(webcamResolutionProperty.get(), null, new QRScanListener(), new ScanDelayCalculator());
|
this.webcamService = new WebcamService(webcamResolutionProperty.get(), null);
|
||||||
webcamService.setPeriod(Duration.millis(SCAN_PERIOD_MILLIS));
|
webcamService.setPeriod(Duration.millis(SCAN_PERIOD_MILLIS));
|
||||||
webcamService.setRestartOnFailure(false);
|
webcamService.setRestartOnFailure(false);
|
||||||
WebcamView webcamView = new WebcamView(webcamService, Config.get().isMirrorCapture());
|
WebcamView webcamView = new WebcamView(webcamService, Config.get().isMirrorCapture());
|
||||||
@ -109,13 +110,13 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
|||||||
progressBar.setPadding(new Insets(0, 10, 0, 10));
|
progressBar.setPadding(new Insets(0, 10, 0, 10));
|
||||||
progressBar.setPrefWidth(Integer.MAX_VALUE);
|
progressBar.setPrefWidth(Integer.MAX_VALUE);
|
||||||
progressBar.progressProperty().bind(percentComplete);
|
progressBar.progressProperty().bind(percentComplete);
|
||||||
webcamService.openingProperty().addListener((observable, oldValue, newValue) -> {
|
webcamService.openingProperty().addListener((_, _, newValue) -> {
|
||||||
if(percentComplete.get() <= 0.0) {
|
if(percentComplete.get() <= 0.0) {
|
||||||
Platform.runLater(() -> percentComplete.set(newValue ? 0.0 : -1.0));
|
Platform.runLater(() -> percentComplete.set(newValue ? 0.0 : -1.0));
|
||||||
}
|
}
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
if(Config.get().getWebcamDevice() != null && webcamDeviceProperty.get() == null) {
|
if(Config.get().getWebcamDevice() != null && webcamDeviceProperty.get() == null) {
|
||||||
for(WebcamDevice device : WebcamScanDriver.getFoundDevices()) {
|
for(CaptureDevice device : webcamService.getFoundDevices()) {
|
||||||
if(device.getName().equals(Config.get().getWebcamDevice())) {
|
if(device.getName().equals(Config.get().getWebcamDevice())) {
|
||||||
webcamDeviceProperty.set(device);
|
webcamDeviceProperty.set(device);
|
||||||
}
|
}
|
||||||
@ -123,6 +124,18 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
webcamService.closedProperty().addListener((_, _, closed) -> {
|
||||||
|
if(closed && webcamResolutionProperty.get() != null) {
|
||||||
|
webcamService.setResolution(webcamResolutionProperty.get());
|
||||||
|
webcamService.setDevice(webcamDeviceProperty.get());
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
if(!webcamService.isRunning()) {
|
||||||
|
webcamService.reset();
|
||||||
|
webcamService.start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
VBox vBox = new VBox(20);
|
VBox vBox = new VBox(20);
|
||||||
vBox.getChildren().addAll(wrappedView, progressBar);
|
vBox.getChildren().addAll(wrappedView, progressBar);
|
||||||
@ -131,45 +144,34 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
|||||||
|
|
||||||
webcamService.resultProperty().addListener(new QRResultListener());
|
webcamService.resultProperty().addListener(new QRResultListener());
|
||||||
webcamService.setOnFailed(failedEvent -> {
|
webcamService.setOnFailed(failedEvent -> {
|
||||||
Throwable exception = failedEvent.getSource().getException();
|
Throwable exception = Throwables.getRootCause(failedEvent.getSource().getException());
|
||||||
|
Platform.runLater(() -> setResult(new Result(exception)));
|
||||||
Throwable nested = exception;
|
|
||||||
while(nested.getCause() != null) {
|
|
||||||
nested = nested.getCause();
|
|
||||||
}
|
|
||||||
if(OsType.getCurrent() == OsType.WINDOWS &&
|
|
||||||
nested.getMessage().startsWith("Library 'OpenIMAJGrabber' was not loaded successfully from file")) {
|
|
||||||
exception = new WebcamDependencyException("Your system is missing a dependency required for the webcam. Follow the link below for more details.\n\n[https://sparrowwallet.com/docs/faq.html#your-system-is-missing-a-dependency-for-the-webcam]", exception);
|
|
||||||
} else if(nested.getMessage().startsWith("Cannot start native grabber") && Config.get().getWebcamDevice() != null) {
|
|
||||||
exception = new WebcamOpenException("Cannot open configured webcam " + Config.get().getWebcamDevice() + ", reverting to the default webcam");
|
|
||||||
Config.get().setWebcamDevice(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Throwable result = exception;
|
|
||||||
Platform.runLater(() -> setResult(new Result(result)));
|
|
||||||
});
|
});
|
||||||
webcamService.start();
|
webcamService.start();
|
||||||
webcamResolutionProperty.addListener((observable, oldValue, newResolution) -> {
|
webcamResolutionProperty.addListener((_, _, newResolution) -> {
|
||||||
if(newResolution != null) {
|
if(newResolution != null) {
|
||||||
setHeight(newResolution == WebcamResolution.HD ? (getHeight() - 100) : (getHeight() + 100));
|
setHeight(newResolution == WebcamResolution.HD ? (getHeight() - 100) : (getHeight() + 100));
|
||||||
EventManager.get().post(new WebcamResolutionChangedEvent(newResolution == WebcamResolution.HD));
|
EventManager.get().post(new WebcamResolutionChangedEvent(newResolution == WebcamResolution.HD));
|
||||||
}
|
}
|
||||||
webcamService.cancel();
|
webcamService.cancel();
|
||||||
});
|
});
|
||||||
webcamDeviceProperty.addListener((observable, oldValue, newValue) -> {
|
webcamDeviceProperty.addListener((_, _, newValue) -> {
|
||||||
Config.get().setWebcamDevice(newValue.getName());
|
Config.get().setWebcamDevice(newValue.getName());
|
||||||
if(!Objects.equals(webcamService.getDevice(), newValue)) {
|
if(!Objects.equals(webcamService.getDevice(), newValue)) {
|
||||||
webcamService.cancel();
|
webcamService.cancel();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
setOnCloseRequest(event -> {
|
setOnCloseRequest(_ -> {
|
||||||
boolean isHdCapture = (webcamResolutionProperty.get() == WebcamResolution.HD);
|
boolean isHdCapture = (webcamResolutionProperty.get() == WebcamResolution.HD);
|
||||||
if(Config.get().isHdCapture() != isHdCapture) {
|
if(Config.get().isHdCapture() != isHdCapture) {
|
||||||
Config.get().setHdCapture(isHdCapture);
|
Config.get().setHdCapture(isHdCapture);
|
||||||
}
|
}
|
||||||
|
|
||||||
Platform.runLater(() -> webcamResolutionProperty.set(null));
|
Platform.runLater(() -> {
|
||||||
|
webcamResolutionProperty.set(null);
|
||||||
|
webcamService.close();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
final ButtonType cancelButtonType = new javafx.scene.control.ButtonType("Close", ButtonBar.ButtonData.CANCEL_CLOSE);
|
final ButtonType cancelButtonType = new javafx.scene.control.ButtonType("Close", ButtonBar.ButtonData.CANCEL_CLOSE);
|
||||||
@ -685,37 +687,6 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class QRScanListener implements WebcamListener {
|
|
||||||
@Override
|
|
||||||
public void webcamOpen(WebcamEvent webcamEvent) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void webcamClosed(WebcamEvent webcamEvent) {
|
|
||||||
if(webcamResolutionProperty.get() != null) {
|
|
||||||
webcamService.setResolution(webcamResolutionProperty.get());
|
|
||||||
webcamService.setDevice(webcamDeviceProperty.get());
|
|
||||||
Platform.runLater(() -> {
|
|
||||||
if(!webcamService.isRunning()) {
|
|
||||||
webcamService.reset();
|
|
||||||
webcamService.start();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void webcamDisposed(WebcamEvent webcamEvent) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void webcamImageObtained(WebcamEvent webcamEvent) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class QRScanDialogPane extends DialogPane {
|
private class QRScanDialogPane extends DialogPane {
|
||||||
@Override
|
@Override
|
||||||
protected Node createButton(ButtonType buttonType) {
|
protected Node createButton(ButtonType buttonType) {
|
||||||
@ -735,15 +706,15 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
|||||||
|
|
||||||
button = hd;
|
button = hd;
|
||||||
} else if(buttonType.getButtonData() == ButtonBar.ButtonData.HELP_2) {
|
} else if(buttonType.getButtonData() == ButtonBar.ButtonData.HELP_2) {
|
||||||
ComboBox<WebcamDevice> devicesCombo = new ComboBox<>(WebcamScanDriver.getFoundDevices());
|
ComboBox<CaptureDevice> devicesCombo = new ComboBox<>(webcamService.getFoundDevices());
|
||||||
devicesCombo.setConverter(new StringConverter<>() {
|
devicesCombo.setConverter(new StringConverter<>() {
|
||||||
@Override
|
@Override
|
||||||
public String toString(WebcamDevice device) {
|
public String toString(CaptureDevice device) {
|
||||||
return device instanceof WebcamScanDevice ? ((WebcamScanDevice)device).getDeviceName() : "Default Camera";
|
return device != null && device.getName() != null ? device.getName().replaceAll(" \\(.*\\)", "") : "Default Camera";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WebcamDevice fromString(String string) {
|
public CaptureDevice fromString(String string) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -993,10 +964,4 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
|
|||||||
super(message, cause);
|
super(message, cause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ScanDelayCalculator implements WebcamUpdater.DelayCalculator {
|
|
||||||
public long calculateDelay(long snapshotDuration, double deviceFps) {
|
|
||||||
return Math.max(SCAN_PERIOD_MILLIS - snapshotDuration, 0L);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
package com.sparrowwallet.sparrow.control;
|
||||||
|
|
||||||
|
import org.openpnp.capture.CaptureFormat;
|
||||||
|
|
||||||
|
public enum WebcamResolution {
|
||||||
|
VGA(640, 480),
|
||||||
|
HD(1280, 720);
|
||||||
|
|
||||||
|
private final int width;
|
||||||
|
private final int height;
|
||||||
|
|
||||||
|
WebcamResolution(int width, int height) {
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPixelsCount() {
|
||||||
|
return this.width * this.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getAspectRatio() {
|
||||||
|
int factor = this.getCommonFactor(this.width, this.height);
|
||||||
|
int wr = this.width / factor;
|
||||||
|
int hr = this.height / factor;
|
||||||
|
return new int[] {wr, hr};
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getCommonFactor(int width, int height) {
|
||||||
|
return height == 0 ? width : this.getCommonFactor(height, width % height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWidth() {
|
||||||
|
return this.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHeight() {
|
||||||
|
return this.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
int[] ratio = this.getAspectRatio();
|
||||||
|
return super.toString() + ' ' + this.width + 'x' + this.height + " (" + ratio[0] + ':' + ratio[1] + ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WebcamResolution from(CaptureFormat captureFormat) {
|
||||||
|
for(WebcamResolution resolution : values()) {
|
||||||
|
if(captureFormat.getFormatInfo().width == resolution.width && captureFormat.getFormatInfo().height == resolution.height) {
|
||||||
|
return resolution;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -1,372 +0,0 @@
|
|||||||
package com.sparrowwallet.sparrow.control;
|
|
||||||
|
|
||||||
import com.github.sarxos.webcam.*;
|
|
||||||
import com.github.sarxos.webcam.ds.buildin.natives.Device;
|
|
||||||
import com.github.sarxos.webcam.ds.buildin.natives.DeviceList;
|
|
||||||
import com.github.sarxos.webcam.ds.buildin.natives.OpenIMAJGrabber;
|
|
||||||
import org.bridj.Pointer;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.color.ColorSpace;
|
|
||||||
import java.awt.image.*;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.Hashtable;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public class WebcamScanDevice implements WebcamDevice, WebcamDevice.BufferAccess, Runnable, WebcamDevice.FPSSource {
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(WebcamScanDevice.class);
|
|
||||||
private static final int DEVICE_BUFFER_SIZE = 5;
|
|
||||||
private static final Dimension[] DIMENSIONS;
|
|
||||||
private static final int[] BAND_OFFSETS;
|
|
||||||
private static final int[] BITS;
|
|
||||||
private static final int[] OFFSET;
|
|
||||||
private static final int DATA_TYPE = 0;
|
|
||||||
private static final ColorSpace COLOR_SPACE;
|
|
||||||
public static final int SCAN_LOOP_WAIT_MILLIS = 100;
|
|
||||||
private int timeout = 5000;
|
|
||||||
private OpenIMAJGrabber grabber = null;
|
|
||||||
private Device device = null;
|
|
||||||
private Dimension size = null;
|
|
||||||
private ComponentSampleModel smodel = null;
|
|
||||||
private ColorModel cmodel = null;
|
|
||||||
private boolean failOnSizeMismatch = false;
|
|
||||||
private final AtomicBoolean disposed = new AtomicBoolean(false);
|
|
||||||
private final AtomicBoolean open = new AtomicBoolean(false);
|
|
||||||
private final AtomicBoolean fresh = new AtomicBoolean(false);
|
|
||||||
private Thread refresher = null;
|
|
||||||
private String name = null;
|
|
||||||
private String id = null;
|
|
||||||
private String fullname = null;
|
|
||||||
private long t1 = -1L;
|
|
||||||
private long t2 = -1L;
|
|
||||||
private volatile double fps = 0.0D;
|
|
||||||
|
|
||||||
protected WebcamScanDevice(Device device) {
|
|
||||||
this.device = device;
|
|
||||||
this.name = device.getNameStr();
|
|
||||||
this.id = device.getIdentifierStr();
|
|
||||||
this.fullname = String.format("%s %s", this.name, this.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return this.fullname;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDeviceName() {
|
|
||||||
return this.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDeviceId() {
|
|
||||||
return this.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Device getDeviceRef() {
|
|
||||||
return this.device;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Dimension[] getResolutions() {
|
|
||||||
return DIMENSIONS;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Dimension getResolution() {
|
|
||||||
if (this.size == null) {
|
|
||||||
this.size = this.getResolutions()[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setResolution(Dimension size) {
|
|
||||||
if (size == null) {
|
|
||||||
throw new IllegalArgumentException("Size cannot be null");
|
|
||||||
} else if (this.open.get()) {
|
|
||||||
throw new IllegalStateException("Cannot change resolution when webcam is open, please close it first");
|
|
||||||
} else {
|
|
||||||
this.size = size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ByteBuffer getImageBytes() {
|
|
||||||
if (this.disposed.get()) {
|
|
||||||
LOG.debug("Webcam is disposed, image will be null");
|
|
||||||
return null;
|
|
||||||
} else if (!this.open.get()) {
|
|
||||||
LOG.debug("Webcam is closed, image will be null");
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
if (this.fresh.compareAndSet(false, true)) {
|
|
||||||
this.updateFrameBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG.trace("Webcam grabber get image pointer");
|
|
||||||
Pointer<Byte> image = this.grabber.getImage();
|
|
||||||
this.fresh.set(false);
|
|
||||||
if (image == null) {
|
|
||||||
LOG.warn("Null array pointer found instead of image");
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
int length = this.size.width * this.size.height * 3;
|
|
||||||
LOG.trace("Webcam device get buffer, read {} bytes", length);
|
|
||||||
return image.getByteBuffer((long)length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void getImageBytes(ByteBuffer target) {
|
|
||||||
if (this.disposed.get()) {
|
|
||||||
LOG.debug("Webcam is disposed, image will be null");
|
|
||||||
} else if (!this.open.get()) {
|
|
||||||
LOG.debug("Webcam is closed, image will be null");
|
|
||||||
} else {
|
|
||||||
int minSize = this.size.width * this.size.height * 3;
|
|
||||||
int curSize = target.remaining();
|
|
||||||
if (minSize > curSize) {
|
|
||||||
throw new IllegalArgumentException(String.format("Not enough remaining space in target buffer (%d necessary vs %d remaining)", minSize, curSize));
|
|
||||||
} else {
|
|
||||||
if (this.fresh.compareAndSet(false, true)) {
|
|
||||||
this.updateFrameBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG.trace("Webcam grabber get image pointer");
|
|
||||||
Pointer<Byte> image = this.grabber.getImage();
|
|
||||||
this.fresh.set(false);
|
|
||||||
if (image == null) {
|
|
||||||
LOG.warn("Null array pointer found instead of image");
|
|
||||||
} else {
|
|
||||||
LOG.trace("Webcam device read buffer {} bytes", minSize);
|
|
||||||
image = image.validBytes((long)minSize);
|
|
||||||
image.getBytes(target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public BufferedImage getImage() {
|
|
||||||
ByteBuffer buffer = this.getImageBytes();
|
|
||||||
if (buffer == null) {
|
|
||||||
LOG.error("Images bytes buffer is null!");
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
byte[] bytes = new byte[this.size.width * this.size.height * 3];
|
|
||||||
byte[][] data = new byte[][]{bytes};
|
|
||||||
buffer.get(bytes);
|
|
||||||
DataBufferByte dbuf = new DataBufferByte(data, bytes.length, OFFSET);
|
|
||||||
WritableRaster raster = Raster.createWritableRaster(this.smodel, dbuf, (Point)null);
|
|
||||||
BufferedImage bi = new BufferedImage(this.cmodel, raster, false, (Hashtable)null);
|
|
||||||
bi.flush();
|
|
||||||
return bi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void open() {
|
|
||||||
if (!this.disposed.get()) {
|
|
||||||
LOG.debug("Opening webcam device {}", this.getName());
|
|
||||||
if (this.size == null) {
|
|
||||||
this.size = this.getResolutions()[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.size == null) {
|
|
||||||
throw new RuntimeException("The resolution size cannot be null");
|
|
||||||
} else {
|
|
||||||
LOG.debug("Webcam device {} starting session, size {}", this.device.getIdentifierStr(), this.size);
|
|
||||||
this.grabber = new OpenIMAJGrabber();
|
|
||||||
DeviceList list = (DeviceList)this.grabber.getVideoDevices().get();
|
|
||||||
Iterator var2 = list.asArrayList().iterator();
|
|
||||||
|
|
||||||
while(var2.hasNext()) {
|
|
||||||
Device d = (Device)var2.next();
|
|
||||||
d.getNameStr();
|
|
||||||
d.getIdentifierStr();
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean started = this.grabber.startSession(this.size.width, this.size.height, 50, Pointer.pointerTo(this.device));
|
|
||||||
if (!started) {
|
|
||||||
throw new WebcamException("Cannot start native grabber!");
|
|
||||||
} else {
|
|
||||||
this.grabber.setTimeout(this.timeout);
|
|
||||||
LOG.debug("Webcam device session started");
|
|
||||||
Dimension size2 = new Dimension(this.grabber.getWidth(), this.grabber.getHeight());
|
|
||||||
int w1 = this.size.width;
|
|
||||||
int w2 = size2.width;
|
|
||||||
int h1 = this.size.height;
|
|
||||||
int h2 = size2.height;
|
|
||||||
if (w1 != w2 || h1 != h2) {
|
|
||||||
if (this.failOnSizeMismatch) {
|
|
||||||
throw new WebcamException(String.format("Different size obtained vs requested - [%dx%d] vs [%dx%d]", w1, h1, w2, h2));
|
|
||||||
}
|
|
||||||
|
|
||||||
Object[] args = new Object[]{w1, h1, w2, h2, w2, h2};
|
|
||||||
LOG.warn("Different size obtained vs requested - [{}x{}] vs [{}x{}]. Setting correct one. New size is [{}x{}]", args);
|
|
||||||
this.size = new Dimension(w2, h2);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.smodel = new ComponentSampleModel(0, this.size.width, this.size.height, 3, this.size.width * 3, BAND_OFFSETS);
|
|
||||||
this.cmodel = new ComponentColorModel(COLOR_SPACE, BITS, false, false, 1, 0);
|
|
||||||
LOG.debug("Clear memory buffer");
|
|
||||||
this.clearMemoryBuffer();
|
|
||||||
LOG.debug("Webcam device {} is now open", this);
|
|
||||||
this.open.set(true);
|
|
||||||
this.refresher = this.startFramesRefresher();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void clearMemoryBuffer() {
|
|
||||||
for(int i = 0; i < 5; ++i) {
|
|
||||||
this.grabber.nextFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private Thread startFramesRefresher() {
|
|
||||||
Thread refresher = new Thread(this, String.format("frames-refresher-[%s]", this.id));
|
|
||||||
refresher.setUncaughtExceptionHandler(WebcamExceptionHandler.getInstance());
|
|
||||||
refresher.setDaemon(true);
|
|
||||||
refresher.start();
|
|
||||||
return refresher;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() {
|
|
||||||
if (this.open.compareAndSet(true, false)) {
|
|
||||||
LOG.debug("Closing webcam device");
|
|
||||||
this.grabber.stopSession();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void dispose() {
|
|
||||||
if (this.disposed.compareAndSet(false, true)) {
|
|
||||||
LOG.debug("Disposing webcam device {}", this.getName());
|
|
||||||
this.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFailOnSizeMismatch(boolean fail) {
|
|
||||||
this.failOnSizeMismatch = fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOpen() {
|
|
||||||
return this.open.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getTimeout() {
|
|
||||||
return this.timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTimeout(int timeout) {
|
|
||||||
if (this.isOpen()) {
|
|
||||||
throw new WebcamException("Timeout must be set before webcam is open");
|
|
||||||
} else {
|
|
||||||
this.timeout = timeout;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateFrameBuffer() {
|
|
||||||
LOG.trace("Next frame");
|
|
||||||
if (this.t1 == -1L || this.t2 == -1L) {
|
|
||||||
this.t1 = System.currentTimeMillis();
|
|
||||||
this.t2 = System.currentTimeMillis();
|
|
||||||
}
|
|
||||||
|
|
||||||
int result = (new WebcamScanDevice.NextFrameTask(this)).nextFrame();
|
|
||||||
this.t1 = this.t2;
|
|
||||||
this.t2 = System.currentTimeMillis();
|
|
||||||
this.fps = (4.0D * this.fps + (double)(1000L / (this.t2 - this.t1 + 1L))) / 5.0D;
|
|
||||||
if (result == -1) {
|
|
||||||
LOG.error("Timeout when requesting image!");
|
|
||||||
} else if (result < -1) {
|
|
||||||
LOG.error("Error requesting new frame!");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run() {
|
|
||||||
do {
|
|
||||||
try {
|
|
||||||
Thread.sleep(SCAN_LOOP_WAIT_MILLIS);
|
|
||||||
} catch(InterruptedException e) {
|
|
||||||
//ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Thread.interrupted()) {
|
|
||||||
LOG.debug("Refresher has been interrupted");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.open.get()) {
|
|
||||||
LOG.debug("Cancelling refresher");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.updateFrameBuffer();
|
|
||||||
} while(this.open.get());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getFPS() {
|
|
||||||
return this.fps;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if(this == o) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if(o == null || getClass() != o.getClass()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
WebcamScanDevice that = (WebcamScanDevice) o;
|
|
||||||
return Objects.equals(fullname, that.fullname);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(fullname);
|
|
||||||
}
|
|
||||||
|
|
||||||
static {
|
|
||||||
DIMENSIONS = new Dimension[]{WebcamResolution.QQVGA.getSize(), WebcamResolution.QVGA.getSize(), WebcamResolution.VGA.getSize()};
|
|
||||||
BAND_OFFSETS = new int[]{0, 1, 2};
|
|
||||||
BITS = new int[]{8, 8, 8};
|
|
||||||
OFFSET = new int[]{0};
|
|
||||||
COLOR_SPACE = ColorSpace.getInstance(1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class NextFrameTask extends WebcamTask {
|
|
||||||
private final AtomicInteger result = new AtomicInteger(0);
|
|
||||||
|
|
||||||
public NextFrameTask(WebcamDevice device) {
|
|
||||||
super(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int nextFrame() {
|
|
||||||
try {
|
|
||||||
this.process();
|
|
||||||
} catch (InterruptedException var2) {
|
|
||||||
WebcamScanDevice.LOG.debug("Image buffer request interrupted", var2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.result.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void handle() {
|
|
||||||
WebcamScanDevice device = (WebcamScanDevice)this.getDevice();
|
|
||||||
if (device.isOpen()) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(SCAN_LOOP_WAIT_MILLIS);
|
|
||||||
} catch(InterruptedException e) {
|
|
||||||
//ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
this.result.set(WebcamScanDevice.this.grabber.nextFrame());
|
|
||||||
WebcamScanDevice.this.fresh.set(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
package com.sparrowwallet.sparrow.control;
|
|
||||||
|
|
||||||
import com.github.sarxos.webcam.WebcamDevice;
|
|
||||||
import com.github.sarxos.webcam.ds.buildin.WebcamDefaultDevice;
|
|
||||||
import com.github.sarxos.webcam.ds.buildin.WebcamDefaultDriver;
|
|
||||||
import javafx.collections.FXCollections;
|
|
||||||
import javafx.collections.ObservableList;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class WebcamScanDriver extends WebcamDefaultDriver {
|
|
||||||
private static final ObservableList<WebcamDevice> webcamDevices = FXCollections.observableArrayList();
|
|
||||||
private static boolean rescan;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<WebcamDevice> getDevices() {
|
|
||||||
if(rescan || webcamDevices.isEmpty()) {
|
|
||||||
List<WebcamDevice> devices = super.getDevices();
|
|
||||||
List<WebcamDevice> scanDevices = new ArrayList<>();
|
|
||||||
for(WebcamDevice device : devices) {
|
|
||||||
WebcamDefaultDevice defaultDevice = (WebcamDefaultDevice)device;
|
|
||||||
WebcamScanDevice scanDevice = new WebcamScanDevice(defaultDevice.getDeviceRef());
|
|
||||||
if(scanDevices.stream().noneMatch(dev -> ((WebcamScanDevice)dev).getDeviceName().equals(scanDevice.getDeviceName()))) {
|
|
||||||
scanDevices.add(scanDevice);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<WebcamDevice> newDevices = new ArrayList<>(scanDevices);
|
|
||||||
newDevices.removeAll(webcamDevices);
|
|
||||||
webcamDevices.addAll(newDevices);
|
|
||||||
webcamDevices.removeIf(device -> !scanDevices.contains(device));
|
|
||||||
}
|
|
||||||
|
|
||||||
return webcamDevices;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ObservableList<WebcamDevice> getFoundDevices() {
|
|
||||||
return webcamDevices;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void rescan() {
|
|
||||||
rescan = true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,5 @@
|
|||||||
package com.sparrowwallet.sparrow.control;
|
package com.sparrowwallet.sparrow.control;
|
||||||
|
|
||||||
import com.github.sarxos.webcam.*;
|
|
||||||
import com.google.zxing.*;
|
import com.google.zxing.*;
|
||||||
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
|
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
|
||||||
import com.google.zxing.common.HybridBinarizer;
|
import com.google.zxing.common.HybridBinarizer;
|
||||||
@ -11,11 +10,18 @@ import javafx.beans.property.BooleanProperty;
|
|||||||
import javafx.beans.property.ObjectProperty;
|
import javafx.beans.property.ObjectProperty;
|
||||||
import javafx.beans.property.SimpleBooleanProperty;
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
import javafx.concurrent.ScheduledService;
|
import javafx.concurrent.ScheduledService;
|
||||||
import javafx.concurrent.Task;
|
import javafx.concurrent.Task;
|
||||||
import javafx.embed.swing.SwingFXUtils;
|
import javafx.embed.swing.SwingFXUtils;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import net.sourceforge.zbar.ZBar;
|
import net.sourceforge.zbar.ZBar;
|
||||||
|
import org.openpnp.capture.CaptureDevice;
|
||||||
|
import org.openpnp.capture.CaptureFormat;
|
||||||
|
import org.openpnp.capture.CaptureStream;
|
||||||
|
import org.openpnp.capture.OpenPnpCapture;
|
||||||
|
import org.openpnp.capture.library.OpenpnpCaptureLibrary;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -23,38 +29,59 @@ import java.awt.*;
|
|||||||
import java.awt.geom.RoundRectangle2D;
|
import java.awt.geom.RoundRectangle2D;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.WritableRaster;
|
import java.awt.image.WritableRaster;
|
||||||
import java.util.Arrays;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class WebcamService extends ScheduledService<Image> {
|
public class WebcamService extends ScheduledService<Image> {
|
||||||
private static final Logger log = LoggerFactory.getLogger(WebcamService.class);
|
private static final Logger log = LoggerFactory.getLogger(WebcamService.class);
|
||||||
|
|
||||||
private WebcamResolution resolution;
|
private WebcamResolution resolution;
|
||||||
private WebcamDevice device;
|
private CaptureDevice device;
|
||||||
private final WebcamListener listener;
|
|
||||||
private final WebcamUpdater.DelayCalculator delayCalculator;
|
|
||||||
private final BooleanProperty opening = new SimpleBooleanProperty(false);
|
private final BooleanProperty opening = new SimpleBooleanProperty(false);
|
||||||
|
private final BooleanProperty closed = new SimpleBooleanProperty(false);
|
||||||
|
|
||||||
private final ObjectProperty<Result> resultProperty = new SimpleObjectProperty<>(null);
|
private final ObjectProperty<Result> resultProperty = new SimpleObjectProperty<>(null);
|
||||||
|
|
||||||
private static final int QR_SAMPLE_PERIOD_MILLIS = 200;
|
private static final int QR_SAMPLE_PERIOD_MILLIS = 200;
|
||||||
|
|
||||||
private Webcam cam;
|
private final OpenPnpCapture capture;
|
||||||
|
private CaptureStream stream;
|
||||||
private long lastQrSampleTime;
|
private long lastQrSampleTime;
|
||||||
|
private final ObservableList<CaptureDevice> foundDevices = FXCollections.observableList(new ArrayList<>());
|
||||||
private final Reader qrReader;
|
private final Reader qrReader;
|
||||||
private final Bokmakierie bokmakierie;
|
private final Bokmakierie bokmakierie;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
Webcam.setDriver(new WebcamScanDriver());
|
OpenpnpCaptureLibrary.INSTANCE.Cap_installCustomLogFunction((level, ptr) -> {
|
||||||
|
switch(level) {
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
log.error(ptr.getString(0).trim());
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
log.info(ptr.getString(0).trim());
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
log.debug(ptr.getString(0).trim());
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
log.trace(ptr.getString(0).trim());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public WebcamService(WebcamResolution resolution, WebcamDevice device, WebcamListener listener, WebcamUpdater.DelayCalculator delayCalculator) {
|
public WebcamService(WebcamResolution requestedResolution, CaptureDevice requestedDevice) {
|
||||||
this.resolution = resolution;
|
this.capture = new OpenPnpCapture();
|
||||||
this.device = device;
|
this.resolution = requestedResolution;
|
||||||
this.listener = listener;
|
this.device = requestedDevice;
|
||||||
this.delayCalculator = delayCalculator;
|
|
||||||
this.lastQrSampleTime = System.currentTimeMillis();
|
this.lastQrSampleTime = System.currentTimeMillis();
|
||||||
this.qrReader = new QRCodeReader();
|
this.qrReader = new QRCodeReader();
|
||||||
this.bokmakierie = new Bokmakierie();
|
this.bokmakierie = new Bokmakierie();
|
||||||
@ -62,50 +89,66 @@ public class WebcamService extends ScheduledService<Image> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Task<Image> createTask() {
|
public Task<Image> createTask() {
|
||||||
return new Task<Image>() {
|
return new Task<>() {
|
||||||
@Override
|
@Override
|
||||||
protected Image call() throws Exception {
|
protected Image call() throws Exception {
|
||||||
try {
|
try {
|
||||||
if(cam == null) {
|
if(stream == null) {
|
||||||
List<Webcam> webcams = Webcam.getWebcams(1, TimeUnit.MINUTES);
|
List<CaptureDevice> devices = capture.getDevices();
|
||||||
if(webcams.isEmpty()) {
|
|
||||||
throw new UnsupportedOperationException("No camera available.");
|
List<CaptureDevice> newDevices = new ArrayList<>(devices);
|
||||||
|
newDevices.removeAll(foundDevices);
|
||||||
|
foundDevices.addAll(newDevices);
|
||||||
|
foundDevices.removeIf(device -> !devices.contains(device));
|
||||||
|
|
||||||
|
if(foundDevices.isEmpty()) {
|
||||||
|
throw new UnsupportedOperationException("No cameras available");
|
||||||
}
|
}
|
||||||
|
|
||||||
cam = webcams.get(0);
|
CaptureDevice selectedDevice = foundDevices.getFirst();
|
||||||
|
|
||||||
if(device != null) {
|
if(device != null) {
|
||||||
for(Webcam webcam : webcams) {
|
for(CaptureDevice webcam : foundDevices) {
|
||||||
if(webcam.getDevice().getName().equals(device.getName())) {
|
if(webcam.getName().equals(device.getName())) {
|
||||||
cam = webcam;
|
selectedDevice = webcam;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(Config.get().getWebcamDevice() != null) {
|
} else if(Config.get().getWebcamDevice() != null) {
|
||||||
for(Webcam webcam : webcams) {
|
for(CaptureDevice webcam : foundDevices) {
|
||||||
if(webcam.getDevice().getName().equals(Config.get().getWebcamDevice())) {
|
if(webcam.getName().equals(Config.get().getWebcamDevice())) {
|
||||||
cam = webcam;
|
selectedDevice = webcam;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
device = cam.getDevice();
|
device = selectedDevice;
|
||||||
|
|
||||||
cam.setCustomViewSizes(resolution.getSize());
|
if(device.getFormats().isEmpty()) {
|
||||||
cam.setViewSize(resolution.getSize());
|
throw new UnsupportedOperationException("No resolutions supported by camera " + device.getName());
|
||||||
if(!Arrays.asList(cam.getWebcamListeners()).contains(listener)) {
|
}
|
||||||
cam.addWebcamListener(listener);
|
|
||||||
|
Map<WebcamResolution, CaptureFormat> supportedResolutions = device.getFormats().stream()
|
||||||
|
.filter(f -> WebcamResolution.from(f) != null)
|
||||||
|
.collect(Collectors.toMap(WebcamResolution::from, Function.identity(), (u, v) -> u));
|
||||||
|
|
||||||
|
CaptureFormat format = supportedResolutions.get(resolution);
|
||||||
|
if(format == null) {
|
||||||
|
if(!supportedResolutions.isEmpty()) {
|
||||||
|
format = supportedResolutions.values().iterator().next();
|
||||||
|
} else {
|
||||||
|
format = device.getFormats().getFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
log.warn("Could not get requested capture resolution, using " + format.getFormatInfo().width + "x" + format.getFormatInfo().height);
|
||||||
}
|
}
|
||||||
|
|
||||||
opening.set(true);
|
opening.set(true);
|
||||||
cam.open(true, delayCalculator);
|
stream = device.openStream(format);
|
||||||
opening.set(false);
|
opening.set(false);
|
||||||
|
closed.set(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferedImage originalImage = cam.getImage();
|
BufferedImage originalImage = stream.capture();
|
||||||
if(originalImage == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
CroppedDimension cropped = getCroppedDimension(originalImage);
|
CroppedDimension cropped = getCroppedDimension(originalImage);
|
||||||
BufferedImage croppedImage = originalImage.getSubimage(cropped.x, cropped.y, cropped.length, cropped.length);
|
BufferedImage croppedImage = originalImage.getSubimage(cropped.x, cropped.y, cropped.length, cropped.length);
|
||||||
BufferedImage framedImage = getFramedImage(originalImage, cropped);
|
BufferedImage framedImage = getFramedImage(originalImage, cropped);
|
||||||
@ -128,19 +171,24 @@ public class WebcamService extends ScheduledService<Image> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reset() {
|
public void reset() {
|
||||||
cam = null;
|
stream = null;
|
||||||
super.reset();
|
super.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean cancel() {
|
public boolean cancel() {
|
||||||
if(cam != null && !cam.close()) {
|
if(stream != null) {
|
||||||
cam.close();
|
stream.close();
|
||||||
|
closed.set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.cancel();
|
return super.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
capture.close();
|
||||||
|
}
|
||||||
|
|
||||||
private void readQR(BufferedImage wideImage, BufferedImage croppedImage) {
|
private void readQR(BufferedImage wideImage, BufferedImage croppedImage) {
|
||||||
Result result = readQR(wideImage);
|
Result result = readQR(wideImage);
|
||||||
if(result == null) {
|
if(result == null) {
|
||||||
@ -235,33 +283,46 @@ public class WebcamService extends ScheduledService<Image> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getCamWidth() {
|
public int getCamWidth() {
|
||||||
return resolution.getSize().width;
|
return resolution.getWidth();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCamHeight() {
|
public int getCamHeight() {
|
||||||
return resolution.getSize().height;
|
return resolution.getHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setResolution(WebcamResolution resolution) {
|
public void setResolution(WebcamResolution resolution) {
|
||||||
this.resolution = resolution;
|
this.resolution = resolution;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WebcamDevice getDevice() {
|
public CaptureDevice getDevice() {
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDevice(WebcamDevice device) {
|
public void setDevice(CaptureDevice device) {
|
||||||
this.device = device;
|
this.device = device;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isOpening() {
|
public ObservableList<CaptureDevice> getFoundDevices() {
|
||||||
return opening.get();
|
return foundDevices;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BooleanProperty openingProperty() {
|
public BooleanProperty openingProperty() {
|
||||||
return opening;
|
return opening;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BooleanProperty closedProperty() {
|
||||||
|
return closed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String fourCCToString(int fourCC) {
|
||||||
|
return new String(new char[] {
|
||||||
|
(char) (fourCC >> 24 & 0xFF),
|
||||||
|
(char) ((fourCC >> 16) & 0xFF),
|
||||||
|
(char) ((fourCC >> 8) & 0xFF),
|
||||||
|
(char) ((fourCC) & 0xFF)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private static class CroppedDimension {
|
private static class CroppedDimension {
|
||||||
public int x;
|
public int x;
|
||||||
public int y;
|
public int y;
|
||||||
|
@ -42,12 +42,11 @@ open module com.sparrowwallet.sparrow {
|
|||||||
requires com.h2database;
|
requires com.h2database;
|
||||||
requires com.sparrowwallet.hummingbird;
|
requires com.sparrowwallet.hummingbird;
|
||||||
requires org.fxmisc.flowless;
|
requires org.fxmisc.flowless;
|
||||||
requires com.github.sarxos.webcam.capture;
|
requires openpnp.capture.java;
|
||||||
requires centerdevice.nsmenufx;
|
requires centerdevice.nsmenufx;
|
||||||
requires org.jcommander;
|
requires org.jcommander;
|
||||||
requires jul.to.slf4j;
|
requires jul.to.slf4j;
|
||||||
requires net.sourceforge.javacsv;
|
requires net.sourceforge.javacsv;
|
||||||
requires com.nativelibs4java.bridj;
|
|
||||||
requires org.reactfx.reactfx;
|
requires org.reactfx.reactfx;
|
||||||
requires dev.bwt.jni;
|
requires dev.bwt.jni;
|
||||||
requires io.reactivex.rxjava2;
|
requires io.reactivex.rxjava2;
|
||||||
@ -66,4 +65,5 @@ open module com.sparrowwallet.sparrow {
|
|||||||
requires com.jcraft.jzlib;
|
requires com.jcraft.jzlib;
|
||||||
requires com.sparrowwallet.tern;
|
requires com.sparrowwallet.tern;
|
||||||
requires com.sparrowwallet.lark;
|
requires com.sparrowwallet.lark;
|
||||||
|
requires com.sun.jna;
|
||||||
}
|
}
|
@ -1,9 +1,6 @@
|
|||||||
<configuration>
|
<configuration>
|
||||||
<statusListener class="ch.qos.logback.core.status.NopStatusListener" />
|
<statusListener class="ch.qos.logback.core.status.NopStatusListener" />
|
||||||
|
|
||||||
<logger name="com.github.sarxos.webcam.Webcam" level="OFF"/>
|
|
||||||
<logger name="com.github.sarxos.webcam.ds.cgt.WebcamOpenTask" level="OFF"/>
|
|
||||||
<logger name="com.github.sarxos.webcam.ds.cgt.WebcamCloseTask" level="OFF"/>
|
|
||||||
<logger name="javafx.css" level="ERROR"/>
|
<logger name="javafx.css" level="ERROR"/>
|
||||||
<logger name="javafx.scene.focus" level="INFO"/>
|
<logger name="javafx.scene.focus" level="INFO"/>
|
||||||
<logger name="sun.net.www.protocol.http.HttpURLConnection" level="INFO" />
|
<logger name="sun.net.www.protocol.http.HttpURLConnection" level="INFO" />
|
||||||
@ -34,7 +31,6 @@
|
|||||||
<logger name="org.eclipse.jetty.http.HttpParser" level="OFF" />
|
<logger name="org.eclipse.jetty.http.HttpParser" level="OFF" />
|
||||||
<logger name="org.eclipse.jetty.util.log" level="OFF" />
|
<logger name="org.eclipse.jetty.util.log" level="OFF" />
|
||||||
<logger name="org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler" level="OFF" />
|
<logger name="org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler" level="OFF" />
|
||||||
<logger name="org.bitcoinj.crypto.MnemonicCode" level="OFF" />
|
|
||||||
<logger name="org.springframework.core.KotlinDetector" level="OFF" />
|
<logger name="org.springframework.core.KotlinDetector" level="OFF" />
|
||||||
<logger name="org.springframework.http.converter.json.Jackson2ObjectMapperBuilder" level="OFF" />
|
<logger name="org.springframework.http.converter.json.Jackson2ObjectMapperBuilder" level="OFF" />
|
||||||
<logger name="org.springframework.web.HttpLogging" level="OFF" />
|
<logger name="org.springframework.web.HttpLogging" level="OFF" />
|
||||||
|
Loading…
x
Reference in New Issue
Block a user