I've been searching for a solution to accessing a built-in webcam from a java or javaFX application. I've seen loads of other posts pointing to OpenCV and JavaCV, Sarxos's library and quite a few others.
I've run into difficulties such as newer versions of OpenCV not working with older code posted on various sites and newer code that uses OpenCV 3.0 is hard to find or doesn't do what I need, which is simply a customer application which saves an image taken from the web cam to a variable (or file).
Hope someone can point me in the right direction.
Thanks in advance
You're in luck. I toyed around with OpenCV last weekend and ran into the same problems as you. Here's an example about how to do it. The example opens the camera, uses an AnimationTimer (a bit overkill, but was a quick solution for prototyping) to grab a mat image periodically, converts the mat image to a JavaFX image, performs face detection and paints it on a canvas.
Here's what you need:
Download OpenCV, e. g. in my case the windows version. Rename the opencv-3.0.0.exe to opencv-3.0.0.exe.zip and open it. Extract the contents of build/java.
Create a new JavaFX project. Put the jar and dlls into a lib folder, e. g.:
lib/opencv-300.jar
lib/x64/opencv_java300.dll
Add the jar to your build path.
In your src folder create a path opencv/data/lbpcascades and put the file lbpcascade_frontalface.xml in there (found in etc/lbpcascades). That's only for face detection, you can uncomment the code in case you don't need it.
Create the application class, code:
import java.io.ByteArrayInputStream;
import java.lang.reflect.Field;
import java.net.URISyntaxException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.geometry.Rectangle2D;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.Image;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.MatOfRect;
import org.opencv.core.Rect;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.objdetect.CascadeClassifier;
import org.opencv.videoio.VideoCapture;
public class Camera extends Application {
private static final int SCENE_W = 640;
private static final int SCENE_H = 480;
CascadeClassifier faceDetector;
VideoCapture videoCapture;
Canvas canvas;
GraphicsContext g2d;
Stage stage;
AnimationTimer timer;
#Override
public void start(Stage stage) {
this.stage = stage;
initOpenCv();
canvas = new Canvas(SCENE_W, SCENE_H);
g2d = canvas.getGraphicsContext2D();
g2d.setStroke(Color.GREEN);
Group group = new Group(canvas);
Scene scene = new Scene(group, SCENE_W, SCENE_H);
stage.setScene(scene);
stage.setResizable(false);
stage.show();
timer = new AnimationTimer() {
Mat mat = new Mat();
#Override
public void handle(long now) {
videoCapture.read(mat);
List<Rectangle2D> rectList = detectFaces(mat);
Image image = mat2Image(mat);
g2d.drawImage(image, 0, 0);
for (Rectangle2D rect : rectList) {
g2d.strokeRect(rect.getMinX(), rect.getMinY(), rect.getWidth(), rect.getHeight());
}
}
};
timer.start();
}
public List<Rectangle2D> detectFaces(Mat mat) {
MatOfRect faceDetections = new MatOfRect();
faceDetector.detectMultiScale( mat, faceDetections);
System.out.println(String.format("Detected %s faces", faceDetections.toArray().length));
List<Rectangle2D> rectList = new ArrayList<>();
for (Rect rect : faceDetections.toArray()) {
int x = rect.x;
int y = rect.y;
int w = rect.width;
int h = rect.height;
rectList.add(new Rectangle2D(x, y, w, h));
}
return rectList;
}
private void initOpenCv() {
setLibraryPath();
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
videoCapture = new VideoCapture();
videoCapture.open(0);
System.out.println("Camera open: " + videoCapture.isOpened());
stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
public void handle(WindowEvent we) {
timer.stop();
videoCapture.release();
System.out.println("Camera released");
}
});
faceDetector = new CascadeClassifier(getOpenCvResource(getClass(), "/opencv/data/lbpcascades/lbpcascade_frontalface.xml"));
}
public static Image mat2Image(Mat mat) {
MatOfByte buffer = new MatOfByte();
Imgcodecs.imencode(".png", mat, buffer);
return new Image(new ByteArrayInputStream(buffer.toArray()));
}
private static void setLibraryPath() {
try {
System.setProperty("java.library.path", "lib/x64");
Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
fieldSysPath.setAccessible(true);
fieldSysPath.set(null, null);
} catch (Exception ex) {
ex.printStackTrace();
throw new RuntimeException(ex);
}
}
public static String getOpenCvResource(Class<?> clazz, String path) {
try {
return Paths.get( clazz.getResource(path).toURI()).toString();
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
launch(args);
}
}
Of course you can do whatever you wish (e. g. saving) with the JavaFX image once you have it.
for sarxos, pseudo code, i can't publish whole class:
import com.sleepingdumpling.jvideoinput.Device;
import com.sleepingdumpling.jvideoinput.VideoFrame;
import com.sleepingdumpling.jvideoinput.VideoInput;
Device choosenDevice;
for (Device device : VideoInput.getVideoDevices()) {
// select your choosenDevice webcam here
if (isMyWebcam(device)) {
choosenDevice = device;
break;
}
}
// eg. VideoInput(640,480,25,choosenDevice );
VideoInput videoInput = new VideoInput(frameWidth, frameHeigth,
frameRate, choosenDevice );
VideoFrame vf = null;
while (grabFrames) {
vf = videoInput.getNextFrame(vf);
if (vf != null) {
frameReceived(vf.getRawData());
// or vf.getBufferedImage();
}
}
videoInput.stopSession();
Related
I'm in the same situation as here : https://sourceforge.net/p/geotools/mailman/message/35977998/
I am working on a Maps Application using geotools (WMS + WFS for grids) and resizing my JavaFX Canvas works well when I am reducing the size of the canvas, but a part of the image is not rendered when I expend my window (the canvas is expended too).
Is there a solution ?
I'm posting the same example as the one in the link above :
import java.awt.Color;
import java.awt.Rectangle;
import org.geotools.feature.DefaultFeatureCollection;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.map.FeatureLayer;
import org.geotools.map.Layer;
import org.geotools.map.MapContent;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.renderer.lite.StreamingRenderer;
import org.geotools.styling.SLD;
import org.geotools.styling.Style;
import org.jfree.fx.FXGraphics2D;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class ResizingTest extends Application {
#Override
public void start(Stage stage) {
Canvas canvas = new Canvas(640, 480);
BorderPane root = new BorderPane(canvas);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
// Create bindings for resizing.
canvas.widthProperty().bind(root.widthProperty());
canvas.heightProperty().bind(root.heightProperty());
SimpleFeatureTypeBuilder lineFeatureTypeBuilder = new
SimpleFeatureTypeBuilder();
lineFeatureTypeBuilder.setName("LineFeatureType");
lineFeatureTypeBuilder.setCRS(DefaultGeographicCRS.WGS84);
lineFeatureTypeBuilder.add("the_geom", LineString.class,
DefaultGeographicCRS.WGS84);
SimpleFeatureType lineFeatureType = lineFeatureTypeBuilder.buildFe
atureType();
SimpleFeatureBuilder lineFeatureBuilder = new
SimpleFeatureBuilder(lineFeatureType);
DefaultFeatureCollection lines = new DefaultFeatureCollection();
Coordinate[][] cs = {
{ new Coordinate(-1, 42), new Coordinate(4, 46) },
{ new Coordinate(-1, 46), new Coordinate(4, 42) }
};
GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFa
ctory();
for(Coordinate [] c : cs) {
LineString line = geometryFactory.createLineString(c);
lineFeatureBuilder.add(line);
SimpleFeature feature = lineFeatureBuilder.buildFeature(null);
lines.add(feature);
}
MapContent map = new MapContent();
Style style = SLD.createLineStyle(Color.RED, 1);
Layer layer = new FeatureLayer(lines, style);
map.addLayer(layer);
//map.getViewport().setBounds(new ReferencedEnvelope(-1, 4, 42, 46,
DefaultGeographicCRS.WGS84));
AnimationTimer loop = new AnimationTimer() {
#Override
public void handle(long now) {
GraphicsContext g = canvas.getGraphicsContext2D();
FXGraphics2D graphics = new FXGraphics2D(g);
graphics.setBackground(java.awt.Color.BLUE);
Rectangle rectangle = new Rectangle( (int)
canvas.getWidth(), (int) canvas.getHeight());
graphics.clearRect(0, 0, (int) rectangle.getWidth(), (int)
rectangle.getHeight());
graphics.drawRect(100, 100, 100, 100);
map.getViewport().setScreenArea(rectangle); // Necessary ?
StreamingRenderer renderer = new StreamingRenderer();
renderer.setMapContent(map);
renderer.paint(graphics, rectangle,
map.getViewport().getBounds());
System.out.println("ScreenArea: " +
map.getViewport().getScreenArea() + " - Viewport: " +
map.getViewport().getBounds());
}
};
loop.start();
}
public static void main(String[] args) {
launch(args);
}
}
When we expand the window, a part of the canvas is not rendered anymore, resulting on a "correct" cross (because it still goes from upper left to lower right corner), but cropped ! Anything drawn on the cropped part is not rendered
Edit :
I am not trying to make the canvas resizable, it already is (Proof : The cross goes from upper left to lower right pixel of canvas). The real issue is the rendering of the map that is cropped (we can't see the full cross).
Resizing a canvas can be tricky in JavaFX. Here is a SO answer which may be helpful for you.
Automatically resize Canvas to fill the enclosing Parent
I finally found a fix !
As mentionned in geotools' StreamingRenderer code :
"the way this thing is built is a mess if you try to use it in a
multithreaded environment"
Avoid using StreamingRenderer in an AnimationLoop, Platform.runLater(), etc...
I called the draw function everytime the map was updated instead, and it works as expected ! :)
I'm developing a simple image editing functionality as a part of a larger JavaFX application, but I'm having some trouble to work out the undo/zoom and draw requirements together.
My requirements are the following:
The user should be able to:
Draw freehand on the image
Zoom in and out the image
Undo the changes
If the canvas is bigger than the window, it should have scroll-bars.
How I implemented these requirements:
The Drawing is done by starting a line when the mouse is pressed on the canvas, stroking it when it is dragged and closing the path when the button is released.
The Zoom works by scaling the canvas to a higher or lower value.
The Undo method takes a snapshot of the current state of the canvas when the mouse is pressed (before any change is made) and push it to a Stack of Images. When I need to undo some change I pop the last image of the Stack and draw it on the canvas, replacing the current image by the last one.
To have scroll-bars I just place the Canvas inside a Group and a ScrollPane.
Everything works fine, except when I try to draw on a scaled canvas. Due to the way I implemented the Undo functionality, I have to scale it back to 1, take a snapshot of the Node then scale it back to the size it was before. When this happens and the user is dragging the mouse the image position changes below the mouse pointer, causing it to draw a line that shouldn't be there.
Normal (unscaled canvas):
Bug (scaled canvas)
I tried the following approaches to solve the problem:
Don't re-scale to take the snapshot - Doesn't cause the unwanted line, but I end up with different image sizes in the stack, if it's smaller (zoomed out) when the snapshot was taken I now have a lower resolution of the image that I can't scale up without losing quality.
Tweak the logic and put the pushUndo call to the mouseReleased event - It almost worked, but when the user scrolled to a place and it's drawing there, the re-scaling causes the image to scroll back to the top-left;
Tried to search an way to "clone" or serialize the canvas and store the object state in the Stack - Didn't found anything I was able to adapt, and JavaFX doesn't support serialization of its objects.
I think the problem can be solved either by reworking the undo functionality as it doesn't need to re-scale the canvas to copy its state or by changing the way I zoom the canvas without scaling it, but I'm out of ideas on how to implement either of those options.
Below is the functional code example to reproduce the problem:
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollPane;
import javafx.scene.image.Image;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import java.util.Stack;
public class Main extends Application {
Stack<Image> undoStack;
Canvas canvas;
double canvasScale;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
canvasScale = 1.0;
undoStack = new Stack<>();
BorderPane borderPane = new BorderPane();
HBox hbox = new HBox(4);
Button btnUndo = new Button("Undo");
btnUndo.setOnAction(actionEvent -> undo());
Button btnIncreaseZoom = new Button("Increase Zoom");
btnIncreaseZoom.setOnAction(actionEvent -> increaseZoom());
Button btnDecreaseZoom = new Button("Decrease Zoom");
btnDecreaseZoom.setOnAction(actionEvent -> decreaseZoom());
hbox.getChildren().addAll(btnUndo, btnIncreaseZoom, btnDecreaseZoom);
ScrollPane scrollPane = new ScrollPane();
Group group = new Group();
canvas = new Canvas();
canvas.setWidth(400);
canvas.setHeight(300);
group.getChildren().add(canvas);
scrollPane.setContent(group);
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.setLineWidth(2.0);
gc.setStroke(Color.RED);
canvas.setOnMousePressed(mouseEvent -> {
pushUndo();
gc.beginPath();
gc.lineTo(mouseEvent.getX(), mouseEvent.getY());
});
canvas.setOnMouseDragged(mouseEvent -> {
gc.lineTo(mouseEvent.getX(), mouseEvent.getY());
gc.stroke();
});
canvas.setOnMouseReleased(mouseEvent -> {
gc.lineTo(mouseEvent.getX(), mouseEvent.getY());
gc.stroke();
gc.closePath();
});
borderPane.setTop(hbox);
borderPane.setCenter(scrollPane);
Scene scene = new Scene(borderPane, 800, 600);
stage.setScene(scene);
stage.show();
}
private void increaseZoom() {
canvasScale += 0.1;
canvas.setScaleX(canvasScale);
canvas.setScaleY(canvasScale);
}
private void decreaseZoom () {
canvasScale -= 0.1;
canvas.setScaleX(canvasScale);
canvas.setScaleY(canvasScale);
}
private void pushUndo() {
// Restore the canvas scale to 1 so I can get the original scale image
canvas.setScaleX(1);
canvas.setScaleY(1);
// Get the image with the snapshot method and store it on the undo stack
Image snapshot = canvas.snapshot(null, null);
undoStack.push(snapshot);
// Set the canvas scale to the value it was before the method
canvas.setScaleX(canvasScale);
canvas.setScaleY(canvasScale);
}
private void undo() {
if (!undoStack.empty()) {
Image undoImage = undoStack.pop();
canvas.getGraphicsContext2D().drawImage(undoImage, 0, 0);
}
}
}
Consider drawing Shape objects, in this case Path objects, and apply scale to them:
import java.util.Stack;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.stage.Stage;
public class Main extends Application {
private Path path;
private Stack<Path> undoStack;
private Group group;
private double scale = 1;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
undoStack = new Stack<>();
Button btnUndo = new Button("Undo");
btnUndo.setOnAction(actionEvent -> undo());
Button btnIncreaseZoom = new Button("Increase Zoom");
btnIncreaseZoom.setOnAction(actionEvent -> increaseZoom());
Button btnDecreaseZoom = new Button("Decrease Zoom");
btnDecreaseZoom.setOnAction(actionEvent -> decreaseZoom());
HBox hbox = new HBox(4, btnUndo, btnIncreaseZoom, btnDecreaseZoom);
group = new Group();
BorderPane root = new BorderPane(new Pane(group), hbox, null,null, null);
Scene scene = new Scene(root, 300, 400);
root.setOnMousePressed(mouseEvent -> newPath(mouseEvent.getX(), mouseEvent.getY()));
root.setOnMouseDragged(mouseEvent -> addToPath(mouseEvent.getX(), mouseEvent.getY()));
primaryStage.setScene(scene);
primaryStage.show();
}
private void newPath(double x, double y) {
path = new Path();
path.setStrokeWidth(1);
path.setStroke(Color.BLACK);
path.getElements().add(new MoveTo(x,y));
group.getChildren().add(path);
undoStack.add(path);
}
private void addToPath(double x, double y) {
path.getElements().add(new LineTo(x, y));
}
private void increaseZoom() {
scale += 0.1;
reScale();
}
private void decreaseZoom () {
scale -= 0.1;
reScale();
}
private void reScale(){
for(Path path : undoStack){
path.setScaleX(scale);
path.setScaleY(scale);
}
}
private void undo() {
if(! undoStack.isEmpty()){
Node node = undoStack.pop();
group.getChildren().remove(node);
}
}
}
I solved the problem by extending the Canvas component and adding a second canvas in the extended class to act as a copy of the main canvas.
Every time I made a change in the canvas I do the same change in this "carbon" canvas. When I need to re-scale the canvas to get the snapshot (the root of my problem) I just re-scale the "carbon" canvas back to 1 and get my snapshot from it. This doesn't cause the drag of the mouse in the main canvas, as it remains scaled during this process. Probably this isn't the optimal solution, but it works.
Below is the code for reference, to anyone who may have a similar problem in the future.
ExtendedCanvas.java
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.Image;
import java.util.Stack;
public class ExtendedCanvas extends Canvas {
private final double ZOOM_SCALE = 0.1;
private final double MAX_ZOOM_SCALE = 3.0;
private final double MIN_ZOOM_SCALE = 0.2;
private double currentScale;
private final Stack<Image> undoStack;
private final Stack<Image> redoStack;
private final Canvas carbonCanvas;
private final GraphicsContext gc;
private final GraphicsContext carbonGc;
public ExtendedCanvas(double width, double height){
super(width, height);
carbonCanvas = new Canvas(width, height);
undoStack = new Stack<>();
redoStack = new Stack<>();
currentScale = 1.0;
gc = this.getGraphicsContext2D();
carbonGc = carbonCanvas.getGraphicsContext2D();
setEventHandlers();
}
private void setEventHandlers() {
this.setOnMousePressed(mouseEvent -> {
pushUndo();
gc.beginPath();
gc.lineTo(mouseEvent.getX(), mouseEvent.getY());
carbonGc.beginPath();
carbonGc.lineTo(mouseEvent.getX(), mouseEvent.getY());
});
this.setOnMouseDragged(mouseEvent -> {
gc.lineTo(mouseEvent.getX(), mouseEvent.getY());
gc.stroke();
carbonGc.lineTo(mouseEvent.getX(), mouseEvent.getY());
carbonGc.stroke();
});
this.setOnMouseReleased(mouseEvent -> {
gc.lineTo(mouseEvent.getX(), mouseEvent.getY());
gc.stroke();
gc.closePath();
carbonGc.lineTo(mouseEvent.getX(), mouseEvent.getY());
carbonGc.stroke();
carbonGc.closePath();
});
}
public void zoomIn() {
if (currentScale < MAX_ZOOM_SCALE ) {
currentScale += ZOOM_SCALE;
setScale(currentScale);
}
}
public void zoomOut() {
if (currentScale > MIN_ZOOM_SCALE) {
currentScale -= ZOOM_SCALE;
setScale(currentScale);
}
}
public void zoomNormal() {
currentScale = 1.0;
setScale(currentScale);
}
private void setScale(double value) {
this.setScaleX(value);
this.setScaleY(value);
carbonCanvas.setScaleX(value);
carbonCanvas.setScaleY(value);
}
private void pushUndo() {
redoStack.clear();
undoStack.push(getSnapshot());
}
private Image getSnapshot(){
carbonCanvas.setScaleX(1);
carbonCanvas.setScaleY(1);
Image snapshot = carbonCanvas.snapshot(null, null);
carbonCanvas.setScaleX(currentScale);
carbonCanvas.setScaleY(currentScale);
return snapshot;
}
public void undo() {
if (hasUndo()) {
Image redo = getSnapshot();
redoStack.push(redo);
Image undoImage = undoStack.pop();
gc.drawImage(undoImage, 0, 0);
carbonGc.drawImage(undoImage, 0, 0);
}
}
public void redo() {
if (hasRedo()) {
Image undo = getSnapshot();
undoStack.push(undo);
Image redoImage = redoStack.pop();
gc.drawImage(redoImage, 0, 0);
carbonGc.drawImage(redoImage, 0, 0);
}
}
public boolean hasUndo() {
return !undoStack.isEmpty();
}
public boolean hasRedo() {
return !redoStack.isEmpty();
}
}
Main.java
package com.felipepaschoal;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class Main extends Application {
ExtendedCanvas extendedCanvas;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
BorderPane borderPane = new BorderPane();
HBox hbox = new HBox(4);
Button btnUndo = new Button("Undo");
btnUndo.setOnAction(actionEvent -> extendedCanvas.undo());
Button btnRedo = new Button("Redo");
btnRedo.setOnAction(actionEvent -> extendedCanvas.redo());
Button btnDecreaseZoom = new Button("-");
btnDecreaseZoom.setOnAction(actionEvent -> extendedCanvas.zoomOut());
Button btnResetZoom = new Button("Reset");
btnResetZoom.setOnAction(event -> extendedCanvas.zoomNormal());
Button btnIncreaseZoom = new Button("+");
btnIncreaseZoom.setOnAction(actionEvent -> extendedCanvas.zoomIn());
hbox.getChildren().addAll(
btnUndo,
btnRedo,
btnDecreaseZoom,
btnResetZoom,
btnIncreaseZoom
);
ScrollPane scrollPane = new ScrollPane();
Group group = new Group();
extendedCanvas = new ExtendedCanvas(300,200);
group.getChildren().add(extendedCanvas);
scrollPane.setContent(group);
borderPane.setTop(hbox);
borderPane.setCenter(scrollPane);
Scene scene = new Scene(borderPane, 600, 400);
stage.setScene(scene);
stage.show();
}
}
like this blank image is saving
import java.io.File;
import java.io.IOException;
import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.effect.Light.Point;
import javafx.scene.image.WritableImage;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import javax.imageio.ImageIO;
public class JavaFxSelectPlay extends Application {
public static void main(String[] args) {
launch();
}
#Override
public void start(Stage primaryStage) throws Exception {
Pane root = new Pane();
WebView wv = new WebView();
WebEngine Img = wv.getEngine();
Img.load("https://app.leadlock.pro/upload/69/1019/images/welcome.jpeg");
final Rectangle selection = new Rectangle();
final Point anchor = new Point();
wv.setOnMousePressed(event -> {
anchor.setX(event.getX());
anchor.setY(event.getY());
selection.setX(event.getX());
selection.setY(event.getY());
selection.setFill(null); // transparent
selection.setStroke(Color.BLACK); // border
selection.getStrokeDashArray().add(10.0);
root.getChildren().add(selection);
});
wv.setOnMouseDragged(event -> {
selection.setWidth(Math.abs(event.getX() - anchor.getX()));
selection.setHeight(Math.abs(event.getY() - anchor.getY()));
selection.setX(Math.min(anchor.getX(), event.getX()));
selection.setY(Math.min(anchor.getY(), event.getY()));
});
wv.setOnMouseReleased(event -> {
// Do what you want with selection's properties here
System.out.printf("X: %.2f, Y: %.2f, Width: %.2f, Height: %.2f%n",
selection.getX(), selection.getY(), selection.getWidth(), selection.getHeight());
// root.getChildren().remove(selection);
// selection.setWidth(0);
// selection.setHeight(0);
});
wv.addEventFilter(KeyEvent.KEY_RELEASED, (KeyEvent e1) -> {
if (e1.getCode() == KeyCode.SPACE ) {
selection.setFill(Color.WHITE); // transparent
}
});
wv.setOnKeyPressed(new EventHandler<KeyEvent>() {
public void handle(final KeyEvent keyEvent) {
if (keyEvent.getCode() == KeyCode.F5) {
System.out.println("F5 pressed");
//Stop letting it do anything else
// WritableImage croppedImage = selection.snapshot(null, null);
WritableImage image = selection.snapshot(new SnapshotParameters(), null);
// TODO: probably use a file chooser here
File file = new File("C:/temp/snapshot.jpg");
try {
ImageIO.write(SwingFXUtils.fromFXImage(image, null), "jpg", file);
} catch (IOException e) {
// TODO: handle exception here
}
}
System.out.println("snapshot saved: " );
}
});
root.getChildren().add(wv);
Scene scene = new Scene(root, 300, 200);
primaryStage.setScene(scene);
primaryStage.setTitle("Primary Stage");
primaryStage.show();
}
}
this code i tried and its running fine but the image that is saved is saved with white color its not saved the orginal selected image so how can i do it please help i need to save the selected image and i had done white but not with white color but the selected image so please tell me how to do it and what im doing wrong.
It seems there are two things going on here.
Firstly, instead of taking a snapshot of the Rectangle you are using to mark the selection, you probably want to take a snapshot of the root and use the selection rectangle to specify what part of the snapshot to take. So, instead of writing
WritableImage image = selection.snapshot(new SnapshotParameters(), null);
try writing
SnapshotParameters params = new SnapshotParameters();
params.setViewport(
new Rectangle2D(
selection.getX(),
selection.getY(),
selection.getWidth(),
selection.getHeight()));
root.getChildren().remove(selection);
WritableImage image = root.snapshot(params, null);
I've also removed the rectangle from the root so that it doesn't appear in the output image.
The second thing that happens is that the image comes out pink. This appears to be an existing issue which is supposed to have been fixed in Java 8 but I can still reproduce it in Java 8 update 152. Adapting the code in the question I linked to, you would have to replace the line
ImageIO.write(SwingFXUtils.fromFXImage(image, null), "jpg", file);
with
BufferedImage bufferedImage = SwingFXUtils.fromFXImage(image, null);
BufferedImage imageRGB = new BufferedImage(
bufferedImage.getWidth(), bufferedImage.getHeight(), BufferedImage.OPAQUE);
Graphics2D graphics = imageRGB.createGraphics();
graphics.drawImage(bufferedImage, 0, 0, null);
ImageIO.write(imageRGB, "jpg", file);
I need to create a video player using Java for my project. I have already checked many examples on the Internet. Some of them run, but do not show any screen, I can only hear the sound of the video. Please help me solve this...
I am using the below import
import javax.media.*;
EDIT:
Below is the code that i use:
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import javax.media.*;
public class MediaPlayerDemo extends JFrame
{
private Player player;
private File file;
public MediaPlayerDemo()
{
super( "Demonstrating the Java Media Player" );
JButton openFile = new JButton( "Open file to play" );
openFile.addActionListener( new ActionListener()
{
public void actionPerformed( ActionEvent e )
{
openFile();
createPlayer();
}
});
getContentPane().add( openFile, BorderLayout.NORTH );
setSize( 300, 300 );
show();
}
private void openFile()
{
JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileSelectionMode( JFileChooser.FILES_ONLY );
int result = fileChooser.showOpenDialog( this );
// user clicked Cancel button on dialog
if ( result == JFileChooser.CANCEL_OPTION )
file = null;
else
file = fileChooser.getSelectedFile();
}
private void createPlayer()
{
if ( file == null )
return;
removePreviousPlayer();
try
{
// create a new player and add listener
player = Manager.createPlayer( file.toURL() );
player.addControllerListener( new EventHandler() );
player.start(); // start player
}
catch ( Exception e )
{
JOptionPane.showMessageDialog( this, "Invalid file or location", "Error loading file",
JOptionPane.ERROR_MESSAGE );
}
}
private void removePreviousPlayer()
{
if ( player == null )
return;
player.close();
Component visual = player.getVisualComponent();
Component control = player.getControlPanelComponent();
Container c = getContentPane();
if ( visual != null )
c.remove( visual );
if ( control != null )
c.remove( control );
}
public static void main(String args[])
{
MediaPlayerDemo app = new MediaPlayerDemo();
app.addWindowListener( new WindowAdapter()
{
public void windowClosing( WindowEvent e )
{
System.exit(0);
}
});
}
// inner class to handler events from media player
private class EventHandler implements ControllerListener
{
public void controllerUpdate( ControllerEvent e )
{
if ( e instanceof RealizeCompleteEvent )
{
Container c = getContentPane();
// load Visual and Control components if they exist
Component visualComponent = player.getVisualComponent();
if ( visualComponent != null )
c.add( visualComponent, BorderLayout.CENTER );
Component controlsComponent = player.getControlPanelComponent();
if ( controlsComponent != null )
c.add( controlsComponent, BorderLayout.SOUTH );
c.doLayout();
}
}
}
}
I used vlcj and it worked smoothly. It's java binding to vlcj player and the good thing that you don't have to provide any drives since vlcj already includes all of them in binary distribution.
Give it a go, there is example of already working player built for you!
Try a JavaFX Mediaplayer:
Usable Codecs:
Audio: MP3; AIFF containing uncompressed PCM; WAV containing uncompressed PCM; MPEG-4 multimedia container with Advanced Audio Coding (AAC) audio
Video: FLV containing VP6 video and MP3 audio; MPEG-4 multimedia
container with H.264/AVC (Advanced Video Coding) video compression .
Here an example from Oracle:
import javafx.application.Application;
import javafx.collections.ListChangeListener;
import javafx.collections.MapChangeListener;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.media.Media;
import javafx.scene.media.MediaView;
import javafx.scene.media.Track;
import javafx.stage.Stage;
/**
* A sample media player which loops indefinitely over the same video
*/
public class MediaPlayer extends Application {
private static final String MEDIA_URL = "http://someserver/somedir/somefile.mp4";
private static String arg1;
#Override public void start(Stage stage) {
stage.setTitle("Media Player");
// Create media player
Media media = new Media((arg1 != null) ? arg1 : MEDIA_URL);
javafx.scene.media.MediaPlayer mediaPlayer = new javafx.scene.media.MediaPlayer(media);
mediaPlayer.setAutoPlay(true);
mediaPlayer.setCycleCount(javafx.scene.media.MediaPlayer.INDEFINITE);
// Print track and metadata information
media.getTracks().addListener(new ListChangeListener<Track>() {
public void onChanged(Change<? extends Track> change) {
System.out.println("Track> "+change.getList());
}
});
media.getMetadata().addListener(new MapChangeListener<String,Object>() {
public void onChanged(MapChangeListener.Change<? extends String, ? extends Object> change) {
System.out.println("Metadata> "+change.getKey()+" -> "+change.getValueAdded());
}
});
// Add media display node to the scene graph
MediaView mediaView = new MediaView(mediaPlayer);
Group root = new Group();
Scene scene = new Scene(root,800,600);
root.getChildren().add(mediaView);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
if (args.length > 0) {
arg1 = args[0];
}
Application.launch(args);
}
}
https://blogs.oracle.com/javafx/entry/mpeg_4_multimedia_support_in
Here is the working code.
package New;
import java.net.URL;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.effect.DropShadow;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaPlayer.Status;
import javafx.scene.media.MediaView;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class FxMediaExample2 extends Application {
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage stage) {
// Locate the media content in the CLASSPATH
URL mediaUrl = getClass().getResource("Test.mp4");
String mediaStringUrl = mediaUrl.toExternalForm();
// Create a Media
Media media = new Media(mediaStringUrl);
// Create a Media Player
final MediaPlayer player = new MediaPlayer(media);
// Automatically begin the playback
player.setAutoPlay(true);
// Create a 400X300 MediaView
MediaView mediaView = new MediaView(player);
mediaView.setFitWidth(400);
mediaView.setFitHeight(300);
mediaView.setSmooth(true);
mediaView.setLayoutX(200);
mediaView.setLayoutY(200);
// Create the DropShadow effect
DropShadow dropshadow = new DropShadow();
dropshadow.setOffsetY(5.0);
dropshadow.setOffsetX(5.0);
dropshadow.setColor(Color.RED);
mediaView.setEffect(dropshadow);
Rectangle rect4 = new Rectangle(35, 55, 95, 25);
rect4.setFill(Color.RED);
rect4.setStroke(Color.BLACK);
rect4.setStrokeWidth(1);
// Create the HBox
// HBox controlBox = new HBox(5, null, null);
// Create the VBox
VBox root = new VBox(1, mediaView);
GridPane gridpane = new GridPane();
gridpane.setPadding(new Insets(95));
gridpane.setHgap(1);
gridpane.setVgap(10);
GridPane.setHalignment(rect4, HPos.CENTER);
Group grp = new Group();
gridpane.add(root, 1, 1);
grp.getChildren().add(gridpane);
// Create the Scene
Scene scene = new Scene(grp);
// Add the scene to the Stage
stage.setScene(scene);
// Set the title of the Stage
stage.setTitle("A simple Media Example");
// Display the Stage
stage.show();
}
}
Java Media Framework can be used to create multimedia applications like video and audio players.
I need to get the background image from a PowerPoint slide using java. I am aware of the Apache POI project. I can find material for getting text and shapes from the slides, but not the actual background. Does anyone have any suggestions?
EDIT: I have creaked the following code using the suggested link. This code seems to grab the contents of the slide, but not exactly the background. The resulting images are white for the background.
I tried it with this PowerPoint
package PowerPointProcessing;
import Logging.LogRunner;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import org.apache.poi.hslf.HSLFSlideShow;
import org.apache.poi.hslf.model.Background;
import org.apache.poi.hslf.model.Fill;
import org.apache.poi.hslf.model.Shape;
import org.apache.poi.hslf.model.Slide;
import org.apache.poi.hslf.usermodel.SlideShow;
/**
*
* #author dvargo
*/
public class PPI
{
Dimension pageSize;
public Slide[] theSlides;
public PPI(String powerPointFilePath)
{
SlideShow ppt = null;
//open the presentation
try
{
ppt = new SlideShow(new HSLFSlideShow(powerPointFilePath));
}
catch(Exception e)
{
LogRunner.getLogger().severe("Could not open the powerpoint presentation");
return;
}
//get all the slides
theSlides = ppt.getSlides();
//see how many slides there are
int numberOfSlides = theSlides.length;
pageSize = ppt.getPageSize();
}
public BufferedImage getBackground(Slide theSlide)
{
Background background;
background = theSlide.getBackground();
Fill f = background.getFill();
Color color = f.getForegroundColor();
Shape[] theShapes = theSlide.getShapes();
BufferedImage img = new BufferedImage(pageSize.width, pageSize.height, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = img.createGraphics();
graphics.setPaint(color);
graphics.fill(new Rectangle2D.Float(0, 0, pageSize.width, pageSize.height));
theSlide.draw(graphics);
return img;
}
public static void main(String[] args) {
PPI ppi = new PPI("C:\\Documents and Settings\\dvargo\\Desktop\\Cludder\\a.ppt");
int count= 0;
for (Slide currSlide : ppi.theSlides)
{
BufferedImage img = ppi.getBackground(currSlide);
try
{
ImageIO.write(img, "jpeg", new File("C:\\Documents and Settings\\dvargo\\Desktop\\ppt\\" + count + ".jpeg"));
}
catch (IOException ex)
{
Logger.getLogger(PPI.class.getName()).log(Level.SEVERE, null, ex);
}
count++;
}
}
}
Looking at the code from this question:
Extracting images from pptx with apache poi
Looks like it should be something like:
Background background = slides[current].getBackground();
Fill f = background.getFill();
Color color = f.getForegroundColor();