在Java中绘制屏幕外图像时的糟糕文本
我被困在试图通过屏幕外图像双缓冲来修复文本质量上(超出了乐趣的极限)。在Java中绘制屏幕外图像时的糟糕文本,java,graphics2d,antialiasing,double-buffering,Java,Graphics2d,Antialiasing,Double Buffering,我被困在试图通过屏幕外图像双缓冲来修复文本质量上(超出了乐趣的极限)。 丑陋的字符串被绘制到屏幕外图像,然后复制到paintComponent的Graphics参数 美观的字符串直接写入paintComponent的Graphics参数,绕过屏幕外图像 图形实例(屏幕上和屏幕外)在渲染质量、抗锯齿等方面的设置相同 提前非常感谢您的智慧 非常简单的代码如下所示: public class AcceleratedPanel extends JPanel { private Dimen
- 丑陋的
被绘制到屏幕外图像,然后复制到字符串
的paintComponent
参数Graphics
- 美观的
直接写入字符串
的paintComponent
参数,绕过屏幕外图像Graphics
图形
实例(屏幕上和屏幕外)在渲染质量、抗锯齿等方面的设置相同
提前非常感谢您的智慧
非常简单的代码如下所示:
public class AcceleratedPanel extends JPanel {
private Dimension osd; //offscreen dimension
private BufferedImage osi; //offscreen image
private Graphics osg; //offscreen graphic
public AcceleratedPanel() {
super();
}
@Override
public final void paintComponent(Graphics g) {
super.paintComponent(g);
// --------------------------------------
//OffScreen painting
Graphics2D osg2D = getOffscreenGraphics();
setupGraphics(osg2D);
osg2D.drawString("Offscreen painting", 10, 20);
//Dump offscreen buffer to screen
g.drawImage(osi, 0, 0, this);
// --------------------------------------
// OnScreen painting
Graphics2D gg = (Graphics2D)g;
setupGraphics(gg);
gg.drawString("Direct painting", 10, 35);
}
/*
To make sure same settings are used in different Graphics instances,
a unique setup procedure is used.
*/
private void setupGraphics(Graphics2D g) {
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
}
private Graphics2D getOffscreenGraphics() {
//Graphics Acceleration
Dimension currentDimension = getSize();
if (osi == null || !currentDimension.equals(osd)) {
osi = (BufferedImage)createImage(currentDimension.width, currentDimension.height);
osg = osi.createGraphics();
osd = currentDimension;
}
return (Graphics2D) osg;
}
} //End of mistery
您没有使用相同的颜色绘制两个字符串。屏幕外图形的默认颜色为rgb(0,0,0)(即纯黑色),而Swing将图形对象的颜色设置为外观的默认颜色,对于我来说,在Windows 7上,使用默认主题时,该颜色为rgb(51,51,51)或深灰色
尝试放置
g.setColor(Color.BLACK)在setupGraphics方法中进行编码>,以确保两个字符串的颜色相同。感谢您的回复
通过提到DPI,MadProgrammer引导我找到了一个工作修复方案,我在这里提供的更多的是解决方案,而不是值得骄傲的“干净”解决方案。无论如何,它解决了这个问题
我注意到,当我的屏幕分辨率为2880x1800(视网膜显示)时,MouseEvent
的getPoint()
方法在屏幕右下角读取x=1440,y=900。然后,JPanel
大小是屏幕分辨率的一半,尽管它覆盖了整个屏幕
由此可见,解决方案如下:
- 首先,创建一个与屏幕分辨率匹配的屏幕外图像,而不是几十篇双缓冲文章中建议的
JPanel.getSize()
- 然后,应用放大变换(大于所需)绘制屏幕外图像,特别是按r=屏幕尺寸/面板尺寸比进行缩放
- 最后,将缩小版的屏幕外图像复制回屏幕,应用缩小因子r(或缩放因子1/r)
解决方案实施分为两种方法:
- 先前发布的初始
paintComponent
的简化版本
- 随后解释了助手方法
getDPIFactor()
ammendedpaintComponent
方法如下:
public final void paintComponent(Graphics g) {
super.paintComponent(g);
double dpiFactor = getDPIFactor();
// --------------------------------------
//OffScreen painting
Graphics2D osg2D = getOffscreenGraphics();
setupGraphics(osg2D);
//Paint stuff bigger than needed
osg2D.setTransform(AffineTransform.getScaleInstance(dpiFactor, dpiFactor));
//Custom painting
performPainting(osg2D);
//Shrink offscreen buffer to screen.
((Graphics2D)g).drawImage(
osi,
AffineTransform.getScaleInstance(1.0/dpiFactor, 1.0/dpiFactor),
this);
// --------------------------------------
// OnScreen painting
Graphics2D gg = (Graphics2D)g;
setupGraphics(gg);
gg.drawString("Direct painting", 10, 35);
}
要完成任务,必须获得屏幕分辨率
调用Toolkit.getDefaultToolkit().getScreenResolution()
无法解决问题,因为它返回覆盖整个屏幕的JPanel
的大小。如上所述,该数字与物理点的实际屏幕大小不匹配
获取此数据的方法由Bosch中士在年批准。
我已经修改了他的代码来实现拼图的最后一部分,getDPIFactor()
这段代码解决了Mac Retina显示器的问题,但我对其他任何地方都不感到惊讶,因为CGraphicsDevice
明确提到了GraphicsDevice
的专有实现
我没有其他HDPI硬件可以用来提供更广泛的解决方案。“…超越乐趣的极限”。欢迎使用“直接”绘制方法。由于屏幕设备配置了图形
上下文,因此“直接”绘制方法受益匪浅-它可能代表更高的DPI,与此相反,您的缓冲图像
可能在72-92(?)DPI之间运行-不幸的是,上次我检查时(那是一段时间以前),没有简单的方法可以获得屏幕设备的DPI(最近可能发生了变化),因此您可能会花一些时间“猜测”制作buffereImage的最佳大小
/*
* Adapted from Sarge Bosch post in StackOverflow.
* https://stackoverflow.com/questions/40399643/how-to-find-real-display-density-dpi-from-java-code
*/
private Double getDPIFactor() {
GraphicsDevice defaultScreenDevice =
GraphicsEnvironment.getLocalGraphicsEnvironment()
.getDefaultScreenDevice();
// on OS X, it would be CGraphicsDevice
if (defaultScreenDevice instanceof CGraphicsDevice) {
CGraphicsDevice device = (CGraphicsDevice) defaultScreenDevice;
// this is the missing correction factor.
// It's equal to 2 on HiDPI a.k.a. Retina displays
int scaleFactor = device.getScaleFactor();
// now we can compute the real DPI of the screen
return scaleFactor * (device.getXResolution() + device.getYResolution()) / 2
/ Toolkit.getDefaultToolkit().getScreenResolution();
} else
return 1.0;
}