Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/372.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Java中绘制屏幕外图像时的糟糕文本_Java_Graphics2d_Antialiasing_Double Buffering - Fatal编程技术网

在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),以确保两个字符串的颜色相同。

感谢您的回复

通过提到DPI,MadProgrammer引导我找到了一个工作修复方案,我在这里提供的更多的是解决方案,而不是值得骄傲的“干净”解决方案。无论如何,它解决了这个问题

我注意到,当我的屏幕分辨率为2880x1800(视网膜显示)时,
MouseEvent
getPoint()
方法在屏幕右下角读取x=1440,y=900。然后,
JPanel
大小是屏幕分辨率的一半,尽管它覆盖了整个屏幕

由此可见,解决方案如下:

  • 首先,创建一个与屏幕分辨率匹配的屏幕外图像,而不是几十篇双缓冲文章中建议的
    JPanel.getSize()

  • 然后,应用放大变换(大于所需)绘制屏幕外图像,特别是按r=屏幕尺寸/面板尺寸比进行缩放

  • 最后,将缩小版的屏幕外图像复制回屏幕,应用缩小因子r(或缩放因子1/r)


解决方案实施分为两种方法:

  • 先前发布的初始
    paintComponent
    的简化版本
  • 随后解释了助手方法
    getDPIFactor()
ammended
paintComponent
方法如下:

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;
}