36

According to these articles:

http://news.kynosarges.org/2015/06/29/javafx-dpi-scaling-fixed
https://twitter.com/michaelsamarin/status/729234779292483584

Java 9 should support high DPI displays (automatic DPI scaling) in Swing. I have tested it on the last version of Java 9 Early Access + on Zulu 9 and it works and looks really great.

I was unable to solve only one thing - high resolution/retina image loading.

According to articles (links) above and below it should use an Apple name convention (@2x):

image.png, image@2x.png, image@3x.png, etc.

I tested these loading methods:

Toolkit.getDefaultToolkit().getImage(getClass().getClassLoader().getResource("something/image.png"));

and

ImageIO.read(getClass().getResource("/something/image.png"));

But none of these works (the only base image was loaded and blurred).

According to this:

https://netbeans.org/bugzilla/show_bug.cgi?id=239745

The first method should be promising.

Has anyone any experiences with this (using Swing or even JavaFX)? I'm not sure if I'm doing something wrong or this feature is not implemented to the current pre-release version of Java 9 sofar.


Update:

It should be possible:

http://openjdk.java.net/jeps/263

I've also tried following naming conventions (described here):

Windows : image.scale-<dpi-value>.png (image.scale-140.png)
Linux : image.java-scale2x.png
Mac : image@2x.png and image.java-scale2x.png

However, I cannot find any working solution or official information. I don't get it - hdpi displays are common today and Java applications look like s... on them.

timiTao
  • 1,417
  • 3
  • 20
  • 34
Jolinar
  • 866
  • 8
  • 16
  • 2
    @2x probably meant to work when referenced by `url` from JavaFX style, not when using programmatic API to load the image in generic way. – Oleg Estekhin Aug 06 '16 at 17:21
  • 2
    Based on the articles referencing JavaFX, I'd say that the support is based on JavaFX only, you'll probably need to define your own methods, perhaps taking a path, name and extension – MadProgrammer Aug 06 '16 at 23:22
  • 2
    @MadProgrammer The article is about Java version 8u60, the first version with fully automatic DPI scaling for JavaFX - there is no support for this for Swing in this version. But there is in Java 9 and I would doubt they will make two name conventions (one for JavaFX and another for Swing). Moreover the third article (NetBeans) is about Swing (about a multi resolution image loading) and conventions are the same (it's for Mac, but JavaFX took it to Windows obviously) - look at this: https://netbeans.org/bugzilla/show_bug.cgi?id=239745#c5 – Jolinar Aug 07 '16 at 11:24
  • 1
    Based on everything I've read, I'm not sure ImageIO will support this directly and all of this relates to Apple's retina displays, you don't highlight if that's the hardware you're using – MadProgrammer Aug 07 '16 at 20:26
  • 2
    You might also want to provide a runnable example, an example of the images and the structure of your project for people to play with ;) – MadProgrammer Aug 07 '16 at 21:17
  • 1
    Base upon [`MultiResolutionImage`](http://download.java.net/java/jdk9/docs/api/java/awt/image/MultiResolutionImage.html), it provides access to the images, i've not seen an examples, so I'm unsure if implementations of `MultiResolutionImage` are required (or expeceted) to use the "best fit" image automatically – MadProgrammer Aug 07 '16 at 21:21
  • Have you tried using [`BaseMultiResolutionImage`](https://docs.oracle.com/javase/9/docs/api/java/awt/image/BaseMultiResolutionImage.html)? – Vince Feb 04 '18 at 17:54
  • 1
    @Vince Emigh `BaseMultiResolutionImage` with a manual (in code) filling by images works. But I would like to have the application compatible with older Java versions (ok - It would be manageable using some reflection mess, but I would like to leave this as the last resort). – Jolinar Feb 04 '18 at 21:46
  • 1
    @Jolinar I'm confused. You want the DPI support that Java 9 added to be accessible in an older version? Like, a work-around? – Vince Feb 05 '18 at 01:26
  • Also, in regards to "*I don't get it - hdpi displays are common today and Java applications look like s... on them.*" - Java does support GUI, but that doesn't mean the support is up to standards/expectation. I generally only use Java for back-end, long/continuously-running applications like servers. You may want to consider using a different toolkit or language for your presentation layer. – Vince Feb 05 '18 at 01:59
  • @Vince Emigh Yes, I want to use new feature that Java 9 offers (for users whose have it), but I don't want to disable users with older versions. The hdpi naming convention should serve exactly this purpose - you do not change a code, but only add new resources (like in Android or iOS). – Jolinar Feb 05 '18 at 08:40
  • @MadProgrammer [`AbstractMultiResolutionImage`](https://docs.oracle.com/javase/9/docs/api/index.html?java/awt/image/AbstractMultiResolutionImage.html) lists an example in the javadoc – Mark Jeronimus Jun 19 '18 at 15:14
  • 1
    @MarkJeronimus I think the problem is they want a “backwards compatible” based solution, one where they don’t need to change existing code to make it work – MadProgrammer Jun 19 '18 at 20:02
  • Good luck with that. Java 9 and up completely broke HiDPI backwards compatibility with no possible workarounds*. (even if code compiled with 8 is run on JVM 9) You either make your HiDPI code work on JVM 8 or JVM 9+ but can't for both. (*there still are open bug reports regarding this) – Mark Jeronimus Jun 21 '18 at 07:55
  • @Mark Jeronimus Yes, the only working solution for Java 8 and 9 (as far as I know) is reflection and `BaseMultiResolutionImage`. – Jolinar Jun 25 '18 at 15:30

1 Answers1

9

As part of HiDPI support, Java 9 introduced multi-resolution support via the java.awt.MultiResolutionImage interface and the java.awt.image.AbstractMultiResolutionImage et al classes. Although they're supported in Swing, there have been bugs and misunderstandings in this area.

Those don't exist in earlier Java versions, so if you want your users to be able to continue to run with earlier runtimes, you're going to have to write code to use regular Image classes when running on earlier JREs.

To use those, you do something like:

  • Start with a set of images are different resolutions:

enter image description here

  • Then create and load the MultiResolutionImage:

    List<Image> imgList = new ArrayList<Image>();
    imgList.add(ImageIO.read(new File("320px-Eagle.jpg"));
    imgList.add(ImageIO.read(new File("800px-Eagle.jpg"));
    imgList.add(ImageIO.read(new File("1024px-Eagle.jpg"));
    imgList.add(ImageIO.read(new File("1280px-Eagle.jpg"));
    imgList.add(ImageIO.read(new File("Eagle.jpg"));
    MultiResolutionImage mrImage = new BaseMultiResolutionImage(imgList.toArray(new Image[0]));
    
  • The use the mrImage object just like any other image.

There's nothing automatic about the naming convention: The image resolution is taken from the image file contents.

Bob Jacobsen
  • 1,150
  • 6
  • 9