Last active
May 18, 2018 16:11
-
-
Save james-d/f826c9f38d53628114124a56fb7c4557 to your computer and use it in GitHub Desktop.
JavaFX wrapper classes for sarxos webcam Java library. Wraps a web cam as a JavaFX Service and provides a View class for the service.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.github.sarxos.webcam.Webcam; | |
import javafx.application.Application; | |
import javafx.beans.binding.Bindings; | |
import javafx.geometry.Insets; | |
import javafx.geometry.Pos; | |
import javafx.scene.Scene; | |
import javafx.scene.control.Button; | |
import javafx.scene.layout.BorderPane; | |
import javafx.stage.Stage; | |
public class FXCamTest extends Application { | |
private WebCamService service ; | |
@Override | |
public void init() { | |
// note this is in init as it **must not** be called on the FX Application Thread: | |
Webcam cam = Webcam.getWebcams().get(0); | |
service = new WebCamService(cam); | |
} | |
@Override | |
public void start(Stage primaryStage) { | |
Button startStop = new Button(); | |
startStop.textProperty().bind(Bindings. | |
when(service.runningProperty()). | |
then("Stop"). | |
otherwise("Start")); | |
startStop.setOnAction(e -> { | |
if (service.isRunning()) { | |
service.cancel(); | |
} else { | |
service.restart(); | |
} | |
}); | |
WebCamView view = new WebCamView(service); | |
BorderPane root = new BorderPane(view.getView()); | |
BorderPane.setAlignment(startStop, Pos.CENTER); | |
BorderPane.setMargin(startStop, new Insets(5)); | |
root.setBottom(startStop); | |
Scene scene = new Scene(root); | |
primaryStage.setScene(scene); | |
primaryStage.show(); | |
} | |
public static void main(String[] args) { | |
launch(args); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- pom.xml to define dependency on webcam library --> | |
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
<modelVersion>4.0.0</modelVersion> | |
<groupId>WebCamTest</groupId> | |
<artifactId>WebCamTest</artifactId> | |
<version>0.0.1-SNAPSHOT</version> | |
<build> | |
<sourceDirectory>src</sourceDirectory> | |
<plugins> | |
<plugin> | |
<artifactId>maven-compiler-plugin</artifactId> | |
<version>3.3</version> | |
<configuration> | |
<source/> | |
<target/> | |
</configuration> | |
</plugin> | |
</plugins> | |
</build> | |
<dependencies> | |
<dependency> | |
<groupId>com.github.sarxos</groupId> | |
<artifactId>webcam-capture</artifactId> | |
<version>0.3.10</version> | |
</dependency> | |
</dependencies> | |
</project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.awt.Dimension; | |
import java.awt.image.BufferedImage; | |
import com.github.sarxos.webcam.Webcam; | |
import com.github.sarxos.webcam.WebcamResolution; | |
import javafx.concurrent.Service; | |
import javafx.concurrent.Task; | |
import javafx.embed.swing.SwingFXUtils; | |
import javafx.scene.image.Image; | |
public class WebCamService extends Service<Image> { | |
private final Webcam cam ; | |
private final WebcamResolution resolution ; | |
public WebCamService(Webcam cam, WebcamResolution resolution) { | |
this.cam = cam ; | |
this.resolution = resolution; | |
cam.setCustomViewSizes(new Dimension[] {resolution.getSize()}); | |
cam.setViewSize(resolution.getSize()); | |
} | |
public WebCamService(Webcam cam) { | |
this(cam, WebcamResolution.QVGA); | |
} | |
@Override | |
public Task<Image> createTask() { | |
return new Task<Image>() { | |
@Override | |
protected Image call() throws Exception { | |
try { | |
cam.open(); | |
while (!isCancelled()) { | |
if (cam.isImageNew()) { | |
BufferedImage bimg = cam.getImage(); | |
updateValue(SwingFXUtils.toFXImage(bimg, null)); | |
} | |
} | |
System.out.println("Cancelled, closing cam"); | |
cam.close(); | |
System.out.println("Cam closed"); | |
return getValue(); | |
} finally { | |
cam.close(); | |
} | |
} | |
}; | |
} | |
public int getCamWidth() { | |
return resolution.getSize().width ; | |
} | |
public int getCamHeight() { | |
return resolution.getSize().height ; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import javafx.scene.Node; | |
import javafx.scene.control.Label; | |
import javafx.scene.image.ImageView; | |
import javafx.scene.layout.Region; | |
public class WebCamView { | |
private final ImageView imageView ; | |
private final WebCamService service ; | |
private final Region view ; | |
private final Label statusPlaceholder ; | |
public WebCamView(WebCamService service) { | |
this.service = service ; | |
this.imageView = new ImageView(); | |
imageView.setPreserveRatio(true); | |
// make the cam behave like a mirror: | |
imageView.setScaleX(-1); | |
this.statusPlaceholder = new Label(); | |
this.view = new Region() { | |
{ | |
service.stateProperty().addListener((obs, oldState, newState) -> { | |
switch (newState) { | |
case READY: | |
statusPlaceholder.setText("Initializing"); | |
getChildren().setAll(statusPlaceholder); | |
break ; | |
case SCHEDULED: | |
statusPlaceholder.setText("Waiting"); | |
getChildren().setAll(statusPlaceholder); | |
break ; | |
case RUNNING: | |
imageView.imageProperty().unbind(); | |
imageView.imageProperty().bind(service.valueProperty()); | |
getChildren().setAll(imageView); | |
break ; | |
case CANCELLED: | |
System.out.println("Cancelled"); | |
imageView.imageProperty().unbind(); | |
imageView.setImage(null); | |
statusPlaceholder.setText("Stopped"); | |
getChildren().setAll(statusPlaceholder); | |
System.out.println("Processed cancel in view"); | |
break ; | |
case FAILED: | |
imageView.imageProperty().unbind(); | |
statusPlaceholder.setText("Error"); | |
getChildren().setAll(statusPlaceholder); | |
service.getException().printStackTrace(); | |
break ; | |
case SUCCEEDED: | |
// unreachable... | |
imageView.imageProperty().unbind(); | |
statusPlaceholder.setText(""); | |
getChildren().clear(); | |
} | |
requestLayout(); | |
}); | |
} | |
@Override | |
protected void layoutChildren() { | |
super.layoutChildren(); | |
double w = getWidth(); | |
double h = getHeight(); | |
if (service.isRunning()) { | |
imageView.setFitWidth(w); | |
imageView.setFitHeight(h); | |
imageView.resizeRelocate(0, 0, w, h); | |
} else { | |
double labelHeight = statusPlaceholder.prefHeight(w); | |
double labelWidth = statusPlaceholder.prefWidth(labelHeight); | |
statusPlaceholder.resizeRelocate((w - labelWidth)/2, (h-labelHeight)/2, labelWidth, labelHeight); | |
} | |
} | |
@Override | |
protected double computePrefWidth(double height) { | |
return service.getCamWidth(); | |
} | |
@Override | |
protected double computePrefHeight(double width) { | |
return service.getCamHeight(); | |
} | |
}; | |
} | |
public WebCamService getService() { | |
return service ; | |
} | |
public Node getView() { | |
return view ; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment