你如何检测Java中的Retina显示?

时间:2013-12-24 23:22:06

标签: java retina-display

如何检测用户是否使用Java进行视网膜显示?我已经知道使用Toolkit.getDefaultToolkit().getDesktopProperty("apple.awt.contentScaleFactor")检测比例因子,但java不允许我将返回的值转换为int。我想知道如何将其转换为int或其他检测视网膜显示的方法。

3 个答案:

答案 0 :(得分:5)

我会以这种方式获得价值 -

public static boolean hasRetinaDisplay() {
  Object obj = Toolkit.getDefaultToolkit()
      .getDesktopProperty(
          "apple.awt.contentScaleFactor");
  if (obj instanceof Float) {
    Float f = (Float) obj;
    int scale = f.intValue();
    return (scale == 2); // 1 indicates a regular mac display.
  }
  return false;
}

答案 1 :(得分:1)

对于Java 9,这也有效:

    public static boolean isMacRetinaDisplay() {
        final GraphicsConfiguration gfxConfig = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
        final AffineTransform transform = gfxConfig.getDefaultTransform();
        return !transform.isIdentity();
    }

您也可以检查变换的比例因子,检查它是否等于2,否则回落到非视网膜。

答案 2 :(得分:0)

请注意,用户可能具有多个显示!在这种情况下,“检测视网膜显示”是什么意思?

对于大多数用途,您有兴趣将图像渲染到GUI组件上。因此,您需要检测组件处于打开状态

幸运的是,java.awt.Component有一个getGraphicsConfiguration method为我们提供了必要的信息。

但是,Java 8(和7)和Java 9需要不同的处理方式:Java 9直接通过graphics device’s default transform公开必要的信息。 Java 7和8也公开了此转换,但是即使对于Retina显示器,也始终将其设置为身份转换(即无转换)。

对于Java <9,我们需要使用反射来查询为Mac实现图形的OpenJDK类中的macOS特定字段。

下面的类对Retina显示器进行必要的检查,并适用于Java 8和Java9。Java7可能也可以进行一些微小的更改,但我没有对其进行测试。

package me.klmr.ui;

import java.awt.*;
import java.lang.reflect.Method;

public final class Device {
    private enum JavaVersion {
        V8,
        V9
    }

    private static final JavaVersion JAVA_VERSION = getJavaVersion();

    private static JavaVersion getJavaVersion() {
        final String versionString = System.getProperty("java.version");
        if (versionString.startsWith("1.8")) return JavaVersion.V8;
        if (versionString.startsWith("9.")) return JavaVersion.V9;
        throw new RuntimeException("Unsupported Java version");
    }

    public static GraphicsConfiguration getCurrentConfiguration(final Component component) {
        final GraphicsConfiguration graphicsConfiguration = component.getGraphicsConfiguration();
        if (graphicsConfiguration == null) {
            return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
        } else {
            return graphicsConfiguration;
        }
    }

    public static GraphicsDevice getCurrentDevice(final Component component) {
        final GraphicsConfiguration graphicsConfiguration = component.getGraphicsConfiguration();
        if (graphicsConfiguration == null) {
            return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
        } else {
            return graphicsConfiguration.getDevice();
        }
    }

    public static boolean isOnRetinaDisplay(final Component component) {
        switch (JAVA_VERSION) {
            case V8: return isOnRetinaDisplayJava8(component);
            case V9: return isOnRetinaDisplayJava9(component);
            default: throw new AssertionError("Unreachable");
        }
    }

    public static double getDisplayScalingFactor(final Component component) {
        switch (JAVA_VERSION) {
            case V8: return getDisplayScalingFactorJava8(component);
            case V9: return getDisplayScalingFactorJava9(component);
            default: throw new AssertionError("Unreachable");
        }
    }

    private static boolean isOnRetinaDisplayJava8(final Component component) {
        final GraphicsDevice device = getCurrentDevice(component);
        try {
            final Method getScaleFactorMethod = device.getClass().getMethod("getScaleFactor");
            final Object scale = getScaleFactorMethod.invoke(device);
            return scale instanceof Integer && ((Integer) scale).intValue() == 2;
        } catch (ReflectiveOperationException e) {
            return false;
        }
    }

    private static boolean isOnRetinaDisplayJava9(final Component component) {
        return ! getCurrentConfiguration(component).getDefaultTransform().isIdentity();
    }

    private static double getDisplayScalingFactorJava8(final Component component) {
        return isOnRetinaDisplayJava8(component) ? 2.0 : 1.0;
    }

    private static double getDisplayScalingFactorJava9(final Component component) {
        return getCurrentConfiguration(component).getDefaultTransform().getScaleX();
    }
}

实际上,将对话框从一个屏幕移动到另一个屏幕将导致组件重新呈现。如果组件的渲染代码使用上述类来找出正确的分辨率,则无论它们当前在哪个显示上,它们都将正确渲染。