JavaFX Image Example
This is a JavaFX Image example. JavaFX provides the Image API that lets you load and display images, and read/write raw image pixels. All classes are in the javafx.scene.image package. The API lets you:
- Load an image in memory
- Display an image as a node in a scene graph
- Read pixels from an image
- Write pixels to an image
- Convert a node in a scene graph to an image and save it to the local file system
The following table shows an overview of the whole article:
Table Of Contents
The following examples uses Java SE 7 and JavaFX 2.2.
1. Loading and Viewing an Image
An instance of the Image
class represents an image in memory. The class supports BMP, PNG, JPEG, and GIF image formats. You can construct an image in a JavaFX
application by supplying pixels to a WritableImage instance. An ImageView is a Node. It is used to display an Image
in a scene graph. If you want to display an image in an application, you need to load the image in an Image
and display the Image
in an ImageView
.
1.1 The Code
FxImageExample1.java
import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.HBox; import javafx.stage.Stage; public class FxImageExample1 extends Application { public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage stage) { // Load an image in the background String imageUrl = "https://docs.oracle.com/javafx/javafx/images/javafx-documentation.png"; Image image = new Image(imageUrl,160,60,false,true); // Create the ImageView ImageView imageView = new ImageView(image); // Create the HBox HBox root = new HBox(); // Add Children to the HBox root.getChildren().add(imageView); // Set the padding of the HBox root.setStyle("-fx-padding: 10;"); // Set the border-style of the HBox root.setStyle("-fx-border-style: solid inside;"); // Set the border-width of the HBox root.setStyle("-fx-border-width: 2;"); // Set the border-insets of the HBox root.setStyle("-fx-border-insets: 5;"); // Set the border-radius of the HBox root.setStyle("-fx-border-radius: 5;"); // Set the border-color of the HBox root.setStyle("-fx-border-color: blue;"); // Set the size of the HBox root.setPrefSize(300, 200); // Create the Scene Scene scene = new Scene(root); // Add the scene to the Stage stage.setScene(scene); // Set the title of the Stage stage.setTitle("Displaying an Image"); // Display the Stage stage.show(); } }
1.2 Loading an Image
The following code snippet loads an image from a source, which can be specified as a String URL or an InputStream.
// Load an image in the background String imageUrl = "https://docs.oracle.com/javafx/javafx/images/javafx-documentation.png";
1.3 Specifying the Image-Loading Properties
Some constructors let you specify some image-loading properties to controls the quality of the image and the loading process:
- requestedWidth
- requestedHeight
- preserveRatio
- smooth
- backgroundLoading
The requestedWidth
and requestedHeight
properties specify the scaled width and height of the image. By default, an image is loaded in its original size. The preserveRatio
property specifies whether to preserve the aspect ratio of the image while scaling. By default, it is false. The smooth
property specifies the quality of the filtering algorithm to be used in scaling. It´s default value is also false. If it is set to true, a better quality filtering algorithm is used, which slows down the image-loading process a bit. The backgroundLoading
property specifies whether to load the image asynchronously. By default, the property is set to false and the image is loaded synchronously. The loading process starts when the Image
object is created. If this property is set to true, the image is loaded asynchronously in a background thread.
Image image = new Image(imageUrl,160,60,false,true);
1.4 Viewing an Image
An instance of the ImageView
class is used to display an image loaded in an Image
object. The ImageView
class inherits from the Node
class, which makes an ImageView
suitable to be added to a scene graph. The class contains several constructors:
- ImageView()
- ImageView(Image image)
- ImageView(String url)
The no-args constructor creates an ImageView
without an image. Use the image property to set an image. The second constructor accepts the reference of an Image
. The third constructor lets you specify the URL of the image source. Internally, it creates an Image
using the specified URL.
// Create the ImageView ImageView imageView = new ImageView(image);
1.5 The GUI
The following graphics shows an example how an Image
can be viewed in a HBox.
2. Multiple Views of an Image
An Image
loads an image in memory from its source. You can have multiple views of the same Image
. An ImageView
provides one of the views. You have an option to resize the original image while loading, displaying, or at both times. Which option you choose to resize an image depends on the requirement at hand.
- Resizing an image in an Image object resizes the image permanently in memory and all views of the image will use the resized image. Once an Image is resized, its size cannot be altered. You may want to reduce the size of an image in an Image object to save memory.
- Resizing an image in an ImageView resizes the image only for this view. You can resize the view of an image in an ImageView even after the image has been displayed.
2.1 The Code
FxImageExample2.java
import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.HBox; import javafx.stage.Stage; public class FxImageExample2 extends Application { public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage stage) { // Load an image in the background String imageUrl = "https://docs.oracle.com/javafx/javafx/images/javafx-documentation.png"; Image image = new Image(imageUrl); // Create three views of different sizes of the same image ImageView view1 = getImageView(image, 100, 50, false); ImageView view2 = getImageView(image, 100, 50, true); ImageView view3 = getImageView(image, 100, 100, true); // Create the HBox HBox root = new HBox(10); // Add Children to the HBox root.getChildren().addAll(view1, view2, view3); // Set the padding of the HBox root.setStyle("-fx-padding: 10;"); // Set the border-style of the HBox root.setStyle("-fx-border-style: solid inside;"); // Set the border-width of the HBox root.setStyle("-fx-border-width: 2;"); // Set the border-insets of the HBox root.setStyle("-fx-border-insets: 5;"); // Set the border-radius of the HBox root.setStyle("-fx-border-radius: 5;"); // Set the border-color of the HBox root.setStyle("-fx-border-color: blue;"); // Set the size of the HBox root.setPrefSize(350, 200); // Create the Scene Scene scene = new Scene(root); // Add the scene to the Stage stage.setScene(scene); // Set the title of the Stage stage.setTitle("Multiple Views of an Image"); // Display the Stage stage.show(); } private ImageView getImageView(Image image, double fitWidth, double fitHeight, boolean preserveRation) { // Create the ImageView ImageView view = new ImageView(image); // Set Properties Width, Height, Smooth and PreserveRatio view.setFitWidth(fitWidth); view.setFitHeight(fitHeight); view.setPreserveRatio(preserveRation); view.setSmooth(true); return view; } }
2.2 Specifying the Properties of an Image
We have already discussed how to resize an image in an Image
object. In this section, we will discuss resizing an image in an ImageView
. Similar to the Image
class, the ImageView
class contains the following four properties to control the resizing of view of an image.
- fitWidth
- fitHeight
- preserveRatio
- smooth
The fitWidth
and fitHeight
properties specify the resized width and height of the image, respectively. By default, they are zero, which means that the ImageView
will use the width and height of the loaded image in the Image
. The preserveRatio
property specifies whether to preserve the aspect ratio of the image while resizing. By default, it is false. The smooth
property specifies the quality of the filtering algorithm to be used in resizing. Its default value is platform dependent. If it is set to true, a better quality filtering algorithm is used.
The Method getImageView(Image image, double fitWidth, double fitHeight, boolean preserveRation)
creates an ImageView
and sets the described properties:
private ImageView getImageView(Image image, double fitWidth, double fitHeight, boolean preserveRation) { // Create the ImageView ImageView view = new ImageView(image); // Set Properties Width, Height, Smooth and PreserveRatio view.setFitWidth(fitWidth); view.setFitHeight(fitHeight); view.setPreserveRatio(preserveRation); view.setSmooth(true); return view; }
2.3 The GUI
The following Image shows the effect of the differenet properties, which are applied to one original image.
3. Reading Pixels from an Image
Images are constructed from pixels. Data for pixels in an image may be stored in different formats. A PixelFormat defines how the data for a pixel for a given format is stored. A WritablePixelFormat represents a destination format to write pixels with full pixel color information.
The PixelReader and PixelWriter interfaces define methods to read from an Image and write data to a WritableImage. Besides an Image, you can read pixels from and write pixels to any surface that contain pixels.
3.1 The Code
FxImageExample3.java
import javafx.application.Application; import javafx.geometry.Pos; import javafx.scene.Scene; import javafx.scene.control.TextArea; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.image.PixelFormat; import javafx.scene.image.PixelReader; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.stage.Stage; public class FxImageExample3 extends Application { // Create the TextArea private final TextArea textArea = new TextArea(); public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage stage) { // Settings for TextArea textArea.setMinWidth(200); textArea.setMinHeight(600); // Load an image in the background String imageUrl = "https://docs.oracle.com/javafx/javafx/images/javafx-documentation.png"; Image image = new Image(imageUrl); // Create the ImageView ImageView imageView = new ImageView(image); // Read pixels from the image this.readPixelsInfo(image); // Create the VBox VBox root = new VBox(); // Add Children to the VBox root.getChildren().addAll(imageView,textArea); root.setAlignment(Pos.TOP_CENTER); // Set the padding of the VBox root.setStyle("-fx-padding: 10;"); // Set the border-style of the VBox root.setStyle("-fx-border-style: solid inside;"); // Set the border-width of the VBox root.setStyle("-fx-border-width: 2;"); // Set the border-insets of the VBox root.setStyle("-fx-border-insets: 5;"); // Set the border-radius of the VBox root.setStyle("-fx-border-radius: 5;"); // Set the border-color of the VBox root.setStyle("-fx-border-color: blue;"); // Set the size of the VBox root.setPrefSize(200, 600); // Create the Scene Scene scene = new Scene(root); // Add the scene to the Stage stage.setScene(scene); // Set the title of the Stage stage.setTitle("Reading Pixels from an Image"); // Display the Stage stage.show(); } @SuppressWarnings("rawtypes") private void readPixelsInfo(Image image) { // Obtain the pixel reader from the image PixelReader pixelReader = image.getPixelReader(); if (pixelReader == null) { System.out.println("Connot read pixels from the image"); return; } // Get Properties from the Image int width = (int)image.getWidth(); int height = (int)image.getHeight(); double progress = image.getProgress(); double requWidth = image.getRequestedWidth(); double requHeight = image.getRequestedHeight(); PixelFormat format = pixelReader.getPixelFormat(); PixelFormat.Type formatType = format.getType(); // Write out the Properties to the TextArea this.writeInfoMessage("Image Width: " + width); this.writeInfoMessage("Image Height: " + height); this.writeInfoMessage("Progress: " + progress); this.writeInfoMessage("Requested Image Width: " + requWidth); this.writeInfoMessage("Requested Image Height: " + requHeight); this.writeInfoMessage("Pixel format type: " + formatType); // Read all pixels for(int y = 0; y < height; y++) { for(int x = 0; x < width; x++) { Color color = pixelReader.getColor(x, y); this.writeInfoMessage("Color at (" + x + ", " + y + ") = " + color); } } } // Method for Logging private void writeInfoMessage(String msg) { this.textArea.appendText(msg + "\n"); } }
3.2 Pixel Formats
The image API in JavaFX gives you access to each pixel in an image. A pixel stores information about its color (red, green, blue) and opacity (alpha). The pixel information can be stored in several formats. An instance the PixelFormat<T extends Buffer> represents the layout of data for a pixel. You need to know the pixel format when you read the pixels from an image. You need to specify the pixel format when you write pixels to an image.
In the above class, an own method was defined, which reads the information of an image and writes it into a TextArea.
@SuppressWarnings("rawtypes") private void readPixelsInfo(Image image) { // Obtain the pixel reader from the image PixelReader pixelReader = image.getPixelReader(); if (pixelReader == null) { System.out.println("Connot read pixels from the image"); return; } // Get Properties from the Image int width = (int)image.getWidth(); int height = (int)image.getHeight(); double progress = image.getProgress(); double requWidth = image.getRequestedWidth(); double requHeight = image.getRequestedHeight(); PixelFormat format = pixelReader.getPixelFormat(); PixelFormat.Type formatType = format.getType(); // Write out the Properties to the TextArea this.writeInfoMessage("Image Width: " + width); this.writeInfoMessage("Image Height: " + height); this.writeInfoMessage("Progress: " + progress); this.writeInfoMessage("Requested Image Width: " + requWidth); this.writeInfoMessage("Requested Image Height: " + requHeight); this.writeInfoMessage("Pixel format type: " + formatType); // Read all pixels for(int y = 0; y < height; y++) { for(int x = 0; x < width; x++) { Color color = pixelReader.getColor(x, y); this.writeInfoMessage("Color at (" + x + ", " + y + ") = " + color); } } }
3.3 The GUI
4. Writing Pixels to an Image
You can write pixels to an image or any surface that supports writing pixels. For example, you can write pixels to a WritableImage
and a Canvas.
4.1 The Code
FxImageExample4.java
import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.image.PixelReader; import javafx.scene.image.PixelWriter; import javafx.scene.image.WritableImage; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.scene.text.Text; import javafx.stage.Stage; public class FxImageExample4 extends Application { public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage stage) { // Load an image in the background String imageUrl = "https://docs.oracle.com/javafx/javafx/images/javafx-documentation.png"; Image image = new Image(imageUrl); // Set the Width and Height of the Image int width = (int)image.getWidth(); int height = (int)image.getHeight(); // Create three WritableImage instances // One Image will be a darker, one brighter, and one semi-transparent WritableImage darkerImage = new WritableImage(width, height); WritableImage brighterImage = new WritableImage(width, height); WritableImage semiTransparentImage = new WritableImage(width, height); // Copy source pixels to the destinations this.createImages(image, darkerImage, brighterImage, semiTransparentImage,width,height); // Create the ImageViews ImageView imageView = new ImageView(image); ImageView darkerView = new ImageView(darkerImage); ImageView brighterView = new ImageView(brighterImage); ImageView semiTransparentView = new ImageView(semiTransparentImage); // Create the VBox for the Original Image VBox originalViewBox = new VBox(); // Add ImageView to the VBox originalViewBox.getChildren().addAll(imageView, new Text("Original")); // Create the VBox for the Darker Image VBox darkerViewBox = new VBox(); // Add ImageView to the VBox darkerViewBox.getChildren().addAll(darkerView, new Text("Darker")); // Create the VBox for the Brighter Image VBox brighterViewBox = new VBox(); // Add ImageView to the VBox brighterViewBox.getChildren().addAll(brighterView, new Text("Brighter")); // Create the VBox for the Semi-Transparent Image VBox transparentViewBox = new VBox(); // Add ImageView to the VBox transparentViewBox.getChildren().addAll(semiTransparentView, new Text("Semi-Transparent")); // Create the HBox HBox root = new HBox(10); // Add VBoxes to the HBox root.getChildren().addAll(originalViewBox,darkerViewBox,brighterViewBox,transparentViewBox); // Set the padding of the HBox root.setStyle("-fx-padding: 10;"); // Set the border-style of the HBox root.setStyle("-fx-border-style: solid inside;"); // Set the border-width of the HBox root.setStyle("-fx-border-width: 2;"); // Set the border-insets of the HBox root.setStyle("-fx-border-insets: 5;"); // Set the border-radius of the HBox root.setStyle("-fx-border-radius: 5;"); // Set the border-color of the HBox root.setStyle("-fx-border-color: blue;"); // Set the size of the HBox root.setPrefSize(400, 200); // Create the Scene Scene scene = new Scene(root); // Add the scene to the Stage stage.setScene(scene); // Set the title of the Stage stage.setTitle("Writing Pixels to an Image"); // Display the Stage stage.show(); } private void createImages(Image image, WritableImage darkerImage,WritableImage brighterImage, WritableImage semiTransparentImage, int width, int height) { // Obtain the pixel reader from the image PixelReader pixelReader = image.getPixelReader(); PixelWriter darkerWriter = darkerImage.getPixelWriter(); PixelWriter brighterWriter = brighterImage.getPixelWriter(); PixelWriter semiTransparentWriter = semiTransparentImage.getPixelWriter(); // Read one pixel at a time from the source and // write it to the destinations for(int y = 0; y < height; y++) { for(int x = 0; x < width; x++) { Color color = pixelReader.getColor(x, y); // Write a darker pixel to the new image darkerWriter.setColor(x, y, color.darker()); // Write a brighter pixel to the new image brighterWriter.setColor(x, y, color.brighter()); // Write a semi-transparent pixel to the new image semiTransparentWriter.setColor(x, y, Color.color(color.getRed(), color.getGreen(),color.getBlue(), 0.50)); } } } }
An instance of the PixelWriter
interface is used to write pixels to a surface. A PixelWriter
is provided by the writable surface. For example, you can use the getPixelWriter()
method of the Canvas
and WritableImage
to obtain a PixelWriter
for them.
The following method creates different views on an image.
private void createImages(Image image, WritableImage darkerImage,WritableImage brighterImage, WritableImage semiTransparentImage, int width, int height) { // Obtain the pixel reader from the image PixelReader pixelReader = image.getPixelReader(); PixelWriter darkerWriter = darkerImage.getPixelWriter(); PixelWriter brighterWriter = brighterImage.getPixelWriter(); PixelWriter semiTransparentWriter = semiTransparentImage.getPixelWriter(); // Read one pixel at a time from the source and // write it to the destinations for(int y = 0; y < height; y++) { for(int x = 0; x < width; x++) { Color color = pixelReader.getColor(x, y); // Write a darker pixel to the new image darkerWriter.setColor(x, y, color.darker()); // Write a brighter pixel to the new image brighterWriter.setColor(x, y, color.brighter()); // Write a semi-transparent pixel to the new image semiTransparentWriter.setColor(x, y, Color.color(color.getRed(), color.getGreen(),color.getBlue(), 0.50)); } } }
Thereafter, a VBox will be craeted for each view. These VBoxes will be added to a HBox
.
// Create the VBox for the Original Image VBox originalViewBox = new VBox(); // Add ImageView to the VBox originalViewBox.getChildren().addAll(imageView, new Text("Original")); // Create the VBox for the Darker Image VBox darkerViewBox = new VBox(); // Add ImageView to the VBox darkerViewBox.getChildren().addAll(darkerView, new Text("Darker")); // Create the VBox for the Brighter Image VBox brighterViewBox = new VBox(); // Add ImageView to the VBox brighterViewBox.getChildren().addAll(brighterView, new Text("Brighter")); // Create the VBox for the Semi-Transparent Image VBox transparentViewBox = new VBox(); // Add ImageView to the VBox transparentViewBox.getChildren().addAll(semiTransparentView, new Text("Semi-Transparent")); // Create the HBox HBox root = new HBox(10); // Add VBoxes to the HBox root.getChildren().addAll(originalViewBox,darkerViewBox,brighterViewBox,transparentViewBox);
4.2 The GUI
5. Download Java Source Code
This was an example of javafx.scene.control.Image
You can download the full source code of this example here: JavaFxImageExample.zip