Manipulating Images with JavaFX

Exclusive offer: get 50% off this eBook here
JavaFX 1.2 Application Development Cookbook

JavaFX 1.2 Application Development Cookbook — Save 50%

Over 60 recipes to create rich Internet applications with many exciting features

$23.99    $12.00
by Vladimir Vivien | August 2010 | Cookbooks Java

One of the exciting features of JavaFX is its inherent support for multimedia. JavaFX includes support for rendering of images in multiple formats and support for playback of audio and video on all platforms where JavaFX is supported. In this article by Vladimir Vivien, author of JavaFX 1.2 Application Development Cookbook, readers learn how to display and manipulate images using the Image API.

In this article, we will cover the following topics:

  • Accessing media assets
  • Loading and displaying images with ImageView
  • Applying effects and transformations to images
  • Creating image effects with blending

(For more resources on Java, see here.)

One of the most celebrated features of JavaFX is its inherent support for media playback. As of version 1.2, JavaFX has the ability to seamlessly load images in different formats, play audio, and play video in several formats using its built-in components. To achieve platform independence and performance, the support for media playback in JavaFX is implemented as a two-tiered strategy:

  • Platform-independent APIs—the JavaFX SDK comes with a media API designed to provide a uniform set of interfaces to media functionalities. Part of the platform-independence offerings include a portable codec (On2's VP6), which will play on all platforms where JavaFX media playback is supported.
  • Platform-dependent implementations—to boost media playback performance, JavaFX also has the ability to use the native media engine supported by the underlying OS. For instance, playback on the Windows platform may be rendered by the Windows DirectShow media engine (see next recipe).

This two-part article shows you how to use the supported media rendering components, including ImageView, MediaPlayer, and MediaView. These components provide high-level APIs that let developers create applications with engaging and interactive media content.

Accessing media assets

You may have seen the use of variable __DIR__ when accessing local resources, but may not fully know about its purpose and how it works. So, what does that special variable store? In this recipe, we will explore how to use the __DIR__ special variable and other means of loading resources locally or remotely.

Getting ready

The concepts presented in this recipe are used widely throughout the JavaFX application framework when pointing to resources. In general, classes that point to a local or remote resource uses a string representation of a URL where the resource is stored. This is especially true for the ImageView and MediaPlayer classes discussed in this article.

How to do it...

This recipe shows you three ways of creating a URL to point to a local or remote resource used by a JavaFX application. The full listing of the code presented here can be found in ch05/source-code/src/UrlAccess.fx.

Using the __DIR__ pseudo-variable to access assets as packaged resources:

var resImage = "{__DIR__}image.png";

Using a direct reference to a local file:

var localImage = "file:/users/home/vladimir/javafx/ch005/source-code/src/image.png";

Using a URL to access a remote file:

var remoteImage = "http://www.flickr.com/3201/2905493571_a6db13ce1b_d.jpg"

How it works...

Loading media assets in JavaFX requires the use of a well-formatted URL that points to the location of the resources. For instance, both the Image and the Media classes (covered later in this article series) require a URL string to locate and load the resource to be rendered. The URL must be an absolute path that specifies the fully-realized scheme, device, and resource location.

The previous code snippets show the following three ways of accessing resources in JavaFX:

  • __DIR__ pseudo-variable—often, you will see the use of JavaFX's pseudo variable __DIR__, used when specifying the location of a resource. It is a special variable that stores the String value of the directory where the executing class that referenced __DIR__ is located. This is valuable, especially when the resource is embedded in the application's JAR file. At runtime, __DIR__ stores the location of the resource in the JAR file, making it accessible for reading as a stream. In the previous code, for example, the expression {__DIR__}image.png explodes as jar:file:/users/home/vladimir/javafx/ch005/source-code/dist/source-code.jar!/image.png.
  • Direct reference to local resources—when the application is deployed as a desktop application, you can specify the location of your resources using URLs that provides the absolute path to where the resources are located. In our code, we use file:/users/home/vladimir/javafx/ch005/source-code/src/image.png as the absolute fully qualified path to the image file image.png.
  • Direct reference to remote resources—finally, when loading media assets, you are able to specify the path of a fully-qualified URL to a remote resource using HTTP. As long as there are no subsequent permissions required, classes such as Image and Media are able to pull down the resource with no problem. For our code, we use a URL to a Flickr image http://www.flickr.com/3201/2905493571_a6db13ce1b_d.jpg.

There's more...

Besides __DIR__, JavaFX provides the __FILE__ pseudo variable as well. As you may well guess, __FILE__ resolves to the fully qualified path of the of the JavaFX script file that contains the __FILE__ pseudo variable. At runtime, when your application is compiled, this will be the script class that contains the __FILE__ reference.

JavaFX 1.2 Application Development Cookbook Over 60 recipes to create rich Internet applications with many exciting features
Published: August 2010
eBook Price: $23.99
Book Price: $39.99
See more
Select your format and quantity:

(For more resources on Java, see here.)

Loading and displaying images with ImageView

JavaFX provides classes, which make it easy to load and display images. This recipe takes a closer look at the mechanics provided by the Image API to load and display images in your JavaFX applications.

Getting ready

This recipe uses classes from the Image API located in the javafx.scene.image package. Using this API, you are able to configure, load, and control how your images are displayed using the classes Image and ImageView. For this recipe, we will build a simple image browser to illustrate the concepts presented here. The browser allows users to load an image by providing its URL. You will use standard JavaFX controls, such as text boxes and buttons, to build the GUI.

How to do it...

The code given next has been shortened to illustrate the essential portions involved in loading and displaying an image. You can get a full listing of the code from ch05/source-code/src/image/ImageBrowserSimpleDemo.fx.

def w = 800;
def h = 600;
var scene:Scene;
def maxW = w * 0.9;
def maxH = h * 0.9;
def imgView:ImageView = ImageView{
preserveRatio:true
fitWidth: maxW fitHeight:maxH
layoutX:(w-maxW)/2 layoutY:(h-maxH)/2
};
function loadImg(){
imgView.image = Image{
url:(scene.lookup("addr") as TextBox).text
backgroundLoading:true
placeholder:Image{url:"{__DIR__}loading.jpg"}
}
}
def addrBar = Group{
layoutX: 20
layoutY: 20
content:HBox {
nodeVPos:VPos.CENTER
spacing:7
content:[
Label{text:"Image URL:" textFill:Color.SILVER}
TextBox{id:"addr" columns:80 promptText:"http://"
action:function(){loadImg()}
}
Button{id:"btnGo" text:"Get Image"
action:function(){loadImg()}
}
]
}
}

When the variables imgView and addrBar are placed on the scene and the application is executed, you will get the results as shown in the following screenshot:

JavaFX 1.2 Application Development

The image shown in this screenshot is licensed under creative common. For additional information and licensing details, go to http://www.flickr.com/photos/motleypixel/2905493571/sizes/m/.

How it works...

Loading and displaying images in JavaFX involves two classes, Image and ImageView. While class Image is responsible for accessing and managing the binary stream of the image, ImageView, on the other hand, is of the type Node and is responsible for displaying the loaded image on the scene. The code presented in this recipe lets the user enter a URL for an image and loads the image on the screen. Let's take a closer look at the code and how it works:

  • The ImageView—the first significant item to notice is the declaration of an ImageView instance assigned to the variable imgView. This is the component that will display the image on the scene when it is fully loaded. We specify the properties fitWidth, fitHeight, and preserveRatio. These properties will cause imgView to stretch (if the image is smaller than specified) or shrink (if the image is larger than specified) while preserving the aspect ratio of the image.
  • Image URL bar—the form that captures the URL of the image to load is grouped in the Group instance variable addrBar. The form consists of a Label, a TextBox, and a Button instance. The TextBox instance has several properties set, including id="addr", which allows us to find a reference to it in the code. Both the TextBox and the Button instances have their action properties defined as a function that invokes function loadImg(). Therefore, when the TextBox has focus and the Enter key is pressed, or when the Button instance is clicked on, the image will be loaded.
  • Loading the image—the image is loaded by calling the function loadImg(). It assigns an instance of Image to imgView.image. For the Image.url property, we use the Scene.lookup(id:String) function to retrieve an instance of the TextBox using its id of addr. For images that may take a while to load, we set up the following two properties:
    • To ensure that the application does not hang while the image loads, the property backgroundLoading:Boolean is set to true. This causes the GUI to remain responsive while an image loads.
    • The property placeholder:Image is used to specify a local image to use while the remote image is loading, as shown in the previous screenshot. For example, we use the local image {__DIR__}loading.png. It gets loaded immediately and remains on the screen while the remote image loads. When the remote image is loaded, it replaces the placeholder image.

There's more...

Format support

As of version 1.2, JavaFX has inherent supports for the most popular image formats (popularity here = web-supported), which includes PNG, JPG, BMP, and GIF. If you have requirements for formats other than these, such as TIFF for instance, you will have to take matters into your own hands and use external image libraries such as Java Advanced Imaging (JAI) API (not covered here).

Asynchronous loading issues

As mentioned in the previous section, when you are loading images from locations with high latency (over the network for instance), you can use the asynchronous background-loading option for your image. This causes the image-loading operation to occur in a separate execution thread to keep your GUI responsive.

This, however, presents an issue, whereby if you want to determine the dimensions of the image (which is available only after the image is fully downloaded), it will report zero when loading asynchronously, as shown in the next segment:

def img = Image{
url:"http://someimage.com/img.png"
backgroundLoading:true
}//does not wait here, it continues to next line

println (img.width); // prints 0

This is because the image is still being downloaded on the Image thread, and the main GUI thread did not wait for completion and continues with its execution. Therefore, when we query the property width of Image, it will be zero.

Unfortunately in version 1.2, the Image class does not offer event notification functions to know when image is done loading. If your code relies on the actual size of the image to be known, you must block with asynchronous loading (by setting backgroundLoading = false) to wait for the image to download and get the size. Another way around is to specify the size of the image yourself by specifying the dimensions (see next sub-section on Image resize and aspect ratio).

Image resize and aspect ratio

Another feature supported by Image and ImageView is the automatic resizing of the image. The Image class will attempt to resize the image when a value is provided for the properties, width:Number or height:Number. ImageView will attempt to do the same when the properties fitWidth:Number and fitHeight:Number are specified. Both classes support property preserveRation:Boolean, which forces the resize operation to maintain the aspect ratio of the original image while resizing to the specified dimensions as shown next:

def imgView:ImageView = ImageView{
preserveRatio:true
fitWidth: 200
};

The previous code will resize the image to a width of 200 pixels. Because the preserveRatio property is true, the height of the image is automatically calculated. This is useful especially if you do not know the actual size of the image ahead of time (see previous section).

JavaFX 1.2 Application Development Cookbook Over 60 recipes to create rich Internet applications with many exciting features
Published: August 2010
eBook Price: $23.99
Book Price: $39.99
See more
Select your format and quantity:

(For more resources on Java, see here.)

Applying effects and transformations to images

Now that you have learned how to load images, what can you do with them? Well, since ImageView is an instance of the Node class, your loaded images can receive the same treatment you would ordinarily provide, shapes, for example. In this recipe, we are going to extend the example from the previous recipe, Loading and displaying images with ImageView, to add image manipulation functionalities.

Getting ready

In this recipe, we are going to use some concepts to extend the image browser example presented in the previous recipe. We will make use of JavaFX GUI controls and node effects.

The example presented here extends the image browser from the previous recipe to add image manipulation capabilities. The new version adds GUI controls to scale, rotate, add effects, and animate the loaded image.

How to do it...

The code snippet presented next has been abbreviated to concentrate on the more interesting aspects of the code. You can access the full code listing from ch05/source-code/src/image/ImageBrowserExtendedDemo.fx.

def w = 800;
def h = 600;
def maxW = w * 0.7;
def maxH = h * 0.7;
var scene:Scene;

def slider = Slider{min:1 max:1.5 value:1}

def imgView:ImageView = ImageView{
preserveRatio:true
fitWidth:bind if((slider.value*maxW) < w)
maxW * slider.value else w
fitHeight:bind if((slider.value*maxH) < h)
maxH * slider.value else h
};

var anim = TranslateTransition{
fromX:0 toX:w - maxW
node:imgView repeatCount:TranslateTransition.INDEFINITE
autoReverse:true
}
var rotateAngle = 0;

... //Address Bar Group and loadImg() function not shown

def footer = Group{
layoutX: 20
layoutY: h - 60
content:HBox {
spacing: 12
content:[
slider,
Button{text:"Rotate" action:function(){
rotateAngle = rotateAngle + 90;
imgView.rotate = rotateAngle;
}}

HBox{spacing:7 content:[
Button{text:"Reflection"
onMouseClicked:function(e){
imgView.effect =
if(imgView.effect == null or
or not (imgView.effect instanceof
Reflection))
Reflection{fraction:0.3 topOffset:0}
else null
}}

... // Other effects omitted
Button{text:"Sepia"
onMouseClicked:function(e){
imgView.effect = if(imgView.effect == null
or not (imgView.effect instanceof
SepiaTone)
)
SepiaTone{level:0.7}
else null
}}
Button{text:"Animate"
onMouseClicked:function(e){
if(not anim.running){
anim.play();
}else{
anim.stop();
}
}}
]}
]
}
}

When the ImageView, the Slider, and the other GUI controls are added to stage, and the application is executed, it will look like what is shown in the next screenshot. In it, you can see the reflection effect applied to the image.

JavaFX 1.2 Application Development

How it works...

In the recipe Loading and displaying images with ImageView we have seen how to use the Image API to load and display local or remote images. This recipe extends the code in that recipe to not only load the image, but also apply effects and animations to it.

As shown in the previous screenshot, this version of the image browser includes a row of GUI controls at the bottom of the screen that are used to apply different transformations and effects to the loaded image. Let's take a closer look at how the code works:

  • Scaling the image—using an instance of the Slider control you can dynamically grow or shrink the image. To do this, we bind the properties ImageView.fitWidth and ImageView.fitHeight to Slider.value. This causes the size of the image to grow or shrink dynamically, while maintaining proper image aspect ratio. The bound expression includes logic to ensure that the image does not grow excessively large when it is scaled up as shown below:

    ImageView{
    fitWidth:bind if((slider.value*maxW) < w)
    maxW * slider.value else w
    fitHeight:bind if((slider.value*maxH) < h)
    maxH * slider.value else h
    };

  • Image rotation—the Button instance with the label "Rotate" rotates the image instance by 90 degrees with each click by setting the imgView.rotate property.
  • Image effects—the next five buttons in the code apply effects reflected in their respective names. These buttons apply the Reflection, Glow, GaussianBlur, Lighting (using a PointLight effect), and SepiaTone effects to the image (only Reflection and Sepia are listed in the code). All buttons work in the same way: if the effect currently applied to the image is null or the effect is not of the desired type, then apply the desired effect, otherwise, if the effect is already being applied, turn it off. This makes the button toggle between its assigned effect.
  • Image animation—the last Button control plays the TranslateTransition instance assigned to the variable anim. The transition animation moves the image from side-to-side indefinitely until the button is pressed again to stop the animation.

Creating image effects with blending

In the previous recipe, we saw how easy it is to build an application that loads, displays, and applies effects to images. In this recipe, we are going to explore how to create new visual effects by blending two separate image sources.

Getting ready

For this recipe, you will need to be familiar with the concepts of loading and displaying images in your application using the Image API. If necessary, review the recipe Loading and displaying images with ImageView. Part of the code also uses transition animation to slide the images one on top of the other with the Transition API. Lastly, the recipe makes use of GUI controls to capture image URLs and action buttons to apply the effects.

How to do it...

The code listing given next is abbreviated to show the essential portions that drive the application. You can get the full listing of this code from ch05/source-code/src/image/ImageBlendDemo.fx.

var scene:Scene;
def w = 800; def h = 600;
def maxW = w * 0.4; def maxH = h * 0.5;

def img1 = ImageView{
translateX:10 translateY:10
preserveRatio:true
fitWidth:maxW fitHeight:maxH
}
def img2 = ImageView{
translateX:w - maxW translateY:10
preserveRatio:true
fitWidth:maxW fitHeight:maxH
}
def imgPanel = Group {content:[img1, img2]}

def anim = Timeline {
keyFrames: [
KeyFrame{time:1s
values: [
img1.translateX => (w - img1.fitWidth)/2
]
}
KeyFrame{time:1s
values: [
img2.translateX => (w - img2.fitWidth)/2
]
}
]
}
// fn to load img
function loadImg(view:ImageView,url:String){
view.effect = null;
view.image = Image{
backgroundLoading:true
url:url
}
}
// controls bottom of screen
def toggleGrp = ToggleGroup{}
def controls = Group{
layoutY: h - 200
content:[
VBox{width:w spacing:12
hpos:HPos.CENTER nodeHPos:HPos.CENTER content:[
TextBox{id:"addr1" columns:60 promptText:"http://"
action:function(){
loadImg(img1,
(scene.lookup("addr1") as TextBox).text)
}}

TextBox{id:"addr2" columns:60 promptText:"http://"
action:function(){
loadImg(img2,
(scene.lookup("addr2") as TextBox).text)
}}
HBox{
content:[
RadioButton{text:"ADD"
toggleGroup:toggleGrp selected:true
}
... // other blending modes omitted
RadioButton{text:"LIGHTEN"
toggleGroup:toggleGrp
}
]
}
HBox{
content:[
RadioButton{text:"MULTIPLY"
toggleGroup:toggleGrp
}
... //other blending modes omitted
RadioButton{text:"SRC_OVER"
toggleGroup:toggleGrp
}
]
}
Button{
text:"Blend Images"
font:Font.font("Sans Serif",
FontWeight.BOLD, 18)
effect:DropShadow{offsetX:3 offsetY:3}
onMouseClicked:function(e){
def mode = toggleGrp.selectedButton.text;
imgPanel.blendMode = BlendMode.valueOf(mode);
anim.rate = 1.0;
anim.playFromStart();
}

onMouseReleased:function(e){
anim.rate = -1.0;
anim.play();
}
}
]}
]
}

When the Group instances imgPanel and controls are placed on the stage, and the application is executed, it produces the next screenshot. The application lets users enter the URLs of two images and select a blend mode. When the Blend Images button is pressed, the images slide to overlap each other and apply the blend effect:

JavaFX 1.2 Application Development

How it works...

The Group class (a node itself) allows the grouping of two or more nodes to be placed on the scene graph. One of the features of the Group node is its ability to apply a blending algorithm to the group's members. It applies its algorithm to all children in its content property when a blend mode is provided through the blendMode:BlendMode property.

In the previous sample code provided, we use Group instance imgPanel to apply blending effects to two images placed in the group. Let's take a closer look at how the application works:

  • The images—the first thing we do in the code is to declare two instances of ImageView, img1 and img2. To ensure that the images fit in a pre-determined dimension on the screen, we set the properties fitWidth and fitHeight on the two instances. Then, we place the two images in a Group instance called imgPanel, where they will receive blending effects.
  • The image animation—to make things a little interesting, the code uses an instance of Timeline to animate the two images. The first KeyFrame instance slides img1 from the left-hand side to the middle of the screen, and the second KeyFrame instance slides img2 from the right-hand side to the middle of the screen. The two images stack up in the middle of the screen where you can see the selected blending effect applied.
  • Loading the images—when the user types the URL location of the images in the TextBox instances, with property id="addr1" and id="addr2", and presses Enter, this invokes the function loadImg(). That function loads and attaches the loaded image to instances of ImageView, img1 and img2, respectively.
  • Applying the blendGroup variable controls contains two rows of RadioButton instances (not all shown in previous code). For each instance of RadioButton, the code assigns the name of a BlendMode as its text content (that is, "ADD", "COLOR_BURN", "MULTIPLY", and so on). When the user clicks on the button titled Blend Image, it creates a BlendMode object using the text of the selected radio button, and applies it to the imgPanel Group containing the images, as shown:

    def mode = toggleGrp.selectedButton.text;
    imgPanel.blendMode = BlendMode.valueOf(mode);

    BlendMode.valueOf(:String) returns an instance of BlendMode based on a String.

There's more...

JavaFX supports a multitude of blending options. The following table shows a list of the more interesting modes:

BlendMode.ADD-adds the color value of the top image to the bottom BlendMode.DARKEN-the darker color values of the child images are displayed
BlendMode.DIFFERENCE-the darker color values are subtracted from the lighter colors BlendMode.LIGHTEN-the lighter color values of the child images are displayed
BlendMode.MULTIPLY-the color values of the child images are multiplied together BlendMode.SCREEN-the color values for the child images inverted, multiplied, and inverted again
BlendMode.OVERLAY-the color values can have the screen or multiplication mode applied to them depending on the bottom input BlendMode.COLOR_BURN-the color values of the bottom layer are divided by that of the top and then inverted

The BlendedMode class offers more blended modes, including RED, GREEN, BLUE, COLOR_DOGE, HARD_LIGHT, SOFT_LIGHT, SRC_ATOP, SRC_IN, SRC_OUT, and SRC_OVER.

Summary

In this article, we will cover the following topics:

  • Accessing media assets
  • Loading and displaying images with ImageView
  • Applying effects and transformations to images
  • Creating image effects with blending

In the next article we will Playback Audio with Video and Create a Media Playback Component Using JavaFX.


Further resources on this subject:


About the Author :


Vladimir Vivien

Vladimir Vivien is a software engineer living in the United States. Past and current experiences include development in Java and .Net for industries including publishing, financial, and healthcare where he worked with a number of varied technologies including user-facing GUI frontends and backend mid-tiers. Vladimir enjoys taking part in open source projects and has contributed JmxBuilder to the Groovy project and is an author of other projects such as JmxLogger. Beside JavaFX, he has a wide range of technology interests including Java, OSGi, Scala, and anything else that runs on the JVM.

Books From Packt


NetBeans Platform 6.9 Developer's Guide
NetBeans Platform 6.9 Developer's Guide

MooTools 1.2 Beginner's Guide
MooTools 1.2 Beginner's Guide

YUI 2.8: Learning the Library
YUI 2.8: Learning the Library

Learning Ext JS 3.0
Learning Ext JS 3.0

Java EE 6 with GlassFish 3 Application Server
Java EE 6 with GlassFish 3 Application Server

Tomcat 6 Developer's Guide
Tomcat 6 Developer's Guide

Spring Persistence with Hibernate
Spring Persistence with Hibernate

EJB 3.0 Database Persistence with Oracle Fusion Middleware 11g
EJB 3.0 Database Persistence with Oracle Fusion Middleware 11g


No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
5
g
1
F
N
w
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software