Java Swing BuffereImage质量差

Java Swing BuffereImage质量差,java,swing,bufferedimage,Java,Swing,Bufferedimage,我试图在BuffereImage上创建一个图形,然后复制到JPanel上。 当我直接在JPanel上画图时,画质是好的,但当使用中间缓冲区时,画质/分辨率明显降低。 我已经从OSX的辅助功能面板中选择了缩放选项。 我正在开发MacBookPro视网膜 是否发生了某种自动缩放? BuffereImage有什么问题 下面是演示问题的代码 package com.sample.gui; import java.awt.BorderLayout; import java.awt.Color; impo

我试图在BuffereImage上创建一个图形,然后复制到JPanel上。 当我直接在JPanel上画图时,画质是好的,但当使用中间缓冲区时,画质/分辨率明显降低。 我已经从OSX的辅助功能面板中选择了缩放选项。 我正在开发MacBookPro视网膜

是否发生了某种自动缩放? BuffereImage有什么问题

下面是演示问题的代码

package com.sample.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class QualityProblem {

private static final double DOT_SIZE = 4;

public static void main(String[] args) {
    JFrame frame = new JFrame("ChartPanel demo");
    frame.setBackground(Color.WHITE);

    // JPanel draw = new DrawingOK();
    JPanel draw = new DrawingUgly();
    draw.setBackground(Color.BLACK);

    frame.getContentPane().add(draw, BorderLayout.CENTER);
    frame.setSize(new Dimension(1200, 900));
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    frame.setVisible(true);
}

private static class DrawingOK extends JPanel {

    private static final long serialVersionUID = 1L;

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        Graphics2D g2draw = (Graphics2D) g.create();
        try {
            g2draw.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2draw.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            g2draw.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);

            Ellipse2D.Double e = new Ellipse2D.Double(50, 50, DOT_SIZE, DOT_SIZE);
            g2draw.setColor(Color.YELLOW);
            g2draw.fill(e);
        } finally {
            g2draw.dispose();
        }
    }
}

private static class DrawingUgly extends JPanel {

    private static final long serialVersionUID = 1L;

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        Dimension size = getParent().getSize();
        BufferedImage image = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_RGB);

        Graphics2D ig = image.createGraphics();
        ig.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        ig.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        ig.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);

        Graphics2D g2draw = (Graphics2D) g.create();
        try {
            Ellipse2D.Double e = new Ellipse2D.Double(50, 50, DOT_SIZE, DOT_SIZE);
            ig.setColor(Color.YELLOW);
            ig.fill(e);
            g2draw.drawImage(image, 0, 0, null);
        } finally {
            ig.dispose();
            g2draw.dispose();
        }
    }
}
}
编辑: 添加了4像素点和50D都放大的图像。 丑陋的一个来源于复制到屏幕图形上的BuffereImage

我修复了您的绘图代码

