Как вы клонируете BufferedImage - PullRequest
       22

Как вы клонируете BufferedImage

112 голосов
/ 18 августа 2010

У меня есть объект, в котором много буферизованных изображений, я хочу создать новый объект, копирующий все буферизованные изображения в новый объект, но эти новые изображения могут быть изменены, и я не хочу, чтобы исходные изображения объекта были измененыизменяя изображения новых объектов.

это ясно?

Возможно ли это сделать, и может кто-нибудь предложить хороший способ сделать это, пожалуйста?Я думал о getSubImage, но где-то читал, что любые изменения в подизображении возвращаются в родительское изображение.

Я просто хочу иметь возможность получить свежую полностью отдельную копию или клон BufferedImage

Ответы [ 7 ]

166 голосов
/ 18 августа 2010

Как то так?

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);
}
41 голосов
/ 12 октября 2013

Я делаю это:

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

Работает довольно хорошо и прост в использовании.

17 голосов
/ 12 ноября 2014

Вышеупомянутая процедура завершается неудачно при применении к подизображениям. Вот более полное решение:

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);
}
4 голосов
/ 05 июля 2015

Другой способ - использовать класс 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;
}
4 голосов
/ 18 августа 2010

Класс BufferedImage не реализует интерфейс Cloneable.Таким образом, метод клонирования не переопределен.Вот альтернатива для техники глубокого копирования: Java Совет 76: альтернатива технике глубокого копирования

2 голосов
/ 14 декабря 2016

Я знаю, что этот вопрос довольно старый, но для будущих посетителей вот решение, которое я бы использовал:

Image oldImage = getImage();
Image newImage = oldImage.getScaledInstance(oldImage.getWidth(null), oldImage.getHeight(null), Image.SCALE_DEFAULT);

Пожалуйста, исправьте меня, если изменение только что полученного newImage также повлияет на исходное изображение.
-> Javadoc для getScaledInstance
-> Javadoc для SCALE_DEFAULT (остальные константы перечислены чуть ниже этой)

1 голос
/ 10 февраля 2012

Это было безумно полезно для программы, которую я использую для рисования, и не смог реализовать состояния Undo / Redo из-за того, что BufferedImages на Stacks практически идентичен.

Кстати, я предлагаю полностью использовать пару стеков для таких операций!Каждый раз, когда вы что-то делаете, немедленно создайте новое изображение, используйте метод 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();
    }
}

Обязательно всегда оставляйте что-то в левом стеке, потому что для рисования он всегда будет использовать элемент сверху (заглядывать)!

...