web-dev-qa-db-ja.com

BufferedImageのクローンを作成する方法

多くのバッファリングされた画像を含むオブジェクトがあり、すべてのバッファリングされた画像を新しいオブジェクトにコピーする新しいオブジェクトを作成したいが、これらの新しい画像は変更される可能性があり、元のオブジェクトの画像が新しいオブジェクトの画像。

それは明らかですか?

これは可能ですか?誰かがそれを行うための良い方法を提案できますか? getSubImageについて考えましたが、サブイメージへの変更が親イメージに反映されることをどこかで読みました。

BufferedImageの新しい完全に個別のコピーまたはクローンを取得できるようにしたいだけです。

111
f1wade

このようなもの?

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

私はこれをします:

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

それはかなりうまく機能し、使いやすいです。

41
APerson

前述の手順は、サブイメージに適用すると失敗します。より完全なソリューションは次のとおりです。

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

別の方法は、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
HyperNeutrino

クラスBufferedImageは、Cloneableインターフェイスを実装しません。したがって、cloneメソッドはオーバーライドされません。ディープコピー手法の代替手段を次に示します。 Javaヒント76:ディープコピー手法の代替手段

4
Mike

私はこの質問がかなり古いことを知っていますが、将来の訪問者のために、私が使用するソリューションがあります:

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

取得したばかりのnewImageを変更しても元の画像に何らかの影響がある場合は修正してください。
-> getScaledInstanceのJavadoc
-> SCALE_DEFAULTのJavadoc (他の定数はそのすぐ下にリストされています)

3
PixelMaster

これは、ものを描くために使用しているプログラムにとっては非常に便利であり、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();
    }
}

必ず左のスタックに何かを残してください。ペイントでは常に最上部の要素(ピーク)が使用されるためです!

1