Java 如何绘制大 BufferedImage 的一部分?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19601116/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 18:40:23  来源:igfitidea点击:

How to draw part of a large BufferedImage?

javagraphicsrenderingbufferedimage

提问by Shaun Wild

I have a 10000x10000 BufferedImageand I'm looking to draw only part of it to a Canvas, is there a way to do this using args such as:

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

x, y, width, height?

x, y, width, height?

So for example, drawImage(img, x, y, width, height) would draw a rectangle from the image starting at (x, y) and having (width, height) as the dimensions?

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

EDIT:

编辑:

I'm going to re- word this question:

我将重新表述这个问题:

I have a 10000x10000 image and I only want to display a portion of it on the screen, the problem with just offsetting it by x and y is that this still causes lag as the entire image is being rendered, just most of it off canvas. How can I basically make it so that the entire image is rendered but I can scroll around it without causing the canvas to lag?

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

采纳答案by Sage

I have a 10000x10000 BufferedImage and I'm looking to draw only part of it to a Canvas, is there a way to do this using args such as:

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

  1. Don't use canvas for custom painting in java. use JComponentor JPanelinstead. It has a nice function paintComponent(Graphics g), override it and paint your image inside with g.drawImage(x, y, width, height, observer);

  2. Swing graphics has Graphics.clipRect(int x, int y, int width, int height)to bound the area rectangle to which you wish to draw prior to drawing the image.

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

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

Edit (In response to your edited question):

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

First approach is to use BufferedImage..getSubimage(x, y, width, height)to get a sub image with specified rectangle region. It is faster.

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

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

This function will give you a new image cropped with the rectangle(x, y, width, height)of your original image you specified. Use the returned image to draw on your component.

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

Tutorial resource:Clipping the Drawing Region

教程资源:裁剪绘图区域



Demo: Demonstrating clipping Image with Animation:

演示:演示用动画剪裁图像:

enter image description here

在此处输入图片说明

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();
            }
        });
    }
}

回答by Junyoung TJ Lee

You can scale or draw a part of an image using Graphics.drawImage as mentioned another answer and according to Java documentation, ImageObserver argument is not needed for BufferedImage so you can just pass null.

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

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

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

However, my choice would be the clipping drawing region of image instead. Here is an example you can try:

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

Graphics2D g = BufferedImage.getGraphics;
g.setClip(x, y, width, height);
g.drawImage(sx, sy, x - sx, y - sy, null );