这是丑陋的图形用户界面

  • 我将面板的大小移动到面板构造函数。设置帧大小包括边框。通过设置面板大小,可以获得所需的绘图区域

  • 我将黑色背景绘画移到了paintComponent方法。你不妨在一个地方画所有的画

  • 我清理了你的绘图代码。不需要复制paintComponent图形实例即可获得Graphics2D

  • 我把圆圈变大了,这样你就可以看到它的锐度了。我将原点移动到圆心,并将圆点大小变成半径

  • 这是密码

    package com.ggl.testing;
    
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.RenderingHints;
    import java.awt.geom.Ellipse2D;
    import java.awt.image.BufferedImage;
    
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;
    
    public class QualityProblem implements Runnable {
    
        private static final double DOT_SIZE = 50D;
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new QualityProblem());
        }
    
        @Override
        public void run() {
            JFrame frame = new JFrame("ChartPanel demo");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setBackground(Color.WHITE);
    
            // JPanel draw = new DrawingOK();
            JPanel draw = new DrawingUgly();
    
            frame.getContentPane().add(draw, BorderLayout.CENTER);
            frame.pack();
            frame.setVisible(true);
        }
    
        private class DrawingOK extends JPanel {
    
            private static final long serialVersionUID = 1L;
    
            public DrawingOK() {
                this.setPreferredSize(new Dimension(600, 400));
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
    
                Graphics2D g2draw = (Graphics2D) g;
    
                g2draw.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                        RenderingHints.VALUE_ANTIALIAS_ON);
                g2draw.setRenderingHint(RenderingHints.KEY_RENDERING,
                        RenderingHints.VALUE_RENDER_QUALITY);
                g2draw.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
                        RenderingHints.VALUE_STROKE_PURE);
    
                g2draw.setColor(Color.BLACK);
                g2draw.fillRect(0, 0, getWidth(), getHeight());
    
                Ellipse2D.Double e = new Ellipse2D.Double(300D - DOT_SIZE,
                        200D - DOT_SIZE, DOT_SIZE + DOT_SIZE, DOT_SIZE + DOT_SIZE);
                g2draw.setColor(Color.YELLOW);
                g2draw.fill(e);
            }
        }
    
        private class DrawingUgly extends JPanel {
    
            private static final long serialVersionUID = 1L;
    
            public DrawingUgly() {
                this.setPreferredSize(new Dimension(600, 400));
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
    
                BufferedImage image = new BufferedImage(getWidth(), getHeight(),
                        BufferedImage.TYPE_INT_RGB);
    
                Graphics2D ig = image.createGraphics();
                ig.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                        RenderingHints.VALUE_ANTIALIAS_ON);
                ig.setRenderingHint(RenderingHints.KEY_RENDERING,
                        RenderingHints.VALUE_RENDER_QUALITY);
                ig.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
                        RenderingHints.VALUE_STROKE_PURE);
    
                ig.setColor(Color.BLACK);
                ig.fillRect(0, 0, getWidth(), getHeight());
    
                Ellipse2D.Double e = new Ellipse2D.Double(300D - DOT_SIZE,
                        200D - DOT_SIZE, DOT_SIZE + DOT_SIZE, DOT_SIZE + DOT_SIZE);
                ig.setColor(Color.YELLOW);
                ig.fill(e);
                ig.dispose();
    
                g.drawImage(image, 0, 0, this);
            }
        }
    
    }
    

    这仅仅是因为在一种情况下,您在硬件支持的表面上绘制,表面显示为640x480,但渲染以2x(或显示的任何比例因子)分辨率完成。在
    buffereImage
    的情况下,您正在将图形绘制到文字640x480像素的缓冲区上。显然,情况会更糟

    我认为,对于您没有明确设置的提示,图像和面板在OS X上使用了不同的呈现提示。将此代码的文本输出复制/粘贴回问题中

    import java.awt.*;
    import java.awt.geom.Ellipse2D;
    import java.awt.image.BufferedImage;
    
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    
    public class QualityProblem {
    
        private static final double DOT_SIZE = 40;
    
        public static void main(String[] args) {
            JFrame frame = new JFrame("ChartPanel demo");
            frame.setLayout(new GridLayout(0, 1));
    
            frame.getContentPane().add(new DrawingUgly());
            frame.getContentPane().add(new DrawingOK());
            frame.setSize(new Dimension(400, 300));
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            frame.setVisible(true);
        }
    
        private static class DrawingOK extends JPanel {
    
            private static final long serialVersionUID = 1L;
    
            DrawingOK() {
                setBackground(Color.GREEN);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
    
                Graphics2D g2draw = (Graphics2D) g.create();
                System.out.println("Panel Rendering Hints:");
                printRenderingHints(g2draw);
                try {
                    g2draw.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                    g2draw.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
                    g2draw.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
    
                    Ellipse2D.Double e = new Ellipse2D.Double(50, 50, DOT_SIZE, DOT_SIZE);
                    g2draw.setColor(Color.YELLOW);
                    g2draw.fill(e);
                } finally {
                    g2draw.dispose();
                }
            }
        }
    
        private static class DrawingUgly extends JPanel {
    
            private static final long serialVersionUID = 1L;
    
            DrawingUgly() {
                setBackground(Color.RED);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
    
                Dimension size = getParent().getSize();
                BufferedImage image = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_ARGB);
    
                Graphics2D ig = image.createGraphics();
    
                System.out.println("Image Rendering Hints:");
                printRenderingHints(ig);
                ig.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                ig.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
                ig.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
    
                Graphics2D g2draw = (Graphics2D) g.create();
                try {
                    Ellipse2D.Double e = new Ellipse2D.Double(50, 50, DOT_SIZE, DOT_SIZE);
                    ig.setColor(Color.YELLOW);
                    ig.fill(e);
                    g2draw.drawImage(image, 0, 0, null);
                } finally {
                    ig.dispose();
                    g2draw.dispose();
                }
            }
        }
    
        private static void printRenderingHints(Graphics2D g) {
            RenderingHints renderingHints = g.getRenderingHints();
            RenderingHints.Key[] renderHintsKeys = {
                RenderingHints.KEY_ALPHA_INTERPOLATION,
                RenderingHints.KEY_ANTIALIASING,
                RenderingHints.KEY_COLOR_RENDERING,
                RenderingHints.KEY_DITHERING,
                RenderingHints.KEY_FRACTIONALMETRICS,
                RenderingHints.KEY_INTERPOLATION,
                RenderingHints.KEY_RENDERING,
                RenderingHints.KEY_STROKE_CONTROL,
                RenderingHints.KEY_TEXT_ANTIALIASING,
                RenderingHints.KEY_TEXT_LCD_CONTRAST
            };
            for (RenderingHints.Key key : renderHintsKeys) {
                Object o = renderingHints.get(key);
                String value = o==null ? "null" : o.toString();
                System.out.println(key + " \t" + value);
            }
        }
    }
    

    请注意,在Windows上,它会生成一个相同的值列表。

    哈拉尔德在下面的一条评论中给出了非常好的建议。BuffereImage size需要乘以2,该图像的Graphics2D必须设置为比例2,而(屏幕设备的)目标Graphics2D需要设置为比例0.5。 使用这些设置,放大时两个圆看起来完全相同。 波纹管完整,修改拉拔类

        private static class DrawingUgly extends JPanel {
    
        private static final long serialVersionUID = 1L;
    
        public DrawingUgly() {
            this.setPreferredSize(new Dimension(600, 25));
        }
    
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
    
            Graphics2D g2draw = (Graphics2D) g.create();
    
            double scale = 2;
            BufferedImage image = new BufferedImage((int) (getWidth() * scale), (int) (getHeight() * scale), BufferedImage.TYPE_INT_RGB);
    
            Graphics2D ig = image.createGraphics();
            ig.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            ig.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            ig.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
    
            ig.scale(scale, scale);
    
            ig.setColor(Color.BLACK);
            ig.fillRect(0, 0, getWidth(), getHeight());
    
            Ellipse2D.Double e = new Ellipse2D.Double(10, 10, DOT_SIZE, DOT_SIZE);
            ig.setColor(Color.YELLOW);
            ig.fill(e);
            ig.dispose();
    
            g2draw.scale(1.0d / scale, 1.0d / scale);
    
            g2draw.drawImage(image, 0, 0, this);
        }
    }
    

    我看起来一模一样。是否可以发布屏幕截图(可能放大)?从图像中获取的
    图形
    对象可能使用了与面板中使用的不同的渲染提示。请尝试创建两倍大小的
    缓冲图像(即
    size.width*2,size.height*2
    ),然后将
    ig
    的比例设置为
    2
    ,将
    g2draw
    的比例设置为
    0.5
    。谢谢haraldK!就这样!我也尝试过类似的方法,但为了找到解决办法,我不顾一切地做了一些错事。非常感谢!吉尔伯特,谢谢你的回答,但你的改变是纯粹的化妆品,放大时不能解决我的边缘不平的问题。看图片这一定是和视网膜有关的东西显示它是如何呈现的。我在这里找到了更多的信息嗨,安德鲁,这是我检查的第一件事。在我的Macbook视网膜上,您的代码也打印相同的值。这更可能与视网膜显示器的高分辨率有关。”…代码打印:…。什么?将输出编辑到问题中。我无法粘贴,太多文本
    面板渲染提示:Alpha混合插值方法键null全局抗锯齿启用键非本质性渲染模式颜色渲染质量键null抖动质量键null分数度量启用键整数文本度量模式图像插值方法键null全局渲染质量键默认渲染方法笔划规格化控制键默认笔划规格化文本特定抗锯齿启用键默认抗锯齿文本模式文本特定LCD对比度键140图像渲染提示:
    完全相同same@ivenhov:为了更好的可读性,编辑您的问题以包含这些结果。@AndrewThompson:在Mac OS X 10.9和10.10上相同,都是无视网膜显示@不能可靠地假设比例因子为2。否。但是您可以通过反射
    GraphicsEnvironment env=GraphicsEnvironment.getLocalGraphicsEnvironment()获取它;最终图形设备设备=env.getDefaultScreenDevice();Field=device.getClass().getDeclaredField(“刻度”)看起来也不是特别便携。我认为即使这样,文本也不能很好地呈现。不幸的是,在Java获得HDPI api之前,没有好的方法可以做到这一点