Drawing certain parts of image offset from the cor

2019-02-15 22:27发布

问题:

I'm using a sprite sheet of sorts to load in spaceships. The documentation of Graphics.drawImage() states the arguments are

boolean Graphics.drawImage(Image img,
   int dstx1, int dsty1, int dstx2, int dsty2,
   int srcx1, int srcy1, int srcx2, int srcy2,
   ImageObserver observer);

However, the documentation says that dstx1 and dsty2 are the coordinates of the top left corner, and when you use dstx2 and dsty2 to specify the area drawn, the dimensions are (dstx2- dstx1) and (dsty2 - dsty1). Unless I'm misunderstanding how the function works, It appears that this only loads portions of the image form the corner. How could one draw a part of the image that is not connected to the lefthand corner, for drawing different parts of a sprite sheet?

回答1:

public abstract boolean drawImage(Image img,
                                  int dx1,
                                  int dy1,
                                  int dx2,
                                  int dy2,
                                  int sx1,
                                  int sy1,
                                  int sx2,
                                  int sy2,
                                  ImageObserver observer)

Parameters:

  • img - the specified image to be drawn. This method does nothing if img is null.
  • dx1 - the x coordinate of the first corner of the destination rectangle.
  • dy1 - the y coordinate of the first corner of the destination rectangle.
  • dx2 - the x coordinate of the second corner of the destination rectangle.
  • dy2 - the y coordinate of the second corner of the destination rectangle.
  • sx1 - the x coordinate of the first corner of the source rectangle.
  • sy1 - the y coordinate of the first corner of the source rectangle.
  • sx2 - the x coordinate of the second corner of the source rectangle.
  • sy2 - the y coordinate of the second corner of the source rectangle.
  • observer - object to be notified as more of the image is scaled and converted.

the ds are the destination, meaning where you want the image to be drawn on your surface. The ss are the coordinates of the source image. For both, the first corner being the upper left, and the second corner being the bottom right.

So you can think of the source image as like a focus section of the image to be drawn. You can use the source coordinates to determine the rectangle region to extract.

The destination coordinates layout how/where the the source region is actually drawn. So if you just want to move the drawn image along the x axis, then you just move the dx1 and the dx2. You can actually use the coordinates to resize the drawn region, by just specifying a coordinate rectangle larger or smaller than the source rectangle

            Source Image                     Destination panel
 sx1, sy1      
    +---------------+---------+        +-----------------------------+
    |               |         |        |                             |
    | region to     |         |        | dx1, dy1                    |
    |        draw   |         |        |    +----------+             |    
    |               |         |        |    |          |             |
    +---------------+         |        |    |          |             | 
    |           sx2, sy2      |        |    +----------+             |     
    |                         |        |            dx2, dy2         |
    |                         |        |                             |
    +-------------------------+        +-----------------------------+

Here's a running example.

Disclaimer: My calculations may be a little off. Not sure if I'm capturing each every section of the image. Just whipped this up really quick.

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class NerdGirl extends JPanel {
    private static final int SPRITE_ROWS = 5;
    private static final int SPRITE_COLUMNS = 2;
    private static final int DELAY = 150;

    private int DIM_W;
    private int DIM_H;

    private int x1Src;
    private int y1Src;
    private int x2Src;
    private int y2Src;

    private BufferedImage img;

    public NerdGirl() {
        try {
            img = ImageIO.read(getClass().getResource("/resources/nerd-girl.jpg"));
        } catch (IOException ex) {
            Logger.getLogger(NerdGirl.class.getName()).log(Level.SEVERE, null, ex);
        }
        DIM_W = img.getWidth() / SPRITE_ROWS;
        DIM_H = img.getHeight() / SPRITE_COLUMNS;
        x1Src = 0;
        y1Src = 0;
        x2Src = x1Src + DIM_W;
        y2Src = y1Src + DIM_H;
        Timer timer = new Timer(DELAY, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (x1Src >= img.getWidth() - DIM_H - 5) {  // 5 to take care of precision loss
                    x1Src = 0;
                    x2Src = x1Src + DIM_W;
                    if (y1Src >= DIM_H - 5) { // 5 to take care of precision loss
                        y1Src = 0;
                        y2Src = y1Src + DIM_H;
                    } else {
                        y1Src += DIM_H;
                        y2Src = y1Src + DIM_H;
                    }

                } else {
                    x1Src += DIM_W;
                    x2Src = x1Src + DIM_W;
                }

                repaint();
            }
        });
        timer.start();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(img, 0, 0, getWidth(), getHeight(), x1Src, y1Src, x2Src, y2Src, this);
    }

    @Override
    public Dimension getPreferredSize() {
        return (img == null) ? new Dimension(300, 300) : new Dimension(DIM_W, DIM_H);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new NerdGirl());
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}