Save Node or Scene to Image in JavaFX 2.0


Even after waiting so many days, the Javafx bug team has not implemented this feature still in this new Javafx General Availability release . So I’ve managed to make blog about this function for javafx. Many javafx enterprises developer may think that javafx is still not useful because they don’t know how to save their graphics component in image format. Developer don’t have a simple api function like sceneToImage() which was provided in javafx script 1.3. Don’t know why ? We developers are that’s why intelligent to find the alternative way. So I also intended to research on this topic.Then started to warmup my hands on keyboard.

We are using some Java apis and JavaFX apis for making these things work. Ok Let’s get started with the class ‘FXImaging’

1
FXImaging.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
import java.awt.Container;
import java.awt.Graphics;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.image.BufferedImage;
import java.io.File;
import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.embed.swing.JFXPanel;
import javafx.geometry.BoundingBox;
import javafx.geometry.Bounds;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.Timer;
/**
*
* @author Narayan
*/
publicclassFXImaging{
/**
* Some of the important private variables;
*/
privateJFXPanel fxPanel;
privateintTIME=200;
privateFile file;
privateJFrame frame;
privateBoundingBox boundbox;
privateTimer timer;
privateStage stage;
privateScene scene;
privateObservableList list;
privateNode node;
/**
*
* @param scene the scene which is to be imaged
* @param save place where the image to be saved
* @param width width of image
* @param height height of image
*/
publicvoidsceneToImage(finalScene scene,finalFile save,doublewidth,doubleheight){
stage=(Stage)scene.getWindow();
this.scene=scene;
BoundingBox bound=null;
if(width>0&&height>0){
bound=newBoundingBox(0,0,width,height);
}
initAndShowGUI(scene,save,bound);
}
/**
* Overload function of sceneToImage
*
* @param scene
* @param save
*/
publicvoidsceneToImage(finalScene scene,finalFile save){
sceneToImage(scene,save,0,0);
}
/**
* This function helps to save the Node to Image
* and it's the only function which is public
*
* @param node node to be saved
* @param list list of children where the node is kept
* @param save place where the image to be saved
*/
publicvoidnodeToImage(finalNode node,finalObservableList list,finalFile save){
nodeToImage(node,list,save,0,0);
}
/**
* This function helps to save the Node to Image
* and it's the only function which is public
*
* @param node the node to be saved
* @param list the ObservableList of children where the node is kept
* @param save place where the image to be saved
* @param width width of image to be saved
* @param height height of image to be saveed
*/
publicvoidnodeToImage(finalNode node,finalObservableList list,finalFile save,finaldoublewidth,finaldoubleheight){
stage=(Stage)node.getScene().getWindow();
scene=node.getScene();
this.node=node;
this.list=list;
BoundingBox bound=null;
if(width>0&&height>0){
bound=newBoundingBox(0,0,width,height);
}
initAndShowGUI(node,save,bound);
}
/**
* This is the main function to generate the graphics of the Node
* using the FXPanel inside the JFrame.
* @param node
* @param f
* @param bound
*/
privatevoidinitAndShowGUI(finalNode node,Filef,BoundingBox bound){
Group root=newGroup();
Scene sc=newScene(root);
root.getChildren().add(node);
initAndShowGUI(sc,f,bound);
}
/**
* This is the main function to generate the graphics of the scene
* using the FXPanel inside the JFrame.
*
* @param sc
* @param f
* @param bound
*/
privatevoidinitAndShowGUI(finalScene sc,Filef,BoundingBox bound){
file=f;
if(bound==null)
boundbox=newBoundingBox(0,0,stage.getWidth(),stage.getHeight());
else
boundbox=bound;
frame=newJFrame();
//Frame.setUndecorated(true);
fxPanel=newJFXPanel();
fxPanel.setScene(sc);
fxPanel.addComponentListener(newComponentListener(){
publicvoidcomponentResized(ComponentEvente){
ActionListener ac=newActionListener(){
publicvoidactionPerformed(java.awt.event.ActionEvente){
save(fxPanel,boundbox,file);
timer.stop();
fxPanel.removeAll();
restore();
frame.dispose();
}
};
//I've set timer for capturing image of the Node
timer=newTimer(TIME,ac);
timer.start();
}
publicvoidcomponentMoved(ComponentEvente){
}
publicvoidcomponentShown(ComponentEvente){
}
publicvoidcomponentHidden(ComponentEvente){
}
});
frame.add(fxPanel);
frame.setSize((int)boundbox.getWidth(),(int)boundbox.getHeight());
if(stage!=null){
frame.setLocation((int)stage.getX(),(int)stage.getY());
Platform.runLater(newRunnable(){
publicvoidrun(){
stage.hide();
}
});
}
frame.setVisible(true);
}
/**
* This function saves the container as FXPanel
* to the Image using the Java API
* @param container
* @param bounds
* @param file
*/
privatevoidsave(Container container,Bounds bounds,File file){
try{
Stringextension="";
Stringname=file.getName();
if(name.contains(".")){
intstart=name.lastIndexOf(".");
extension=file.getName().substring(start+1);
}
else{
extension="jpg";
}
ImageIO.write(toBufferedImage(container,bounds),extension,file);
System.out.println("Node To Image saved");
}catch(java.lang.Exception exception){
exception.printStackTrace();
JOptionPane.showMessageDialog(null,"The image couldn't be saved","Error",JOptionPane.ERROR_MESSAGE);
restore();
}
}
/**
* Restoring the scene or Node to it's original state
*/
privatevoidrestore(){
if(node!=null){
restoreNode();
}else{
restoreScene();
}
}
/**
* Restores the Node
*/
privatevoidrestoreNode(){
Platform.runLater(newRunnable(){
publicvoidrun(){
list.add(node);
stage.show();
}
});
}
/**
* This function restores the main Scene to the original Stage
* from where the event has been triggered
*/
privatevoidrestoreScene(){
Platform.runLater(newRunnable(){
publicvoidrun(){
stage.setScene(scene);
stage.show();
}
});
}
/**
* This function is used to get the BufferedImage of the
* Container as JFXPanel
* @param container
* @param bounds
* @return
*/
privateBufferedImage toBufferedImage(Container container,Bounds bounds){
BufferedImage bufferedImage=newBufferedImage(
(int)bounds.getWidth(),
(int)bounds.getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics graphics=bufferedImage.getGraphics();
graphics.translate((int)-bounds.getMinX(),(int)-bounds.getMinY());// translating to upper-left corner
container.paint(graphics);
graphics.dispose();
returnbufferedImage;
}
}

I’ve commented the codes so that you will understand the use of the function properly. In above class the nodeToImage(),sceneToImage() are the function which help to save your Node or Scene into Image format. The save() function helps to save your bufferedImage from JavaAPI. After saving the image the Node/Scene is being restored to the original stage from where the Node/Scene is being taken. The algorithm of saving Node/Scene is given in the picture below.

Now you can easily save your Node or Scene in the Image format. Below is one of the sample demo of saving the Scene into Image.

1
FXImagingTest.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
" ]public class FXImagingTest extends Application {
private ObservableList<String> items;
private ListView list;
private VBox root;
private Scene scene;
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Application.launch(args);
}
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Hello World");
root = new VBox();
scene = new Scene(root, 400, 250);
list = new ListView();
items = FXCollections.observableArrayList();
Button btn = new Button();
btn.setOnAction(new EventHandler<ActionEvent>(){
public void handle(ActionEvent event) {
FXImaging imager = new FXImaging();
imager.nodeToImage(list,root.getChildren(),new File("c:/st.png"));
}
});
for(int i = 0; i<10; i++ ) {
items.add("Item"+i+"1");
}
list.setItems(items);
root.getChildren().addAll(list,btn);
primaryStage.setScene(scene);
primaryStage.show();
}
}

Image of Node

Or if you want to make image of whole Scene then use this code:

1
imager.sceneToImage(scene,newFile("c:/st.png"));

Image of Scene

It has image like below

Thanks. for watching this blog. You can comment if you have any queries.
Have a good πŸ™‚ day.

Share this:

12 thoughts on “Save Node or Scene to Image in JavaFX 2.0”

  1. Hello! Cool works!

    But is (will) any possibility to NOT use AWT and Swing?
    As I can imagine, this layers bring additional requirements of time and memory?

  2. Narayan Gopal Maharjan

    Actually it’s just the hack for saving the Node or scene to Image format. The JavaFX team is working on this facility I think this facility will be available on coming version soon

    Thanks.

  3. Pingback: Java desktop links of the week, November 7 | Jonathan Giles

  4. Very nice one..!! Liked it a lot..!! Thank u very much use full to my project as well. Keep it up…, keep doing.

  5. Yes we can send to browser for download as well, but I think you should make your own server and port for listening to the visitor’s computer and send file there by using HTTP headers rules.