你如何克隆BufferedImage

时间:2010-08-18 16:10:06

标签: java copy clone bufferedimage

我有一个对象,其中有许多缓冲图像,我想创建一个新对象将所有缓冲图像复制到新对象中,但这些新图像可能会被更改,我不希望原始对象图像被更改通过改变新的物体图像。

那是清楚的吗?

这可能吗?有人可以建议一个好方法吗? 我已经想到了getSubImage,但是在某处读取了对子图像的任何更改都会被重新选回父图像。

我只是希望能够获得一个新的完全独立的BufferedImage副本或克隆

8 个答案:

答案 0 :(得分:166)

这样的东西?

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

答案 1 :(得分:41)

我这样做:

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

效果相当好,使用简单。

答案 2 :(得分:17)

当应用于子图像时,前面提到的过程失败。这是一个更完整的解决方案:

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

答案 3 :(得分:4)

Class BufferedImage没有实现Cloneable接口。因此克隆方法不会被覆盖。这是深度复制技术的替代方案: Java Tip 76: An alternative to the deep copy technique

答案 4 :(得分:4)

另一种方法是使用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;
}

答案 5 :(得分:2)

我知道这个问题已经很久了,但是对于未来的访问者来说,这就是我使用的解决方案:

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

如果更改刚刚获得的newImage也会以任何方式影响原始图像,请更正我 - > Javadoc for getScaledInstance
- > Javadoc for SCALE_DEFAULT(其他常量列在那一个下面)

答案 6 :(得分:1)

这对于我用来绘制内容的程序非常有用,并且由于Stacks上的BufferedImages实际上是同一件事,因此无法实现Undo / Redo状态。

顺便说一句,我建议使用几个堆栈来完成这些操作! 每当你做某事时,立即创建一个新图像,使用上面提到的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();
    }
}

请务必在左侧堆栈中留下一些东西,因为对于绘画,它总是会使用它顶部的元素(窥视)!

答案 7 :(得分:0)

以下使用 arraycopy 的解决方案比接受的答案快 3-4 倍

m365 spo

顺便说一下,使用 Graphics2D 的答案也提供了同样好的结果。