FOLLOW ME Twitter Facebook Вконтакте LinkedIn RSS Feed

Retina support in Oracle JDK 1.7.0_40 and above

Category: Java
Jun 23, 2013
Konstantin Bulenkov

Hi everyone!

A few days ago I installed Oracle JDK (version 1.7.0_40) built especially for early access purposes. So, it’s not the final release. The build contains tons of bug fixes and backports from JDK 8 for AWT/Swing and that was the main point why I started to play with it. As you might have heard, Retina support was one of the major issues in all 1.7.* releases. I’d say there was no Retina support before the build 1.7.0_40. I’m going to show you some differences of Retina support in Apple and Oracle JDKs.

1. isRetina() method

That’s funny, but there is no public API for it in Oracle JDK 7. Here is how we (IntelliJ IDEA team) do it under Apple JDK:

class IsRetina {
  public static final boolean isRetina = isRetina();

  private static boolean isRetina() {
    try {
      final boolean[] isRetina = new boolean[1];
      new apple.awt.CImage.HiDPIScaledImage(1,1,BufferedImage.TYPE_INT_ARGB) {
        public void drawIntoImage(BufferedImage image, float v) {
          isRetina[0] = v > 1;
      return isRetina[0];
    } catch (Throwable e) { 
      return false;

and to avoid ClassNotFoundException we call IsRetina if and only if we are on Mac OS X.

public class UIUtil {
  public static boolean isRetina() {
    if (SystemInfo.isJavaVersionAtLeast("1.6.0_33") && SystemInfo.isAppleJvm) {
      return IsRetina.isRetina;
    return false; 

These are the links to and
What to do under Oracle JDK? I spent some time debugging IntelliJ and found a solution. The main idea is that different platforms have different implementations of java.awt.GraphicsDevice abstract class. On Mac OS X it’s apple.awt.CGraphicsDevice and it contains what we need – the scale factor.

public static boolean isRetina() {
  //other OS and JVM specific checks...
  if (SystemInfo.isJavaVersionAtLeast("1.7.0_40") && SystemInfo.isOracleJvm) {
    GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
    final GraphicsDevice device = env.getDefaultScreenDevice();

    try {
      Field field = device.getClass().getDeclaredField("scale");

      if (field != null) {
        Object scale = field.get(device);

        if (scale instanceof Integer && ((Integer)scale).intValue() == 2) {
          return true;
    } catch (Exception ignore) {}
  return false;

2. Using retina quality images

If you don’t use double sized images in your java application they will be automatically resized on Retina. Here is an example (no retina icons at left and retina quality at right)
How to avoid your application looking so bad on Retina devices? This is one of possible solutions:
2.1 To avoid automatic resizing on retina devices you should provide two images for every icon: regular and double sized. For example, 16×16 and 32×32 for Retina. According Apple’s guidelines it’s better to name them say “myicon.png” and “myicon@2x.png” (with “@2x” at the end of double sized ones).

2.2 Handle image loading from resources and image painting. Write a simple class IconLoader with a static method getIcon(String path).

public static Icon getIcon(URL url) {
  if (isRetina()) {
    url = add2xAtTheEndOfPath(url);
    return new RetinaIcon(Toolkit.getDefaultToolkit().createImage(url));

  return new ImageIcon(Toolkit.getDefaultToolkit().createImage(url));

private static final class RetinaIcon extends ImageIcon {

  public RetinaIcon(final Image image) {

  public synchronized void paintIcon(Component c, Graphics g, int x, int y) {
    ImageObserver observer = getImageObserver();

    if (observer == null) {
      observer = c;

    Image image = getImage();
    int width = image.getWidth(observer);
    int height = image.getHeight(observer);
    final Graphics2D g2d = (Graphics2D)g.create(x, y, width, height);

    g2d.scale(0.5, 0.5);
    g2d.drawImage(image, 0, 0, observer);
    g2d.scale(1, 1);

3. Custom painting using images as a buffer

When you have a component that requires difficult custom painting it’s better and cheaper to cache it once and then do paint a cached image. This pattern is mainly used when component repainting involves difficult model calculations and takes time on every repaint.
To understand the problem deeply I’ll give you an example. Let’s consider we have a QR-Code generator component that is a combination of JTextArea and a custom drawing component which paintComponent() method takes text from the text area, builds a data model, and paints the result.
QR-code generator
The paint() method here can take some time depending on model building complexity. Anyway, the paint() method will be called every time we activate/deactivate Window, or when we move mouse over it, etc. It could be called hundreds of times with the same data for model generation. So, why don’t just cache it and clear the cache on every text change?

private Image myCache;

public void paintComponent(Graphics g) {
  if (myCache == null) {
    myCache = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2d = myCache.createGraphics();
    oldPaintComponent(g2d); //how paintComponent() worked before
  g.drawImage(myCache, 0, 0, null);

//called from listeners of the text area
public void clearCache() {
  myCache = null;

What’s the problem with Retina here? Right! Images get twice bigger automatically.

Oracle JDK 1.7.0_40ea:

Custom painting with Oracle JDK

Apple JDK 1.6.0_51:

Custom painting with Apple JDK

Apple JDK contains a special class apple.awt.CImage.HiDPIScaledImage to avoid situations like this.

public class AppleHiDPIScaledImage {
  public static BufferedImage create(int width, int height, int imageType) {
    return new CImage.HiDPIScaledImage(width, height, imageType) {
      protected void drawIntoImage(BufferedImage image, float scale) {

You can draw text, lines, shapes, etc into this image (technically speaking into its Graphics object) and everything will be OK.

Unfortunately, Oracle JDK doesn’t have such utility classes for Retina devices and I’m get stuck trying to find a simple solution here. I’ve played with double sized BufferedImage. No luck. Any ideas?

Update: I finally found a way to do it by implementing Graphics2D interface and using a special HiDPIScaledImage object. You can look at the sources here Look for classes: HiDPIScaledGraphics, JBHiDPIScaledImage, RetinaImage, and UIUtil.


  • Thank you for the very informative article!

  • Today, I tried build 40 and somehow text still looks blurry, I was wondering if High Resolution Capable .plist was needed as in Apple version, but still not working, any clues?

    • Hello Manuel, it sounds weird. Have you tried to run your java app with java -jar ? This should be in your plist file:

  • How can I get the Intellij EAP13 to use the Oracle 1.7 JDK on my machine?
    After upgrading to Mavericks I no longer have the Java 6 installed.

    But if I use the idea executable I get an error:

    frj@frj-mbp-3:/Applications/IntelliJ IDEA 13 $ Contents/MacOS/idea
    No Java runtime present, requesting install.

    I have tried editing JVMVersion in Info.plist but that did not change anything:

    Any tips will be much appreciated – otherwise I will have to install the Apple JDK 6 just for Intellij

    • Check that JDK is installed correctly

      localhost:~ kb$ /usr/libexec/java_home -v 1.7
      localhost:~ kb$
      • My Oracle JDK 1.7u45 was working ok, and /usr/libexec/java_home -v1.7 returned a working path to it. But Intellij did not try and use this version – even with the Info.plist containing JVMVersion 1.7*.

        Before I saw your reply I ended up installing Apples JDK6 – my boss was getting impatient with me :-/
        Apple JDK 6 installation made it work again.

        About the same time I wrote to you I had also asked the question in the EAP support forum – – I got a reply from one of your supporters redirecting me to:
        Dated 23rd of October stating that Apple JDK6 is in fact needed to launch Intellij.

        When I have time later today I will attempt uninstalling the JDK6 and trying your Info.plist.

        I diff’ed it with mine and the only difference (apart from version numbers) is the VMOptions section.
        In mine I have


        In yours you don’t have the agent lib argument at all – but you have a setting I do not have:

        I’m guessing it is only the agentlib part I need to strip from my plist to test if jdk 1.7 can be used?

        • Well, you don’t need It just makes some idea developers actions available. And you don’t need the agent too. We use it to let users make CPU/memory snapshots from toolbar.

    • Btw, I’m on Mavericks now and everything works fine. I have not reinstalled my JDKs. Try to use my Info.plist

  • It is somewhat difficult to remove Apple JDK 6 once it has been installed. So I’m afraid that I cannot test how the behaviour is on a system without the Apple JDK.

    But I can confirm that Idea is in fact using my Oracle JDK 1.7 when I have JVMOptions 1.7* in the Info.plist (I did not need to remove the -agentlib part from it).

    But before I installed the Apple JDK 6 – I was unable to launch Intellij at all.

    So maybe it is just the binary that is ‘hard-coded’ to use the Apple JDK and once it is launched, reads the Info.plist configuration and uses the Oracle JDK 1.7 for launching Intellij.

    • I have a fresh installation of OS X Mavericks + Java 7u45 (Apple’s Java SE 6 is NOT installed) and I can confirm, that IntelliJ IDEA cannot launch (throwing: No Java runtime present, requesting install.).
      Changing the Info.plist’s entry to 1.7* doesn’t work either.
      So IntelliJ IDEA must be relying on some Apple’s Java 6 components…

      • Thanks, we’ve fixed it in the final release of IntelliJ IDEA 13. We’re going to announce it tomorrow or the day after tomorrow.

  • Hi, thanks for your post, I am using HiDpi 3200*1800 windows machine, IntelliJ is not supporting HiDpi in 13.1.4 … I tried everything… it is not working … What will be your solution?

    • I’m working on some solution right now. At the moment there is no any.

      • That would be great to have IntelliJ works nice in Windows or Linux

      • Hi Konstantin,

        I am currently working on a MBP running Linux Mint 17. It has a Retina display, but even if I set the


        option in idea.vmoptions (or idea64.vmoptions), it has no effect. Icons are very small. I could work around it for the editor by increasing the font size, but it would be nice to have an option in the settings to enable usage of hdpi icons (or better, enable hidpi support without relying on detection). I was very surprised since support for HiDPI devices in Linux was actually announced here:


  • Hi Konstantin,

    I’m using my Retina MBP with an ultrawide 29″ LCD attached to it over HDMI at my workplace. Idea (both 13 and 14EA) indeed looks somewhat better on Retina display when running with JDK 1.7 or 1.8. However, it looks much worse on my primary workplace LCD display comparing to JDK 1.6. I believe it’s not just an JDK glitch, since a number of other apps doesn’t make any difference.

    Here’s a sample of jdk 1.6 rendering: and here’s a sample of jdk 1.8 one:

    I’d much appreciate for any hint on how could I fix it.

    (just to be clear — I’m pretty much happy with Idea running with jdk 1.6 even on retina display, and the only reason I started looking into JDK 1.8 was a plugin requiring that).

    Thank you!

    • Alexey, Oracle JRE 1.7 and above uses OpenGL to render text. And it doesn’t support subpixel anti-aliasing. Only Apple JRE does. We will fix this problem soon by creating our own custom JRE.

      • Is there a roadmap for the fix? Because i think it would help a lot if people knew when the release of the fix is planned, since it is needed by more and more users.
        Thank you in advance!

  • Just an update as this note is highly ranked in Google search… Retina support is much improved in JDK 1.8. You can draw images at full resolution on a Retina display by drawing them at half size, either by specifying width/2 and height/2 to drawImage or by using drawRenderedImage with a scale(.5,.5) transform. The only need to access a platform class is to get the scale factor, as your isRetina() method demonstrates.

    • Hi Alan, are there some improvements/APIs in 1.8 to work fine on both Retina and non-Retina displays? For example, Mac Book Pro with Retina connected to a standard monitor?

      • As far as I know, only statically prepared pairs of images (@2x) are handled automatically on both kinds of displays, and only using certain methods. For example, Toolkit.getImage() works but Toolkit.createImage() does not. I have no idea why. The feature is not documented.

        For other kinds of image display, the application must decide whether the image should be displayed magnified or at native resolution and apply the appropriate scaling as I described. In some cases, the best solution might be to use a smaller component when displaying at native resolution. In your scenario, the application would need to determine whether the window is on a Retina or non-Retina display. There is no API for determining that. Your method of using reflection to examine the graphics device presumably still works in 1.8, but I have not tried it.

        As far as I know, there is no direct support for updating the layout of a window if the window is moved from one kind of display to the other. I suppose one could write an event listener to do this when the window is moved.

  • I guess I should add that if you are displaying large images in small components, the right thing will happen automatically.

  • How can I use these with SWT-Buttons?

  • I think you need to check if the device is a retina device on every invocation of paintIcon(…); in a multi-monitor scenario, by the time you are rendering, the display could be different from the display that was active when you called isRetina()…

    Here’s my modification to your RetinaIcon approach, Konstantin (whose formatting is probably going to be mutilated in this comment field…)

    import javax.swing.*;
    import java.awt.*;
    import java.awt.image.ColorModel;
    import java.lang.reflect.Field;

    final class RetinaIcon extends ImageIcon {

    private final ImageIcon twoTimesImageIcon;

    public RetinaIcon(final Image standardImage, Image twoTimesImage) {
    this.twoTimesImageIcon = new ImageIcon(twoTimesImage);

    private static boolean isRetina(Component c) {
    GraphicsDevice device = c.getGraphicsConfiguration().getDevice();

    try {
    Field field = device.getClass().getDeclaredField(“scale”);

    if (field == null) {
    return false;

    Object scale = field.get(device);

    return scale instanceof Integer && (Integer) scale == 2;
    } catch (Exception ignore) {
    return false;

    public synchronized void paintIcon(Component c, Graphics g, int x, int y) {
    boolean retina = c != null && isRetina(c);
    if (!retina) {
    super.paintIcon(c, g, x, y);

    Image image = getImage();
    int width = image.getWidth(c);
    int height = image.getHeight(c);
    final Graphics2D g2d = (Graphics2D) g.create(x, y, width, height);

    g2d.scale(0.5, 0.5);
    g2d.drawImage(twoTimesImageIcon.getImage(), 0, 0, c);
    g2d.setComposite(new Composite() {
    public CompositeContext createContext(ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints) {
    return null;
    g2d.scale(1, 1);

  • It would be great if IntelliJ supported hidpi screens on Windows too. I hoped new version 14.1 EAP has it solved, installed it (in another folder, to have both 14.0.3 and 14.1 EAP versions. Unfortunatelly the text is still blur. :-(

Leave a comment