7

我有一个 10000x10000BufferedImage并且我只想将它的一部分绘制到 a Canvas,有没有办法使用 args 来做到这一点,例如:

x, y, width, height?

例如,drawImage(img, x, y, width, height) 将从 (x, y) 开始并以 (width, height) 作为尺寸的图像绘制一个矩形?

编辑:

我将重新提出这个问题:

我有一个 10000x10000 的图像,我只想在屏幕上显示它的一部分,只是用 x 和 y 偏移它的问题是,这仍然会导致延迟,因为整个图像正在被渲染,只是大部分在画布上。我怎样才能基本上使它呈现整个图像,但我可以滚动它而不会导致画布滞后?

4

3 回答 3

19

我有一个 10000x10000 BufferedImage 并且我希望只将它的一部分绘制到画布上,有没有办法使用 args 来做到这一点,例如:

  1. 不要在 java 中使用画布进行自定义绘画。使用JComponentorJPanel代替。它有一个很好的功能paintComponent(Graphics g),覆盖它并在里面绘制你的图像g.drawImage(x, y, width, height, observer)

  2. Swing 图形必须Graphics.clipRect(int x, int y, int width, int height)在绘制图像之前绑定要绘制的区域矩形。

编辑(针对您编辑的问题):

第一种方法是使用BufferedImage..getSubimage(x, y, width, height)获取具有指定矩形区域的子图像。它更快。

    BufferedImage img = ImageIO.read(new File("file")); 
    img = img.getSubimage(50, 50, 500, 500); // 500 x 500

此功能将为您提供使用rectangle(x, y, width, height)您指定的原始图像裁剪的新图像。使用返回的图像在您的组件上绘图。

教程资源: 裁剪绘图区域


演示:演示使用动画剪辑图像:

在此处输入图像描述

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.*;
import java.util.logging.*;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.Timer;

class MyCanvas extends JPanel implements ActionListener
{
  public BufferedImage buffImg;
  public Rectangle rectangle;
  Random random;
  long lastTimeChanged;
  int dirX = 1, dirY = 1;
  volatile static boolean imageLoading = true; 
    public MyCanvas() {
        random = new Random();
        rectangle = new Rectangle(50, 50, 250, 250);
        lastTimeChanged = System.currentTimeMillis();
        setBackground(Color.WHITE);
    }


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

        if(imageLoading)
        {
            showWaitForLoading(g);
            return;
        }

        g.clipRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
        g.drawImage(buffImg, 0, 0, getWidth(), getHeight(), this);

    }


    public void showWaitForLoading(Graphics g)
    {
        Graphics2D g2d = (Graphics2D)g.create();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setColor(Color.DARK_GRAY);
        g2d.fillRoundRect(getWidth()/2-100, getHeight()/2-15, 200, 30, 30, 30);
        g2d.setColor(Color.WHITE);
        g2d.drawString("Loading image...", getWidth()/2 - 45, getHeight()/2 + 3 );
        g2d.dispose();
    }

    @Override
    public void actionPerformed(ActionEvent e) {

        long endTime = System.currentTimeMillis();
        if(endTime - lastTimeChanged > 500)
        {
            dirX = random.nextInt(2) == 0 ? -1 : 1;
            dirY = random.nextInt(2) == 0 ? -1 : 1;
            lastTimeChanged = endTime;
        }

        if(rectangle.x < 0)dirX = 1;
        else if(rectangle.x + rectangle.width > getWidth())dirX = -1;

        if(rectangle.y < 0)dirY = 1;
        else if(rectangle.y + rectangle.height > getHeight())dirY = -1;

        rectangle.x = rectangle.x + dirX * 10;
        rectangle.y = rectangle.y + dirY * 10;;

        repaint();
    }

}
public class CustomPainting {


    public static void main(String[] args) throws IOException {

        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
               final MyCanvas canvas = new MyCanvas();
               JFrame frame = new JFrame();
              frame.setSize(new Dimension(500, 500));
              frame.add(canvas);
              frame.setVisible(true);
              frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

              Timer timer = new Timer(200, canvas);
              timer.start();
              new Thread()
              {
                  public void run()
                  {
                      try {
                          canvas.buffImg = ImageIO.read(new URL("http://images6.fanpop.com/image/photos/33400000/Cute-Panda-beautiful-pictures-33434826-500-500.jpg"));
                          MyCanvas.imageLoading = false;
                      } catch (IOException ex) {
                          Logger.getLogger(CustomPainting.class.getName()).log(Level.SEVERE, null, ex);
                      }
                  }
              }.start();
            }
        });
    }
}
于 2013-10-26T00:00:40.180 回答
0

就在这里:drawImage(Image img, int x, int y, int width, int height, ImageObserver observer)

于 2013-10-25T23:53:59.357 回答
0

您可以使用 Graphics.drawImage 缩放或绘制图像的一部分,如另一个答案所述,并且根据 Java 文档,BufferedImage 不需要 ImageObserver 参数,因此您可以传递 null。

http://docs.oracle.com/javase/7/docs/api/java/awt/Graphics.html

但是,我的选择是图像的剪切绘图区域。这是您可以尝试的示例:

Graphics2D g = BufferedImage.getGraphics;
g.setClip(x, y, width, height);
g.drawImage(sx, sy, x - sx, y - sy, null );
于 2013-10-26T00:22:34.507 回答