【问题标题】:Displaying Java BufferedImage on MacBook with Retina display does not work在配备 Retina 显示屏的 MacBook 上显示 Java BufferedImage 不起作用
【发布时间】:2013-09-13 01:13:36
【问题描述】:

我编写了一个 Java7 应用程序,该应用程序创建一个 BufferedImage,每当用户更改对图像有影响的内容时,它就会被后台线程绘制。问题是在显示图像时,正确的图像只显示几秒钟,然后显示一个不稳定的图像(大小正确),其中包含来自系统的帧缓冲区的其余部分;见下图:

它应该是这样的:

绘制线程完成后,BufferedImage 将被绘制到 JPanel 组件上,并使用 AffineTransformation 进行转换以反映一定的缩放级别。

BufferedImage 的大小由一个不依赖于 MacBook 或JFrame 分辨率的固定数字决定(通常相当高,例如 4000x2000)。绘制BufferedImage 的面板位于ScrollPane 内,该面板可根据面板的大小进行调整。每次线程绘制新版本时,BufferedImage 是被覆盖还是创建新的都没有关系。

我已经在 windows 上测试了该工具,一台不带视网膜显示屏的 MacBook 和三台带视网膜显示屏的 MacBook,在所有没有视网膜显示屏的机器上,该工具都能完美运行。有什么想法吗?

编辑:程序是这样工作的:HexaVisExplorer 类是使用项目的 NetBeans 构建的 JFrame GUI。它保留了一个ScrollPane,和一个VisualizationPanel,它是ScrollPane 的内容,并且每当用户更改对结果图像有影响的属性时,组件的ActionListener 就会调用@ 中的一个方法987654338@。在那里,一个属性被设置,一个Thread被初始化并开始,基于VisualizationPanel中设置的属性,将绘制一个新的BufferedImage。完成此操作后,新的BufferedImage 将保存到VisualizationPanel,然后将使用覆盖的paintComponent() 重新绘制,其中将使用java.awt.geom.AffineTransform 转换图像以进行有效缩放。最后,滚动窗格的视口被修改以反映新的图像大小。代码如下:

类 HexavisExplorer.java

public class HexaVisExplorer extends javax.swing.JFrame {

    private VisualizationPanel visualizationPanel;
    private javax.swing.JScrollPane jScrollPane1;

    public HexaVisExplorer() {
        //...Example where a component listener calls a method in VisualizationPanel.java to set a property
        polygonBorderCheckbox.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                visualizationPanel.setPolygonBorders(polygonBorderCheckbox.isSelected());
            }
        });
        //...
    } 
}  

VisualizationPanel,方法recalculate() 创建一个新的VisualizationThread,它使用VisualizationPanel 中的属性生成有问题的BufferedImage。当重新计算完成时,

public class VisualizationPanel extends JPanel {

   private boolean polygonBorders;
   //here be more property class variables and getter/setter for them

    public void setPolygonBorders(boolean polygonBorders) {
        this.polygonBorders = polygonBorders;
        recalculate();
        this.revalidate();
        this.repaint();
    }

    public void recalculate(){
        vt = new VisualizationThread(this);
        vt.execute();
    }

    @Override
    protected void paintComponent(Graphics g) {


        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
        dataTransformation.setToScale(transform_factor, transform_factor);
        g2d.transform(dataTransformation);
        g2d.drawImage(toDraw, 0, 0, null);
        this.setSize((int) Math.ceil(transform_factor * maxwidth), (int) Math.ceil(transform_factor * maxheight));
        this.setPreferredSize(new Dimension((int) Math.ceil(transform_factor * maxwidth), (int) Math.ceil(transform_factor * maxheight)));
        this.revalidate();
        hx.modifyVisPanelViewport(this);
    }
}

VisualizationThread 获取VisualizationPanel,读取其属性并计算新的BufferedImage based on that. When done, done()is called, which then sets the newBufferedImageto draw to theVisualizationPanel` 并重新绘制它。

public class VisualizationThread extends SwingWorker<Object, Object> {
    private VisualizationPanel vp;
    private BufferedImage toDraw;
    
    @Override
    protected Object doInBackground() throws Exception {
    // The bufferedImage  gets drawn on here.
    }

    @Override
    protected void done() {
        vp.setToDraw(toDraw);
        vp.setPreferredSize(new Dimension(toDraw.getWidth(), toDraw.getHeight()));
        vp.repaint();
        vp.revalidate();
    }
}

【问题讨论】:

  • 显示一些代码,否则我们并没有真正需要帮助的信息
  • 你在使用AffineTransformOp吗?
  • dataTransformation 是 java.awt.geom.AffineTransform,所以我没有使用 AffineTransformOp。我添加了一些代码,希望您现在可以更好地理解!
  • @jurib:使用@ 来称呼cmets 中的人;我只是偶然看到你的更新。

标签: java swing osx-mountain-lion retina-display


【解决方案1】:

看起来就像主机对等组件期望使用一种颜色模型渲染图像但遇到另一种颜色模型。对于一个明确的答案,有太多的方法会出错,但有几件事需要仔细审查:

  • 验证您的BufferedImage 具有兼容的颜色模型和空间,用于example

  • 考虑使用AffineTransformOp 进行缩放,概述here,因为它可以创建“具有正确大小和带数的目标图像”。

  • event dispatch thread 上执行done() 时,请验证您的程序的其余部分是否已正确同步,对于example

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-24
    • 2016-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多