Как вы клонируете BufferedImage
У меня есть объект, в котором много буферизованных изображений, я хочу создать новый объект, копирующий все буферизованные изображения в новый объект, но эти новые изображения могут быть изменены, и я не хочу, чтобы исходные изображения объекта были изменены путем изменения новые объекты изображения.
это понятно?
Возможно ли это сделать, и может кто-нибудь предложить хороший способ сделать это, пожалуйста? Я думал о getSubImage, но где-то читал, что любые изменения в подизображении возвращаются в родительское изображение.
Я просто хочу иметь возможность получить свежую полностью отдельную копию или клон BufferedImage
10 ответов
Что-то вроде этого?
static BufferedImage deepCopy(BufferedImage bi) {
ColorModel cm = bi.getColorModel();
boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
WritableRaster raster = bi.copyData(null);
return new BufferedImage(cm, raster, isAlphaPremultiplied, null);
}
Я сделаю это:
public static BufferedImage copyImage(BufferedImage source){
BufferedImage b = new BufferedImage(source.getWidth(), source.getHeight(), source.getType());
Graphics g = b.getGraphics();
g.drawImage(source, 0, 0, null);
g.dispose();
return b;
}
Он работает довольно хорошо и прост в использовании.
Ранее упомянутая процедура не выполняется при применении к подизображениям. Вот более полное решение:
public static BufferedImage deepCopy(BufferedImage bi) {
ColorModel cm = bi.getColorModel();
boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
WritableRaster raster = bi.copyData(bi.getRaster().createCompatibleWritableRaster());
return new BufferedImage(cm, raster, isAlphaPremultiplied, null);
}
Другой способ заключается в использовании Graphics2D
класс, чтобы нарисовать изображение на новое пустое изображение. Это на самом деле не клонирует изображение, но приводит к получению копии изображения.
public static final BufferedImage clone(BufferedImage image) {
BufferedImage clone = new BufferedImage(image.getWidth(),
image.getHeight(), image.getType());
Graphics2D g2d = clone.createGraphics();
g2d.drawImage(image, 0, 0, null);
g2d.dispose();
return clone;
}
Я знаю, что этот вопрос довольно старый, но для будущих посетителей вот решение, которое я бы использовал:
Image oldImage = getImage();
Image newImage = oldImage.getScaledInstance(oldImage.getWidth(null), oldImage.getHeight(null), Image.SCALE_DEFAULT);
Пожалуйста, поправьте меня, если меняете только что полученный newImage
также влияет на исходное изображение в любом случае.
-> Javadoc для getScaledInstance
-> Javadoc для SCALE_DEFAULT (остальные константы перечислены чуть ниже этой)
Класс BufferedImage не реализует интерфейс Cloneable. Таким образом, метод клонирования не переопределен. Вот альтернатива для техники глубокого копирования: Java Совет 76: альтернатива технике глубокого копирования
Следующее решение с использованием arraycopy примерно в 3-4 раза быстрее , чем принятый ответ:
public static BufferedImage copyImage(BufferedImage source){
BufferedImage bi = new BufferedImage(source.getWidth(), source.getHeight(), source.getType());
byte[] sourceData = ((DataBufferByte)source.getRaster().getDataBuffer()).getData();
byte[] biData = ((DataBufferByte)bi.getRaster().getDataBuffer()).getData();
System.arraycopy(sourceData, 0, biData, 0, sourceData.length);
return bi;
}
Кстати, ответы с использованием Graphics2D дают такие же хорошие результаты.
Это было безумно полезно для программы, которую я использую для рисования, и не смог реализовать состояния Отмена / Повторить из-за того, что BufferedImages на стеках фактически одно и то же.
Кстати, я предлагаю полностью использовать пару стеков для таких операций! Каждый раз, когда вы что-то делаете, немедленно создайте новое изображение, используйте метод deepCopy, упомянутый выше
image = deepCopy((BufferedImage) stackUndo.peek());
измените изображение по своему усмотрению, затем, когда вы прекратите редактирование (например, когда вы отпустите кнопку мыши),
stackUndo.push(image);
и всегда рисовать элемент в верхней части левой стопки
g.drawImage(stackUndo.peek(),x,y,null);
и затем, если вы выполните какую-либо операцию отмены / повтора, выполните что-то вроде этого
public void undoOrRedo(String op) {
if(op.equals("undo") && stackUndo.size()>1){
stackRedo.push(stackUndo.pop());
repaint();
}
if(op.equals("redo") && stackRedo.size()>0){
stackUndo.push(stackRedo.pop());
repaint();
}
}
всегда оставляйте что-то в левом стеке, потому что для рисования он всегда будет использовать элемент сверху (заглядывать)!
Вот решение, которое я написал много лет назад для JFreeChart.
Он также скопирует любые свойства, которые могут присутствовать в BufferedImage.
Я считаю, что он был протестирован со всеми известными цветовыми моделями (типами изображений).
Будет ли он работать сImage Type 0
обсуждает @JoséRobertoAraújoJunior Не знаю.
Но: тип изображения 0 недействителен и не должен возникать.
/**
* Copied from
* <a href=https://github.com/jfree/jfreechart/blob/master/src/main/java/org/jfree/chart/util/PaintAlpha.java>JFreeChart PaintAlpha</a>
*
* @param srcImage
* @return
*/
public static BufferedImage cloneImage(final BufferedImage srcImage) {
final WritableRaster srcRaster = srcImage.getRaster();
final WritableRaster dstRaster = srcRaster.createCompatibleWritableRaster();
/*
* This is the code that actually COPIES the pixels...
*/
dstRaster.setRect(srcRaster);
/*
* Images hardly ever have Properties, but we copy them anyway...
*/
final String[] propNames = srcImage.getPropertyNames();
final Hashtable<String, Object> props;
if (propNames == null) {
props = null;
} else {
props = new Hashtable<>();
for (int i = 0; i < propNames.length; i++) {
props.put(propNames[i], srcImage.getProperty(propNames[i]));
}
}
/*
* That's it folks! Return the new clone...
*/
return new BufferedImage(srcImage.getColorModel(), dstRaster, srcImage.isAlphaPremultiplied(), props);
}
Я сделал это решение, используя две функции, оно работает на каждом возможном изображении, даже на изображении с видеокамеры ноутбука. Я столкнулся с проблемой, что после кадрирования изображения через камеру оно не работало, но это решение будет работать
static BufferedImage deepCopy(BufferedImage bi)
{
try
{
ColorModel cm = bi.getColorModel();
boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
WritableRaster raster = bi.copyData(bi.getRaster().createCompatibleWritableRaster());
return new BufferedImage(cm, raster, isAlphaPremultiplied, null);
}
catch(Exception ex)
{
}
try{
BufferedImage b = new BufferedImage(bi.getWidth(), bi.getHeight(), bi.getType());
Graphics g = b.getGraphics();
g.drawImage(bi, 0, 0, null);
g.dispose();
return b;
}
catch(Exception ex){
}
return null;
}