3

I have a javafx.scene.image.Image, and I would like to resize it, e.g. scaling it by a given factor. How to do that (without converting to BufferedImage), and what are the options regarding quality and performance (such as interpolation types)?

There are several questions that look similar, but I couldn't find anybody who asked the same thing. The key point is that the input is an Image object (and scaling factor) and the desired output is another Image object.

  • What do you want to do with the image after scaling it? Typically in JavaFX you would display an `Image` in an `ImageView`, which provides the [functionality to scale the image it displays](http://docs.oracle.com/javase/8/javafx/api/javafx/scene/image/ImageView.html#fitWidthProperty) (or you can [scale the image on loading directly](http://docs.oracle.com/javase/8/javafx/api/javafx/scene/image/Image.html#Image-java.lang.String-double-double-boolean-boolean-)). You can of course always load and scale the image and then snapshot an `ImageView` containing it; would that work? – James_D Feb 24 '16 at 19:29
  • @James_D I may display it, save it to a file or use it in any other conceivable way. For example I might keep a downscaled image in memory for displaying at a later time. I guess a snapshot could work. – aditsu quit because SE is EVIL Feb 24 '16 at 19:40
  • To save it to file, you need to convert it to a buffered image anyway, so maybe conversion is the way to go. – James_D Feb 24 '16 at 19:50

2 Answers2

14

The simplest way is something like:

public Image scale(Image source, int targetWidth, int targetHeight, boolean preserveRatio) {
    ImageView imageView = new ImageView(source);
    imageView.setPreserveRatio(preserveRatio);
    imageView.setFitWidth(targetWidth);
    imageView.setFitHeight(targetHeight);
    return imageView.snapshot(null, null);
}

A minimal amount of control over the speed/smoothness of the scaling algorithm is made available via a call to imageView.setSmooth(...); with the value true using a slower algorithm with better smoothing and false using a faster algorithm with less smoothing.

James_D
  • 201,275
  • 16
  • 291
  • 322
1

Without converting it to BufferedImage you will need to implement scaling algorithm and do something like:

Image source = ...
WritableImage target = new WritableImage(targetWidth, targetHeight)

scale(target, source)

(Note that javafx.scene.image.WritableImage is extended from Image and intended for purposes of creating image from memory data.)

The scale function will read pixels from source image PixelReader and, after doing scaling operation on each individual source pixel, will write pixels into target image PixelWriter. Actual implementation will depend on selected algorithm.

In other words you will need to implement your own scaling algorithm.

Please note that this is not trivial operation as you will need to acount for upsampling (target is larger) and downsampling (target is smaller). You can find a list of image scaling algorithms on Wikipedia

One of the simplest algorithms is Nearest neighbour but it produces some artifacts.

stjepano
  • 1,052
  • 7
  • 15