如何在 Java 中裁剪图像?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2386064/
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-13 06:50:25  来源:igfitidea点击:

How do I crop an image in Java?

java

提问by Hussain

I want to crop an image manually using the mouse.
Suppose the image has some text, and I want to select some text from an image, then for that purpose I want to crop that area by using the mouse.

我想使用鼠标手动裁剪图像。
假设图像有一些文本,我想从图像中选择一些文本,然后为此我想使用鼠标裁剪该区域。

回答by ultrajohn

You need to read about Java Image API and mouse-related API, maybe somewhere under the java.awt.event package.

您需要阅读 Java Image API 和与鼠标相关的 API,可能在java.awt.event package.

For a start, you need to be able to load and display the image to the screen, maybe you'll use a JPanel.

首先,您需要能够加载图像并将其显示到屏幕上,也许您会使用JPanel.

Then from there, you will try implement a mouse motion listener interface and other related interfaces. Maybe you'll get tied on the mouseDraggedmethod...

然后,您将尝试实现鼠标运动侦听器接口和其他相关接口。也许你会被mouseDragged方法束缚......

For a mousedraggedaction, you will get the coordinate of the rectangle form by the drag...

对于一个mousedragged动作,您将通过拖动获得矩形的坐标...

Then from these coordinates, you will get the subimage from the image you have and you sort of redraw it anew....

然后从这些坐标中,您将从您拥有的图像中获得子图像,然后重新绘制它....

And then display the cropped image... I don't know if this will work, just a product of my imagination... just a thought!

然后显示裁剪后的图像...我不知道这是否行得通,只是我想象的产物...只是一个想法!

回答by Maurits Rijk

This question has not enough information to answer. A general solution (depending on your GUI framework): add a mouse event handler that will catch clicks and mouse movements. This will give you your (x, y) coordinates. Next use these coordinates to crop your image.

这个问题没有足够的信息来回答。通用解决方案(取决于您的 GUI 框架):添加一个鼠标事件处理程序来捕捉点击和鼠标移动。这将为您提供 (x, y) 坐标。接下来使用这些坐标裁剪图像。

回答by Martijn Courteaux

This is a method which will work:

这是一种有效的方法:

import java.awt.image.BufferedImage;
import java.awt.Rectangle;
import java.awt.Color;
import java.awt.Graphics;

public BufferedImage crop(BufferedImage src, Rectangle rect)
{
    BufferedImage dest = new BufferedImage(rect.getWidth(), rect.getHeight(), BufferedImage.TYPE_ARGB_PRE);
    Graphics g = dest.getGraphics();
    g.drawImage(src, 0, 0, rect.getWidth(), rect.getHeight(), rect.getX(), rect.getY(), rect.getX() + rect.getWidth(), rect.getY() + rect.getHeight(), null);
    g.dispose();
    return dest;
}

Of course you have to make your own JComponent:

当然你必须自己制作JComponent:

import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.awt.Rectangle;
import java.awt.Graphics;
import javax.swing.JComponent;

public class JImageCropComponent extends JComponent implements MouseListener, MouseMotionListener
{
   private BufferedImage img;
   private int x1, y1, x2, y2;

   public JImageCropComponent(BufferedImage img)
   {
       this.img = img;
       this.addMouseListener(this);
       this.addMouseMotionListener(this);
   }

   public void setImage(BufferedImage img)
   {
       this.img = img;
   }

   public BufferedImage getImage()
   {
       return this;
   }

   @Override
   public void paintComponent(Graphics g)
   {
      g.drawImage(img, 0, 0, this);
      if (cropping)
      {
          // Paint the area we are going to crop.
          g.setColor(Color.RED);
          g.drawRect(Math.min(x1, x2), Math.min(y1, y2), Math.max(x1, x2), Math.max(y1, y2));
      }
   }

   @Override
   public void mousePressed(MouseEvent evt)
   {
       this.x1 = evt.getX();
       this.y1 = evt.getY();
   }

   @Override
   public void mouseReleased(MouseEvent evt)
   {
       this.cropping = false;
       // Now we crop the image;
       // This is the method a wrote in the other snipped
       BufferedImage cropped = crop(new Rectangle(Math.min(x1, x2), Math.min(y1, y2), Math.max(x1, x2), Math.max(y1, y2));
       // Now you have the cropped image;
       // You have to choose what you want to do with it
       this.img = cropped;
   }

   @Override
   public void mouseDragged(MouseEvent evt)
   {
       cropping = true;
       this.x2 = evt.getX();
       this.y2 = evt.getY();
   }

   //TODO: Implement the other unused methods from Mouse(Motion)Listener

}

I didn't test it. Maybe there are some mistakes (I'm not sure about all the imports).

我没有测试它。也许有一些错误(我不确定所有的进口)。

You can put the crop(img, rect)method in this class. Hope this helps.

你可以把这个crop(img, rect)方法放在这个类中。希望这可以帮助。

回答by codehead

