如何在Java中裁剪图像?

时间:2023-02-09 14:48:49

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.

我想用鼠标手工裁剪一个图像。假设图像有一些文本,我想从图像中选择一些文本,为了实现这个目的,我想使用鼠标来裁剪这个区域。

6 个解决方案

#1


128  

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

#2


31  

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)

公共缓冲编辑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.

返回由指定矩形区域定义的子映像。返回的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)

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

#3


10  

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)方法放在这个类中。希望这个有帮助。

#4


8  

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

#5


6  

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)的坐标。接下来使用这些坐标来裁剪你的图像。

#6


2  

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

您需要阅读Java映像API和与鼠标相关的API,可能在Java .awt下的某个地方。活动方案。

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

然后,您将尝试实现一个鼠标移动侦听器接口和其他相关接口。也许你会被鼠标拖动的方法束缚住……

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

对于鼠标拖动操作,您将通过拖动获得矩形的坐标。

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!

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

#1


128  

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

#2


31  

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)

公共缓冲编辑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.

返回由指定矩形区域定义的子映像。返回的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)

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

#3


10  

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)方法放在这个类中。希望这个有帮助。

#4


8  

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

#5


6  

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)的坐标。接下来使用这些坐标来裁剪你的图像。

#6


2  

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

您需要阅读Java映像API和与鼠标相关的API,可能在Java .awt下的某个地方。活动方案。

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

然后,您将尝试实现一个鼠标移动侦听器接口和其他相关接口。也许你会被鼠标拖动的方法束缚住……

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

对于鼠标拖动操作,您将通过拖动获得矩形的坐标。

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!

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