快速缩放图像,并确保它实际缩放

时间:2013-04-20 15:53:38

标签: java swing scale bufferedimage graphics2d

我正在尝试按以下方式缩放截图:

robot.createScreenCapture(SCREEN_RECT);

我试图将其降低到600X400的图像并适合600X400的JFrame 我的程序正在使用摇摆工作者从每张图片或帧中创建视频。帧的延迟为每个200ms。被告知重新缩放时的图像只显示原始尺寸的原始图像。有谁知道如何解决这个问题,还是我应该放弃调整大小?

@SuppressWarnings("serial")
public class temporaryShit extends JPanel 
{
    private static final int width = 600;
    private static final int height = 400;
    private JLabel displayedLabel = new JLabel();

    public temporaryShit() 
    {
        setLayout(new BorderLayout());
        add(displayedLabel);
        try {
            MySwingWorker mySwingWorker = new MySwingWorker();
            mySwingWorker.execute();
        } catch (AWTException e) {
        }
    }

    public void setLabelIcon(Icon icon) {
        displayedLabel.setIcon(icon);
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(width, height);
    }

    private class MySwingWorker extends SwingWorker<Void, Icon> 
    {
        private final Rectangle SCREEN_RECT = new Rectangle(0, 0, width, height);
        private long delay = 200;
        private Robot robot = null;

        public MySwingWorker() throws AWTException 
        {
            robot = new Robot();
        }

        @Override
        protected Void doInBackground() throws Exception 
        {
            Timer utilTimer = new Timer();
            TimerTask task = new TimerTask() 
            {
                @Override
                public void run() 
                {
                    BufferedImage capturedImage = captureScreen();
                    publish(new ImageIcon(capturedImage));
                }
            };
            utilTimer.scheduleAtFixedRate(task, delay, delay);
            return null;
        }

        @Override
        protected void process(List<Icon> chunks) 
        {
            for (Icon icon : chunks) 
            {
                setLabelIcon(icon);
            }
        }

        private BufferedImage captureScreen() 
        {
            BufferedImage img = robot.createScreenCapture(SCREEN_RECT);
            return createResizedImage(img, width, height);
        }

        public BufferedImage createResizedImage(Image original, int width, int height) 
        {
            BufferedImage scaledBI = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g = scaledBI.createGraphics();
            g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g.drawImage(original, 0, 0, width, height, null);
            g.dispose();
            return scaledBI;
        }
    }

    private static void createAndShowGui() 
    {
        temporaryShit mainPanel = new temporaryShit();

        JFrame frame = new JFrame("SwingWorker Eg");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String[] args) 
    {
        SwingUtilities.invokeLater(new Runnable() 
        {
            public void run() 
            {
                createAndShowGui();
            }
        });
    }
}

2 个答案:

答案 0 :(得分:2)

您已经拥有指定大小的新图片 - scaled,您可以将其用于渲染。

这是一个简单的例子:

enter image description here

import java.awt.Image;
import java.awt.image.BufferedImage;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;

class TestBrightness {
    public static void main(String args[]) {
        try {
            URL imageUrl = new URL(
                    "http://duke.kenai.com/comfyChair/ComfyChairRadSmall.jpg");

            BufferedImage ioImage = ImageIO.read(imageUrl);

            JPanel panel = new JPanel();
            Image scaledImg = ioImage.getScaledInstance(ioImage.getWidth() / 2, 
                    ioImage.getHeight() / 2, Image.SCALE_SMOOTH);

            panel.add(new JLabel(new ImageIcon(ioImage)));
            panel.add(new JLabel(new ImageIcon(scaledImg)));

            JOptionPane.showMessageDialog(null, panel, "100% vs 50%",
                    JOptionPane.INFORMATION_MESSAGE);

        } catch (Exception e) {
            JOptionPane.showMessageDialog(null, e.getMessage(), "Failure",
                    JOptionPane.ERROR_MESSAGE);
            e.printStackTrace();
        }
    }
}

作为旁注,有许多方法可以缩放图像,Image.getScaledInstance()可能不是最好的。您可能有兴趣查看The Perils of Image.getScaledInstance()了解Image.getScaledInstance()

的一些详细信息

编辑:问题更新

上次问题更新删除了有关getScaledInstance的所有详细信息,并使此回答无效。 getScaledInstance是一种非常慢的方法,它也是异步的。尝试使用此方法获取已调整大小的图像:

public static BufferedImage createResizedImage(Image original, int width,
        int height) {
    BufferedImage scaledBI = new BufferedImage(width, height,
            BufferedImage.TYPE_INT_ARGB);
    Graphics2D g = scaledBI.createGraphics();
    g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
            RenderingHints.VALUE_INTERPOLATION_BILINEAR);
    g.drawImage(original, 0, 0, width, height, null);
    g.dispose();
    return scaledBI;
}

您可能希望更改渲染提示以获得更好的质量。

要获得更好,更完整的图像缩放器,请查看 Filthy Rich Clients 一书中的getFasterScaledInstance()

编辑:上传代码和SwingWorker的最后一次更新

SwingWorker的实施不正确。 doInBackground()时间表java.Utils.Timer。此计时器处理所有更新,而实际的SwingWorker工作线程结束。计时器的所有更新都不会在事件调度线程上触发。在EDT上分配ImageIcon可能不安全。并且肯定更新UI是不安全的,即不在EDT上调用setLabelIcon()。有关详细信息,请参阅Concurrency in Swing教程。

您可以在while中添加Thread.sleep循环和doInBackground()并删除计时器。或者,Swing计时器可能更适合这种情况。这是一个例子:

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;

public class DemoRobotPanel extends JPanel{
    private static final long serialVersionUID = 1L;

    private Image image;
    private Robot robot;
    private Rectangle CAPTURE_RECT;
    private int TIMER_DELAY = 1000;
    private int desiredWidth = 600;
    private int desiredHeight = 400;

    public DemoRobotPanel() {
        CAPTURE_RECT = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());

        try {
            robot = new Robot();

            ActionListener taskPerformer = new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    try {
                        BufferedImage img = robot.createScreenCapture(CAPTURE_RECT);
                        setImage(img);
                    } catch (HeadlessException e) {
                        e.printStackTrace();
                    }
                }
            };

            Timer timer = new Timer(TIMER_DELAY, taskPerformer);
            timer.start();

        } catch (AWTException ex) {
            // TODO Auto-generated catch block
            ex.printStackTrace();
        }
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(desiredWidth, desiredHeight);
    }

    public void setImage(Image image) {
        this.image = image;
        repaint();
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (image != null)
            g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
    }

    private static void createAndShowGui()  {
        final DemoRobotPanel panel = new DemoRobotPanel();
        JFrame frame = new JFrame("Demo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(panel);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGui();
            }
        });
    }
}

答案 1 :(得分:0)

试试这个:


    public BufferedImage resize(BufferedImage bufferedImage, int resizeWidth, int resizeHeight) {
        // Create new (blank) image of required (scaled) size
        BufferedImage scaledImage = new BufferedImage(resizeWidth, resizeHeight, BufferedImage.TYPE_INT_ARGB);
        // Paint scaled version of image to new image
        Graphics2D graphics2D = scaledImage.createGraphics();
        graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        graphics2D.drawImage(bufferedImage, 0, 0, resizeWidth, resizeHeight, null);
        graphics2D.dispose();
        return scaledImage;
    }

您可能想尝试不同的RenderingHints。