视网膜显示器上的摆动和位图

我有一个可以在OS X上运行的Java桌面应用程序。

现在新的MacBook Pro有一个视网膜显示器,我担心:它如何在Swing上工作?

当Java应用程序同时使用Swing组件和一些位图图形(如自定义图标/ ImageIcon)时怎么样?

是否应自动调整所有桌面Java应用程序的大小(例如,将每个像素增加四倍),或者我是否需要创建两个版本的图标集(例如,一个具有24×24图标,另一个具有96×96图标)并以某种方式确定应用程序在视网膜显示器上运行?

使用IconLoader库。 它支持HiDPI图像http://bulenkov.com/iconloader/它还提供了一种使用HiDPI图像的方法(绘图等)

在Apple的Java 6上,您可以提供同一图像的多个版本。 根据屏幕(视网膜或非视网膜),拾取和绘制一个或另一个图像。

但是,这些图像必须以特殊方式加载:

Toolkit.getDefaultToolkit().getImage("NSImage://your_image_name_without_extension"); 

例如,如果您的(常规分辨率)图像被调用:“scissor.png”,则必须创建一个高分辨率版本“scissor@2x.png”(遵循Apple命名约定 )并将两个图像放在Resources目录中您的应用包(是的,您需要捆绑您的应用 )。 然后打电话:

 Image img = Toolkit.getDefaultToolkit().getImage("NSImage://scissor"); 

您可以在按钮中使用生成的图像,它将以神奇的正确分辨率绘制。

你可以使用另外两个“技巧”:

  1. 在绘制图像之前,在Graphics2D对象上使用(0.5,0.5)的AffineTransform。 另请参阅此java-dev消息
  2. 使用此hack以编程方式创建映像的高dpi版本

第一个“技巧”(0.5缩放)现在也适用于Oracle的Java 7/8。 即如果您将具有0.5缩放的图像直接绘制到组件的Graphics对象,它将在Retina显示器上以高分辨率渲染(并且还具有其原始大小的一半)。

我可以确认在Oracle Java 1.8上缩放图像。 我无法让NSImage破解java 1.7或1.8。 我认为这只适用于Mac的Java 6 …

除非别人有更好的解决方案,否则我的工作如下:

创建两组图标。 如果您有一个48pixel宽的图标,则创建一个48px @normal DPI ,另一个为96px使用2x DPI 。 将2xDPI图像重命名为@2x.png以符合Apple命名标准。

Subclass ImageIcon并将其称为RetinaIcon或其他。 您可以按如下方式测试Retina显示屏:

 public static boolean isRetina() { boolean isRetina = false; GraphicsDevice graphicsDevice = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); try { Field field = graphicsDevice.getClass().getDeclaredField("scale"); if (field != null) { field.setAccessible(true); Object scale = field.get(graphicsDevice); if(scale instanceof Integer && ((Integer) scale).intValue() == 2) { isRetina = true; } } } catch (Exception e) { e.printStackTrace(); } return isRetina; } 

确保@OverrideImageIcon类的宽度和高度,如下所示:

 @Override public int getIconWidth() { if(isRetina()) { return super.getIconWidth()/2; } return super.getIconWidth(); } @Override public int getIconHeight() { if(isRetina()) { return super.getIconHeight()/2; } return super.getIconHeight(); } 

对视网膜屏幕进行测试并覆盖自定义宽度/高度方法后,您可以按如下方式自定义painIcon方法:

 @Override 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); if(isRetina()) { g2d.scale(0.5, 0.5); } else { } g2d.drawImage(image, 0, 0, observer); g2d.scale(1, 1); g2d.dispose(); } 

我不知道这将如何适用于多个屏幕 – 有没有其他人可以帮助解决这个问题?

希望这段代码无论如何都有帮助!

杰森巴拉克劳。

以下是使用上述缩放的示例: RetinaIcon位于左侧。 ImageIcon在右边

这是一个解决方案,当苹果菜单中使用图标时也可以使用。 图标会自动变灰。 所以我实现了一个密集绘制的DenseIcon类:

 public synchronized void paintIcon(Component c, Graphics g, int x, int y) { if(getImageObserver() == null) { g.drawImage(getImage0(), x, y, getIconWidth(), getIconHeight(), c); } else { g.drawImage(getImage0(), x, y, getIconWidth(), getIconHeight(), getImageObserver()); } } 

如何勾解灰色我还没弄明白。 因此,作为kludge,我们返回一个低分辨率图像,以便菜单可以进行修改:

 public Image getImage() { Image image = getImage0().getScaledInstance( getIconWidth(), getIconHeight(), Image.SCALE_SMOOTH); ImageIcon icon = new ImageIcon(image, getDescription()); return icon.getImage(); } 

你可以在gist上找到完整类的代码。 您需要使用指向两倍大小的图像的URL来实例化图标类。 适用于2K显示器。

这就是我的视网膜macbook ’12上图标的样子:

在此处输入图像描述

在IntelliJ IDEA 11(摇摆应用程序)的左侧图标和右侧的IDEA 12中声称被视线化 。 正如您所看到的,自动resize的图标(左侧)看起来非常难看。

据我所知,他们就像Chrome团队的成员一样 ,通过提供双倍大小的图标来实现。