Как мне обрезать изображение в Java?
Я хочу обрезать изображение вручную с помощью мыши.
Предположим, что на изображении есть какой-то текст, и я хочу выделить текст на изображении, а затем для этого я хочу обрезать эту область с помощью мыши.
7 ответов
Решение, которое я нашел наиболее полезным для обрезки буферизованного изображения, использует getSubImage(x,y,w,h);
Моя процедура обрезки в итоге выглядела так:
private BufferedImage cropImage(BufferedImage src, Rectangle rect) {
BufferedImage dest = src.getSubimage(0, 0, rect.width, rect.height);
return dest;
}
Есть две потенциально серьезные проблемы с основным ответом на этот вопрос. Во-первых, согласно документам:
public BufferedImage getSubimage (int x, int y, int w, int h)
Возвращает вложенный образ, определенный указанной прямоугольной областью. Возвращенный BufferedImage использует тот же массив данных, что и исходное изображение.
По сути, это означает, что результат от getSubimage действует как указатель, который указывает на подраздел исходного изображения.
Почему это важно? Что ж, если вы планируете редактировать подизображение по какой-либо причине, изменения также будут происходить с исходным изображением. Например, я столкнулся с этой проблемой, когда я использовал уменьшенное изображение в отдельном окне, чтобы увеличить исходное изображение. (вроде как увеличительное стекло). Я сделал возможным инвертировать цвета, чтобы легче видеть некоторые детали, но область, которая была "увеличена", также инвертировалась в исходном изображении! Таким образом, была небольшая часть исходного изображения, которая имела инвертированные цвета, в то время как остальная часть оставалась нормальной. Во многих случаях это не имеет значения, но если вы хотите отредактировать изображение или просто хотите получить копию обрезанного раздела, вы можете рассмотреть метод.
Что подводит нас ко второй проблеме. К счастью, это не такая большая проблема, как первая. getSubImage использует тот же массив данных, что и исходное изображение. Это означает, что все исходное изображение все еще сохраняется в памяти. Предполагая, что при "обрезании" изображения вам действительно нужно изображение меньшего размера, вам нужно будет перерисовать его как новое изображение, а не просто получить субизображение.
Попробуй это:
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
Эта техника сама даст вам обрезанное изображение, которое вы ищете, без ссылки на исходное изображение. Это сохранит целостность исходного изображения, а также сэкономит вам память на хранение большего изображения. (Если вы сделаете дамп исходного изображения позже)
Это метод, который будет работать:
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;
}
Конечно, вы должны сделать свой собственный 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
}
Я не проверял это. Может быть, есть некоторые ошибки (я не уверен во всем импорте).
Вы можете поставить crop(img, rect)
метод в этом классе. Надеюсь это поможет.
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;
}
}
На этот вопрос недостаточно информации, чтобы ответить. Общее решение (в зависимости от вашей структуры GUI): добавьте обработчик событий мыши, который будет ловить щелчки и движения мыши. Это даст вам ваши (х, у) координаты. Затем используйте эти координаты, чтобы обрезать ваше изображение.
Вам нужно прочитать о Java Image API и API, связанном с мышью, возможно, где-то под java.awt.event package
,
Для начала вы должны иметь возможность загружать и отображать изображение на экране, может быть, вы будете использовать JPanel
,
Затем оттуда вы попытаетесь реализовать интерфейс слушателя движения мыши и другие связанные интерфейсы. Может быть, вы будете привязаны к mouseDragged
метод...
Для mousedragged
действие, вы получите координату прямоугольника путем перетаскивания...
Затем из этих координат вы получите изображение с имеющегося у вас изображения, и вы как бы заново его перерисовываете....
А затем покажите обрезанное изображение... Я не знаю, сработает ли это, просто продукт моего воображения... просто мысль!
Я привожу этот пример, потому что это действительно работает для моего варианта использования.
Для метода ниже 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;
}