如何用 Graphics2D 创建的形状裁剪 BufferedImage?(Java)

How to clip a BufferedImage with a shape created with Graphics2D?(Java)

目前,我正在开发我的第一个 Java 应用程序,用户可以使用它浏览照片、剪切照片和旋转照片。我在裁剪图像时遇到问题。我想要实现的是:

目前我有几个问题:

  1. 我的图像集中在 JLabel 上,它又被添加到 JPanel,最后一个被添加到 JFrame,所以现在,当我想在 JLable 上方添加一个矩形时(因此它位于图片上)它是不可见的,只能直接添加到 JPanel 上。
  2. 我用 paintComponent 画了一个图像,但不知道如何移动和拉伸它并重新绘制矩形。

下面是我的代码部分(我希望)能更准确地描述我的问题:

public class GraphicalUserInterface {


static JPanel background;
static JLabel labelIcon;

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            new GraphicalUserInterface().go();
        }
    });
}


public void go() {
    buildGui();
}

public void buildGui() {

    frame = new JFrame("PicMove");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    BorderLayout layout = new BorderLayout();
    background = new JPanel(layout);

   /**To center picture on the background**/
    labelIcon = new JLabel();
    labelIcon.setHorizontalAlignment(JLabel.CENTER);
    labelIcon.setVerticalAlignment(JLabel.CENTER);

    background.add(BorderLayout.SOUTH, bottom);
    background.add(BorderLayout.PAGE_START, bar);
    background.add(BorderLayout.CENTER, labelIcon);
    background.add(BorderLayout.EAST, chatPanel);

    frame.getContentPane().add(BorderLayout.CENTER, background);
    frame.setJMenuBar(menuBar);
    frame.setVisible(true);
    frame.setSize(1300, 1200);}


static class CutImage extends JPanel implements Runnable {
    boolean clip;

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

        Graphics2D g2d = (Graphics2D) g;

        if (clip) {
            BasicStroke bs = new BasicStroke(50, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
                    10, null, 0);
            g2d.setStroke(bs);
            QuadCurve2D.Float qc = new QuadCurve2D.Float(20, 50, 100, 140, 460, 170);
            g2d.setClip(qc);
        }
        BasicStroke bs = new BasicStroke(5, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
                10, new float[]{10}, 0);
        g2d.setStroke(bs);
        g2d.drawRect(260, 50, 80, 120);

    }

    @Override
    public void run() {
        CutImage cutPanel = new CutImage();
        GraphicalUserInterface.background.add(cutPanel).repaint();
    }
}
public class PicChanges implements Runnable{

static BufferedImage newImage;
static File [] selectedFile;
static int currentImage;



FileNameExtensionFilter filter;
JFileChooser fileChooser;

public void openPic() {
    currentImage = 0;
    try {
        fileChooser = new JFileChooser();
        fileChooser.setCurrentDirectory(new java.io.File((System.getProperty("user.home"))));
        filter = new FileNameExtensionFilter("*.images", "jpg", "gif", "png");
        fileChooser.addChoosableFileFilter(filter);
        fileChooser.setMultiSelectionEnabled(true);
        int result = fileChooser.showOpenDialog(null);
        if (result == JFileChooser.OPEN_DIALOG) {
            selectedFile = fileChooser.getSelectedFiles();
            for (File image : selectedFile) {
                if ((image.isFile()) && (selectedFile.length > 0)){
                    newImage = ImageIO.read(selectedFile[0]);
                    GraphicalUserInterface.labelIcon.setIcon(new ImageIcon(
                            new ImageIcon(newImage).getImage().getScaledInstance(
                                    450, 620, Image.SCALE_DEFAULT)));
                } else if (result == JFileChooser.CANCEL_OPTION) {
                    System.out.println("No Pics Selected");
                }
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}
@Override
public void run() {
    Thread.currentThread().interrupt();
    openPic();
}

public static void nextPic() {
    currentImage++;
    try {
        newImage = ImageIO.read(selectedFile[currentImage]);
    } catch (IOException e) {
        e.printStackTrace();
        System.out.println("No pictures left");
        System.out.println("next"+currentImage);
    }
    GraphicalUserInterface.labelIcon.setIcon(new ImageIcon(
            new ImageIcon(newImage).getImage().getScaledInstance(
                    450, 620, Image.SCALE_DEFAULT)));
}

static class NextPicture implements Runnable{
    @Override
    public void run() {
        Thread.currentThread().interrupt();
        nextPic();
    }
}

public static void previousPic () {
    currentImage--;
    try {
        newImage = ImageIO.read(selectedFile[currentImage]);
    } catch (IOException e) {
        e.printStackTrace();
        System.out.println("previous "+currentImage);
    }
    GraphicalUserInterface.labelIcon.setIcon(new ImageIcon(
            new ImageIcon(newImage).getImage().getScaledInstance(
                    450, 620, Image.SCALE_DEFAULT)));
}

static class PreviousPic implements Runnable{
    @Override
    public void run() {
        Thread.currentThread().interrupt();
        previousPic();
    }
}
}

我的想法是添加 MouseListeners,但我可以将它添加到使用 Graphics2D 创建的形状吗? 我将不胜感激 :) 谢谢

在寻找这个问题的解决方案时,我又问了两个问题(也许对某人有帮助):

1)

2)

