Virtual Camcorder in JavaFX
A few words about me: I belong to Gen X who developed complex software using a simple editor (e.g. notepad++ or jedit, etc.). I was the senior developer of BEA Weblogic (which is now owned by Oracle). In 2001 I sold my BEA shares and retired at exactly 50. Today, as an old man, I still develop some apps for my own needs and… just for fun. Unlike Gen-Y and Gen-Z, we have always tried to keep software development as simple as possible. No unnecessary dependency files, no framework, no IDE. Everything is manageable and controllable. It’s simple because the more files you have to manage, the more confusion there is for yourself and within the team. And in the end, no one can see through or master a huge pile of different files like XMLs, resources of icons and images, text files, sources, etc.
I believe everyone knows animated image with the suffix GIF (or Graphics Interchange Format). As an IT developer, have you ever thought about how you can develop an app that captures videos and converts the images into a GIF file? This is very easy in JAVA. I’ll show you how to create an app that captures videos (e.g. YouTube or any animated GIF) on the screen and lets you create your own GIF files that can be edited, etc.
First of all, an animation is a sequence of images that are slightly different from each other and occur in a rapid timeframe. Normally the animation is vivid when the sequence of timeframes is around 25 frames per second. There are two ways to capture images on the screen: an external camera or a screenshot. The first option is out of the question. The second option basically simulates an external camera that can take the screenshots fast enough to display a vivid animation (i.e. 25 time frames per second).
Then some words about coding: Coding is a question of belief. There is someone who relies only on framework and IDE which produce a heap of dependency files and lots of small APIs grouped into “package”. The others, for example, love simple but convenient editors like Notepad++ or Jedit. Whatever the people like, coding is similar to construction of a house: first the foundation, then the house frame, then the roof, then the door and windows, etc. None of the works can be done in parallel. For this reason, I will show you the codes and basic development of an application without going into Frameworks or IDEs.
In addition, I will show you how to “exploit” all the most beautiful JavaFX features that are hidden or unknown to many. For example, JavaFX with multiple Stages (like Swing with multiple JFrames) always floats on top (regardless of other running apps), JavaFX CSS tricks and last but not least the use of a concurrency pool (ForkJoinPool).
Note: JavaFX is not an integral part of Java as of JDK 11, so I recommend you use the most stable JDK 8 or JDK 9.
The basic development environment:
- Working directory: for example: C:\myapp\gif (similar in Linux), where the sources are created.
- Compile: Open a CMD window (terminal under Linux). Example:
- Set CLASSPATH. For example, on WINDOWS: Create a batch file setCP.bat as follows:
// on Windows - should be in System Environment variables
set CLASSPATH=%CLASSPATH%;.;.\classes
// on LINUX - should be in .profile
export CLASSPATH=$CLASSPATH:.:./classes
The 3rd step includes the current (a dot) working directory and the subdirectory “classes” (.\classes or ./classes) to the Java variable CLASSPATH.
The source that simulates a camera is CamCorder.java (Camera + reCorder) and is written in JavaFX. As mentioned above, we lay the foundation for CamCorder with the control panel, then the camera frame is the “lens”. From them we begin to develop the functionalities of a virtual camera. The source is written in JAVA JFX. At the end of this tutorial, I’ll post the complete package of CamCorder here in ZIP format.
The CamCorder Control Panel (CamCorder.java)
public class CamCorder extends Application {
//
public void start(Stage panel) {
this.panel = panel;
panel.setOnCloseRequest(ev -> {
ev.consume(); // Ignore the close by pressing X in the rightmost upper corner
});
...
focus = Tools.getButton("FOCUS", "Focus Screen Image");
focus.setOnAction(ev -> {
});
start = Tools.getButton("START", "Start Recording Screen");
start.setOnAction(ev -> {
if (!focused) {
System.out.println("Nowhere on SCREEN is focused.");
return;
}
if (idle) {
start.setText("STOP");
} else {
start.setText("START");
}
});
//
load = Tools.getButton("LOAD", "Load from GIF/GZIP image file");
load.setOnAction(ev -> {
});
edit = Tools.getButton("EDIT", "Edit BufferedImages");
edit.setOnAction(ev -> {
editing();
});
undo = Tools.getButton("UNDO", "Undo Editing");
undo.setOnAction(ev -> {
});
show = Tools.getButton("SHOW", "Show animated BufferedImages");
show.setOnAction(ev -> {
});
save = Tools.getButton(new Image(CamCorder.class.getResourceAsStream("save.png")),
"Save to GIF/GZIP file");
save.setOnAction(ev -> {
});
reset = Tools.getButton("RESET", "RESET");
reset.setOnAction(ev -> {
});
Button quit = Tools.getButton("QUIT", "Quit & Exit CamCorder");
quit.setOnAction(ev -> {
panel.close();
Platform.exit();
System.exit(0);
});
VBox bBox = new VBox(5);
bBox.setAlignment(Pos.CENTER);
// Insets(top, right, bottom, left)
bBox.setPadding(new Insets(10, 0, 15, 0));
bBox.getChildren().addAll(focus, start, load, edit, undo, show, save, reset, quit);
Scene scene = new Scene(bBox, 145, 350);
scene.getStylesheets().add("gif.css");
panel.getIcons().add(new Image(CamCorder.class.getResourceAsStream("sanduhr.gif")));
panel.setAlwaysOnTop(true);
panel.setResizable(false);
panel.setScene(scene);
panel.setY(0);
panel.setX(0);
panel.show();
CamCorder ControlPanel
Explanation:
- All JFX buttons are activated by lambda expression (e -> { … });
- Line scene.getStylesheets().add(“gif.css”) uses the style from the external file gif.css
- Line panel.setAlwaysOnTop(true) always places the ControlPanel above other applications.
The ControlPanel is the foundation and contains 9 buttons. With the implementation of Tools.getButton(), a hint text with the description of the button appears when the mouse pointer hovers over the buttons. Nine buttons means 9 CamCorder activities need to be implemented.
The Tools codes (Tools.java):
public class Tools {
...
/**
@param icon JFX Image or String
@param txt String as tooltip or button name (if icon = null)
@return Button
*/
public static Button getButton(Object icon, String txt) {
Button button = null;
if (icon == null || icon instanceof String) {
button = new Button(icon == null? txt:(String)icon);
// direct CSS style
button.setStyle("-fx-font-size:11; -fx-font-weight: bold;");
} else try {
button = new Button( );
button.setGraphic(new ImageView((Image) icon));
} catch (Exception ex) {
button = new Button(txt);
button.setStyle("-fx-font-weight: bold;");
}
Tooltip tt = new Tooltip();
tt.setText(txt);
tt.setStyle("-fx-base: #AE3522; -fx-text-fill: orange; -fx-font-cb: bold;");
button.setTooltip(tt);
return button;
}
Explanation:
- If the icon is null or a string, the button name is either txt (null) or this icon string
- otherwise the button is represented by the specified icon.
(to be continued)