How do you clone a BufferedImage
我有一个对象,其中有许多BufferedImages,我想创建一个新对象,将所有BufferedImages复制到新对象中,但这些新图像可能会被更改,我不希望通过更改新对象图像来更改原始对象图像。
明白了吗?
这有可能吗?有人能建议一个好的方法吗?我想到了getsubimage,但在某个地方读到了子映像的任何更改都会被关联回父映像。
我只想得到一个全新的完全独立的bufferedimage拷贝或克隆。
像这样?
1 2 3 4 5 6 | 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 2 3 4 5 6 7 | 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; } |
它工作得相当好,而且使用简单。
当应用于子图像时,前面提到的过程失败。下面是一个更完整的解决方案:
1 2 3 4 5 6 | 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); } |
另一种方法是使用
1 2 3 4 5 6 7 8 | 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; } |
类BufferedImage不实现可克隆接口。因此,克隆方法不会被重写。下面是深度复制技术的另一种选择:Java PoT 76:深度拷贝技术的另一种选择
我知道这个问题很古老,但对于未来的访问者,我会使用以下解决方案:
1 2 |
如果更改刚刚获得的
这对于我用来绘制东西的程序非常有用,并且由于堆栈上的bufferedImages实际上是相同的,所以无法实现撤消/重做状态。
顺便说一下,我建议一路使用两个堆栈来进行这种操作!每次你做什么,立即创建一个新的图像,使用上面提到的deepcopy方法
1 |
根据需要更改图像,然后在停止编辑(如释放鼠标按钮)时进行更改。
1 | stackUndo.push(image); |
并始终在左堆栈顶部绘制元素
1 | g.drawImage(stackUndo.peek(),x,y,null); |
然后如果你做了一些撤消/重做操作,就按照这样做
1 2 3 4 5 6 7 8 9 10 | 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(); } } |
一定要在左边的堆栈中留下一些东西,因为在绘制时,它总是使用顶部的元素(peek)!