【问题标题】:BufferedImage getScaledInstance changes brightness of pictureBufferedImage getScaledInstance 改变图片的亮度
【发布时间】:2013-12-03 17:08:53
【问题描述】:

我使用这段代码将图像绘制到图形组件中。如果足够大,它应该将图像大小调整为可用的最大空间:

    // getWidth() = component width, image.getWidth() = image width
    double w = getWidth() * 1.0 / image.getWidth();
    double h = getHeight() * 1.0 / image.getHeight();
    if (w < 1 || h < 1) {
        double d = Math.min(Math.min(w, h), 1);
        g.drawImage(bi.getScaledInstance((int) (d * image.getWidth()), (int) (d * image.getHeight()), Image.SCALE_REPLICATE), 0, 0, null);
    } else {
        g.drawImage(bi, 0, 0, null);
    }

代码有效,图像正确缩放。但不幸的是,当图像被缩放时,图像的亮度也会在 Graphics 上发生变化!

有人知道这可能来自哪里吗? 我附上了屏幕的缩放(第一个)和未缩放版本。

我希望有人可以帮助我!

干杯! 塞巴斯蒂安

【问题讨论】:

    标签: java swing bufferedimage brightness


    【解决方案1】:

    这似乎是Image.getScaledInstance 的问题(也可能与灰度图像有关)。我尝试了其他几个提示,但结果相同。

    相反,我使用了自己的缩放算法(我从网上偷来的),它使用分而治之的方法,通常会产生更好的结果...

    所以,原来的在上面,左边是Image#getScaledInstance,右边是自定义缩放

    nb:这使用了我自己的一些个人库代码,所以它可能不完全适合你,但它提供了基础知识......

    import java.awt.BorderLayout;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Image;
    import java.awt.RenderingHints;
    import java.awt.Transparency;
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.io.IOException;
    import javax.imageio.ImageIO;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class ImageScaleTest {
    
        public static void main(String[] args) {
            new ImageScaleTest();
        }
    
        public ImageScaleTest() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new BorderLayout());
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public static enum RenderQuality {
    
            High,
            Medium,
            Low
        }
    
        public class TestPane extends JPanel {
    
            private BufferedImage original;
            private BufferedImage scaled2;
            private Image scaled;
    
            public TestPane() {
                try {
                    original = ImageIO.read(new File("/path/to/image"));
                    scaled = original.getScaledInstance(original.getWidth() / 2, original.getHeight() / 2, Image.SCALE_DEFAULT);
                    scaled2 = getScaledInstance(original, 0.5d, RenderQuality.High);
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(400, 600);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.drawImage(original, 0, 0, this);
                g2d.drawImage(scaled, 0, original.getHeight(), this);
                g2d.drawImage(scaled2, scaled.getWidth(this), original.getHeight(), this);
                g2d.dispose();
            }
        }
    
        public static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor, RenderQuality quality) {
    
            BufferedImage imgBuffer = null;
    
            if (quality == RenderQuality.High) {
    
    //            System.out.println("Scale high quality...");
                imgBuffer = getScaledInstance(img, dScaleFactor, RenderingHints.VALUE_INTERPOLATION_BILINEAR, true);
    
            } else if (quality == RenderQuality.Medium) {
    
                imgBuffer = getScaledInstance(img, dScaleFactor, RenderingHints.VALUE_INTERPOLATION_BILINEAR, false);
    
            } else {
    
    //            System.out.println("Scale low quality...");
                imgBuffer = getScaledInstance(img, dScaleFactor, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR, false);
    
            }
    
            return imgBuffer;
    
        }
    
        protected static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor, Object hint, boolean bHighQuality) {
    
            BufferedImage imgScale = img;
    
            int iImageWidth = (int) Math.round(img.getWidth() * dScaleFactor);
            int iImageHeight = (int) Math.round(img.getHeight() * dScaleFactor);
    
            if (dScaleFactor <= 1.0d) {
    
                imgScale = getScaledDownInstance(img, iImageWidth, iImageHeight, hint, bHighQuality);
    
            } else {
    
                imgScale = getScaledUpInstance(img, iImageWidth, iImageHeight, hint, bHighQuality);
    
            }
    
            return imgScale;
    
        }
    
        protected static BufferedImage getScaledDownInstance(BufferedImage img,
                int targetWidth,
                int targetHeight,
                Object hint,
                boolean higherQuality) {
    
            int type = (img.getTransparency() == Transparency.OPAQUE)
                    ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
    
            BufferedImage ret = (BufferedImage) img;
    
            if (targetHeight > 0 || targetWidth > 0) {
                int w, h;
                if (higherQuality) {
                    // Use multi-step technique: start with original size, then
                    // scale down in multiple passes with drawImage()
                    // until the target size is reached
                    w = img.getWidth();
                    h = img.getHeight();
                } else {
                    // Use one-step technique: scale directly from original
                    // size to target size with a single drawImage() call
                    w = targetWidth;
                    h = targetHeight;
                }
    
                do {
                    if (higherQuality && w > targetWidth) {
                        w /= 2;
                        if (w < targetWidth) {
                            w = targetWidth;
                        }
                    }
    
                    if (higherQuality && h > targetHeight) {
                        h /= 2;
                        if (h < targetHeight) {
                            h = targetHeight;
                        }
                    }
    
                    BufferedImage tmp = new BufferedImage(Math.max(w, 1), Math.max(h, 1), type);
                    Graphics2D g2 = tmp.createGraphics();
                    g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
                    g2.drawImage(ret, 0, 0, w, h, null);
                    g2.dispose();
    
                    ret = tmp;
                } while (w != targetWidth || h != targetHeight);
            } else {
                ret = new BufferedImage(1, 1, type);
            }
            return ret;
        }
    
        protected static BufferedImage getScaledUpInstance(BufferedImage img,
                int targetWidth,
                int targetHeight,
                Object hint,
                boolean higherQuality) {
    
            int type = BufferedImage.TYPE_INT_ARGB;
    
            BufferedImage ret = (BufferedImage) img;
            int w, h;
            if (higherQuality) {
                // Use multi-step technique: start with original size, then
                // scale down in multiple passes with drawImage()
                // until the target size is reached
                w = img.getWidth();
                h = img.getHeight();
            } else {
                // Use one-step technique: scale directly from original
                // size to target size with a single drawImage() call
                w = targetWidth;
                h = targetHeight;
            }
    
            do {
                if (higherQuality && w < targetWidth) {
                    w *= 2;
                    if (w > targetWidth) {
                        w = targetWidth;
                    }
                }
    
                if (higherQuality && h < targetHeight) {
                    h *= 2;
                    if (h > targetHeight) {
                        h = targetHeight;
                    }
                }
    
                BufferedImage tmp = new BufferedImage(w, h, type);
                Graphics2D g2 = tmp.createGraphics();
                g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
                g2.drawImage(ret, 0, 0, w, h, null);
                g2.dispose();
    
                ret = tmp;
                tmp = null;
            } while (w != targetWidth || h != targetHeight);
            return ret;
        }
    }
    

    五月,也想看看The Perils of Image.getScaledInstance()

    ps- 我快速搜索了一下,这似乎是 API 中的错误(或功能)

    【讨论】:

    • +1 表示危险; AffineTransformOp,概述here,是一种替代方案。
    • 谢谢!我会使用这个实现!
    猜你喜欢
    • 1970-01-01
    • 2014-02-17
    • 1970-01-01
    • 2021-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-25
    • 1970-01-01
    相关资源
    最近更新 更多