如何克隆BufferedImage


120

我有一个其中包含许多bufferedimages的对象,我想创建一个新对象,将所有bufferedimages复制到新对象中,但是这些新图像可能会更改,并且我不希望通过更改原始对象图像来更改新对象图像。

明白了吗?

这有可能做到吗,有人可以建议一个好方法吗?我曾经想到过getSubImage,但在某处读到,对子图像的任何更改都会重新关联到父图像。

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


1
您不能调用该clone()方法吗?还是我错过了什么?我BufferedImage
Noel M 2010年

1
clone仅提供浅表副本,因此它将包含对缓冲图像的引用;不是它们的副本。
Ultimate Gobblement

7
@ NoelM,UltimateGobblement:BufferedImage未实现,Cloneable并且该clone()方法具有受保护的访问。
罗伯特

Answers:


173

像这样吗

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

4
我也在程序中借用了=)
Daniel Kats 2012年

这种方法在复制子图像时
遇到

7
尽管这在大多数情况下都有效,但是当BufferedImage被裁剪后,它不能正常工作(在裁剪之前会返回整个图像)。一个简单的解决方法是将最后一行更改为:
HaydenStudios 2014年

3
返回新的BufferedImage(cm,raster,isAlphaPremultiplied,null).getSubimage(0,0,bi.getWidth(),bi.getHeight());
HaydenStudios 2014年

copyData(null)并不总是有效,因为它可能适用于父栅格(即,当图像是子图像时),请参阅我的修改后的答案
user1050755 2014年

46

我这样做:

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

它工作得很好,并且易于使用。


3
这看起来很简单。为什么这不是最佳答案?有我不知道的缺陷吗?
WVrock

2
@WVrock如果图像类型为0(自定义),则不起作用
Tilman Hausherr

3
替换图形g = b.getGraphics(); 通过Graphics2D g = b.createGraphics(); 它是完美的
Nadir

1
我认为这是最干净的答案。尽管此结果与接受的答案之间有任何性能差异?我觉得可以忽略不计吗?纯粹由于在jvm中优化了对象创建,这可能更快吗?还要使用openjdk 11.如果有人可以回答该问题。
thekevshow

18

当应用于子图像时,上述过程将失败。这是一个更完整的解决方案:

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

谢谢,尝试克隆子图像时出现偏移错误。这个版本正是我所需要的。
洛可可式

5

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

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

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

如果更改刚获得newImage的图像也以任何方式影响原始图像,请纠正我。
-> 用于getScaledInstance的Javadoc-
> 用于SCALE_DEFAULT的Javadoc(其他常量在该常量的下面列出)


我认为这实际上不会复制图像,即,如果您更改了原始图像,则缩放后的比例也会发生变化,但是一段时间以来,这样的病态让其他人可以肯定地说。
f1wade

1
实际上确实会复制图像,因为对原始图像的更改不会更改副本。这个答案简短明了,甚至不限于BufferedImages。唯一的问题是它返回Image,而不是返回BufferedImage
克鲁夫(Kröw)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.