这进一步帮助我找到了出路。 我的解决方案是创建一个单独的框架,用于在其中显示复制的 BufferedImage,并在此框架上借助 MouseListeners 绘制一个矩形。这是一段代码:

public class ImageScreenShot extends JFrame implements MouseListener, MouseMotionListener {

@Override
public Dimension getPreferredSize() {
    return super.getPreferredSize();
}

private static Thread screenShotThread;

public static Thread getScreenShotThread() {
    return screenShotThread;
}

public static void setScreenShotThread(Thread screenShot) {
    ImageScreenShot.screenShotThread = screenShot;
}

private int drag_status = 0, c1, c2, c3, c4;

public int getC1() {
    return c1;
}

public int getC2() {
    return c2;
}

public int getC3() {
    return c3;
}

public int getC4() {
    return c4;
}

class AdditionalPanel extends JLabel {
    private BufferedImage img;

    public BufferedImage getImg() {
        return img;
    }

    public AdditionalPanel(BufferedImage img) {
        this.img = img;
        setPreferredSize(new Dimension(2560, 1600));
        getPreferredSize();
        setLayout(null);
    }

    @Override
    public Dimension getPreferredSize() {
        return super.getPreferredSize();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(img, 0, 0, null);
        System.out.println("Additional panel class paint method was invoked");
    }
}

public void cut() {
    AdditionalPanel apanel = new AdditionalPanel(PicChanges.getNewImage());
    JScrollPane scrollPane = new JScrollPane(apanel);
    scrollPane.addMouseMotionListener(this);
    scrollPane.addMouseListener(this);
    getContentPane().add(scrollPane, BorderLayout.CENTER);
    setPreferredSize(new Dimension(2560, 1600));
    getPreferredSize();
    pack();
    setVisible(true);
}

private void draggedScreen() throws Exception {
    int w = c1 - c3;
    int h = c2 - c4;
    w = w * -1;
    h = h * -1;
    Robot robot = new Robot();
    BufferedImage img = robot.createScreenCapture(new Rectangle(c1, c2, w, h));
    File save_path = new File("screen1.jpg");
    ImageIO.write(img, "JPG", save_path);
    GraphicalUserInterface.getLabelIcon().setIcon(new ImageIcon(new ImageIcon(img).getImage().getScaledInstance(img.getWidth(), img.getHeight(), Image.SCALE_SMOOTH)));
    JOptionPane.showConfirmDialog(this, "Would you like to save your cropped Pic?");
    System.out.println("Cropped image saved successfully.");
}

@Override
public void mouseClicked(MouseEvent arg0) {
}

@Override
public void mouseEntered(MouseEvent arg0) {
}

@Override
public void mouseExited(MouseEvent arg0) {
}

@Override
public void mousePressed(MouseEvent arg0) {
    repaint();
    c1 = arg0.getXOnScreen();
    c2 = arg0.getYOnScreen();
    System.out.println("pressed");
}

@Override
public void mouseReleased(MouseEvent arg0) {
    repaint();
    if (drag_status == 1) {
        c3 = arg0.getXOnScreen();
        c4 = arg0.getYOnScreen();
        try {
            repaint();
            draggedScreen();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

@Override
public void mouseDragged(MouseEvent arg0) {
    repaint();
    drag_status = 1;
    c3 = arg0.getXOnScreen();
    c4 = arg0.getYOnScreen();
}

@Override
public void mouseMoved(MouseEvent arg0) {
}

@Override
public void paint(Graphics g) {
    super.paint(g);
    int w = c1 - c3;
    int h = c2 - c4;
    w = w * -1;
    h = h * -1;
    if (w < 0)
        w = w * -1;
    g.setColor(Color.RED);
    g.drawRect(c1, c2, w, h);
    System.out.println("Paint component was invoked in imagescreenshot class");
}

P.S。我知道添加 JFrame 不是最好的解决方案,但我仍在寻找实现它的最佳方法,所以请不要犹豫,对我的代码发表评论并指出什么是错的或什么是好的)