Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
245 views
in Technique[技术] by (71.8m points)

java - How to draw part of a large BufferedImage?

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:

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?

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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:

  1. Don't use canvas for custom painting in java. use JComponent or JPanel instead. 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.

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 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.

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...