OpenJDK在4K高缩放Windows11环境下文本渲染质量优化求助
解决OpenJDK在高DPI显示器下Bitmap文本模糊问题
在Windows 11搭配4K显示器并设置175%缩放的环境中,Java 8能正常渲染清晰的Bitmap文本,但OpenJDK 11、22等版本会出现像素化模糊,可通过以下方案优化:
一、补充文本渲染相关的RenderingHints
仅开启基础抗锯齿不足以适配高DPI,需添加针对性的文本渲染提示:
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
VALUE_TEXT_ANTIALIAS_LCD_HRGB:针对LCD显示器优化文本抗锯齿,比普通抗锯齿更适配高DPI场景VALUE_FRACTIONALMETRICS_ON:启用分数度量,避免文本布局时的像素强制对齐导致模糊
二、创建适配高DPI的BufferedImage
固定尺寸创建Bitmap会忽略系统缩放比例,改用屏幕GraphicsConfiguration生成适配实际像素的Bitmap:
// 替换原BufferedImage创建逻辑 GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); float scale = Toolkit.getDefaultToolkit().getScreenResolution() / 96.0f; int scaledWidth = (int) Math.round(600 * scale); int scaledHeight = (int) Math.round(100 * scale); image = gc.createCompatibleImage(scaledWidth, scaledHeight, Transparency.TRANSLUCENT);
绘制文本时同步按缩放比例调整字体大小和坐标:
g2d.setFont(new Font("Times New Roman", Font.PLAIN, (int) Math.round(50 * scale))); g2d.drawString(text, (int) Math.round(10 * scale), (int) Math.round(50 * scale));
最后在paintComponent中按原始逻辑尺寸绘制缩放后的Bitmap:
@Override protected void paintComponent(Graphics g) { super.paintComponent(g); g.drawImage(image, 0, 0, 600, 100, this); }
三、设置高DPI适配的JVM系统属性
在启动应用时添加以下参数,强制OpenJDK识别系统高DPI缩放:
-Dsun.java2d.dpiaware=true -Djdk.awt.allowPixelScale=true -Dsun.java2d.uiScale=auto
其中sun.java2d.uiScale=auto会自动适配系统缩放比例,无需手动计算缩放因子。
修改后的完整代码
package 4ktest; import javax.swing.*; import java.awt.*; import java.awt.image.BufferedImage; public class TestWindow1 extends JPanel { private BufferedImage image; private final float scale; public TestWindow1(String text) { scale = Toolkit.getDefaultToolkit().getScreenResolution() / 96.0f; GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); int scaledWidth = (int) Math.round(600 * scale); int scaledHeight = (int) Math.round(100 * scale); image = gc.createCompatibleImage(scaledWidth, scaledHeight, Transparency.TRANSLUCENT); Graphics2D g2d = image.createGraphics(); // 配置完整渲染提示 g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g2d.setColor(Color.WHITE); g2d.fillRect(0, 0, image.getWidth(), image.getHeight()); g2d.setColor(Color.BLACK); // 按缩放比例调整字体与绘制坐标 g2d.setFont(new Font("Times New Roman", Font.PLAIN, (int) Math.round(50 * scale))); g2d.drawString(text, (int) Math.round(10 * scale), (int) Math.round(50 * scale)); g2d.dispose(); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); g.drawImage(image, 0, 0, 600, 100, this); } public static void main(String[] args) { // 设置高DPI适配属性 System.setProperty("sun.java2d.dpiaware", "true"); System.setProperty("jdk.awt.allowPixelScale", "true"); System.setProperty("sun.java2d.uiScale", "auto"); SwingUtilities.invokeLater(() -> { JFrame frame = new JFrame("Text to Bitmap"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(600, 150); TestWindow1 panel = new TestWindow1("Version " + System.getProperty("java.version")); frame.add(panel); frame.setVisible(true); }); } }
内容的提问来源于stack exchange,提问作者Klaus Friese
相关产品推荐
相关产品推荐

