Skip to content

Instantly share code, notes, and snippets.

@james-d
Last active May 18, 2018 16:11
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save james-d/f826c9f38d53628114124a56fb7c4557 to your computer and use it in GitHub Desktop.
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.
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);
}
}
<!-- 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>
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 ;
}
}
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