The solution I found most useful for cropping a buffered image uses the getSubImage(x,y,w,h);

我发现对裁剪缓冲图像最有用的解决方案使用 getSubImage(x,y,w,h);

My cropping routine ended up looking like this:

我的裁剪程序最终看起来像这样:

  private BufferedImage cropImage(BufferedImage src, Rectangle rect) {
      BufferedImage dest = src.getSubimage(0, 0, rect.width, rect.height);
      return dest; 
   }

回答by Joshua Zollinger

There are two potentially major problem with the leading answer to this question. First, as per the docs:

这个问题的主要答案有两个潜在的主要问题。首先,根据文档:

public BufferedImage getSubimage(int x, int y, int w, int h)

Returns a subimage defined by a specified rectangular region. The returned BufferedImage shares the same data array as the original image.

public BufferedImage getSubimage(int x, int y, int w, int h)

返回由指定矩形区域定义的子图像。 返回的 BufferedImage 与原始图像共享相同的数据数组。

Essentially, what this means is that result from getSubimage acts as a pointer which points at a subsection of the original image.

本质上,这意味着 getSubimage 的结果充当指向原始图像子部分的指针。

Why is this important? Well, if you are planning to edit the subimage for any reason, the edits will also happen to the original image. For example, I ran into this problem when I was using the smaller image in a separate window to zoom in on the original image. (kind of like a magnifying glass). I made it possible to invert the colors to see certain details more easily, but the area that was "zoomed" also got inverted in the original image! So there was a small section of the original image that had inverted colors while the rest of it remained normal. In many cases, this won't matter, but if you want to edit the image, or if you just want a copy of the cropped section, you might want to consider a method.

为什么这很重要?好吧,如果您出于任何原因计划编辑子图像,编辑也会发生在原始图像上。例如,当我在单独的窗口中使用较小的图像放大原始图像时遇到了这个问题。(有点像放大镜)。我可以反转颜色以更容易地看到某些细节,但是“放大”的区域在原始图像中也被反转了!因此,原始图像的一小部分颜色反转,而其余部分保持正常。在许多情况下,这无关紧要,但如果您想编辑图像,或者如果您只想要裁剪部分的副本,您可能需要考虑一种方法。

Which brings us to the second problem. Fortunately, it is not as big a problem as the first. getSubImage shares the same data array as the original image. That means that the entire original image is still stored in memory. Assuming that by "crop" the image you actually want a smaller image, you will need to redraw it as a new image rather than just get the subimage.

这就引出了第二个问题。幸运的是,它不像第一个问题那么大。getSubImage 与原始图像共享相同的数据数组。这意味着整个原始图像仍然存储在内存中。假设通过“裁剪”图像您实际上想要一个较小的图像,您将需要将其重新绘制为新图像,而不仅仅是获取子图像。

Try this:

尝试这个:

BufferedImage img = image.getSubimage(startX, startY, endX, endY); //fill in the corners of the desired crop location here
BufferedImage copyOfImage = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics g = copyOfImage.createGraphics();
g.drawImage(img, 0, 0, null);
return copyOfImage; //or use it however you want

This technique will give you the cropped image you are looking for by itself, without the link back to the original image. This will preserve the integrity of the original image as well as save you the memory overhead of storing the larger image. (If you do dump the original image later)

此技术将为您提供您正在寻找的裁剪图像,而无需返回原始图像的链接。这将保持原始图像的完整性,并为您节省存储较大图像的内存开销。(如果您稍后转储原始图像)

回答by Pankaj Mandale

File fileToWrite = new File(filePath, "url");

BufferedImage bufferedImage = cropImage(fileToWrite, x, y, w, h);

private BufferedImage cropImage(File filePath, int x, int y, int w, int h){

    try {
        BufferedImage originalImgage = ImageIO.read(filePath);

        BufferedImage subImgage = originalImgage.getSubimage(x, y, w, h);



        return subImgage;
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }
}

回答by edubriguenti

I'm giving this example because this actually work for my use case.

我给出这个例子是因为这实际上适用于我的用例。

I was trying to use the AWS Rekognition API. The API returns a BoundingBox object:

我试图使用AWS Rekognition API。API 返回一个 BoundingBox 对象:

BoundingBox boundingBox = faceDetail.getBoundingBox();

The code below uses it to crop the image:

下面的代码使用它来裁剪图像:

import com.amazonaws.services.rekognition.model.BoundingBox;

private BufferedImage cropImage(BufferedImage image, BoundingBox box) {
        Rectangle goal = new Rectangle(Math.round(box.getLeft()* image.getWidth()),Math.round(box.getTop()* image.getHeight()),Math.round(box.getWidth() * image.getWidth()), Math.round(box.getHeight() * image.getHeight()));

        Rectangle clip = goal.intersection(new Rectangle(image.getWidth(), image.getHeight()));

        BufferedImage clippedImg = image.getSubimage(clip.x, clip.y , clip.width, clip.height);

        return clippedImg;
    }