Bagaimana Anda mengkloning BufferedImage

120

Saya memiliki objek yang memiliki banyak gambar buffer di dalamnya, saya ingin membuat objek baru yang menyalin semua gambar yang di-buffer ke dalam objek baru, tetapi gambar baru ini dapat diubah dan saya tidak ingin gambar objek asli diubah dengan mengubah gambar objek baru.

Apakah itu jelas?

Apakah ini mungkin untuk dilakukan dan adakah yang bisa menyarankan cara yang baik untuk melakukannya? Saya telah memikirkan getSubImage tetapi membaca bahwa setiap perubahan pada subimage terkait kembali ke gambar induk.

Saya hanya ingin mendapatkan salinan baru yang sepenuhnya terpisah atau klon dari BufferedImage

f1wade
sumber
1
tidak bisakah kamu memanggil clone()metode ini? Atau apakah saya melewatkan sesuatu? Saya tidak tahu banyak tentang BufferedImagekelas
Noel M
1
clone hanya menyediakan salinan dangkal sehingga akan berisi referensi ke gambar yang di-buffer; bukan salinannya.
Ultimate Gobblement
7
@NoelM, UltimateGobblement: BufferedImagetidak diimplementasikan Cloneabledan clone()metode ini memiliki akses yang dilindungi.
Robert

Jawaban:

173

Sesuatu seperti ini?

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);
}
Klark
sumber
4
Saya juga meminjam ini dalam program saya =)
Daniel Kats
memiliki masalah dengan metode ini saat menyalin subimage
mishka
7
Meskipun ini berfungsi di sebagian besar situasi, ini tidak berfungsi dengan baik ketika BufferedImage telah dipotong (mengembalikan seluruh gambar sebelum dipotong). Perbaikan sederhana untuk ini adalah dengan mengubah baris terakhir itu menjadi:
HaydenStudios
3
kembalikan BufferedImage baru (cm, raster, isAlphaPremultiplied, null) .getSubimage (0, 0, bi.getWidth (), bi.getHeight ());
HaydenStudios
copyData (null) tidak selalu berfungsi karena dapat bekerja pada raster induk (mis. bila gambar adalah gambar sub), lihat jawaban saya yang dimodifikasi
pengguna1050755
46

Saya melakukan ini:

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

Ini bekerja dengan cukup baik dan mudah digunakan.

Seseorang
sumber
3
Ini terlihat sangat sederhana. Mengapa ini bukan jawaban terbaik? Apakah ada kekurangan yang tidak saya sadari?
WVrock
2
@WVrock Tidak berfungsi jika jenis gambar adalah 0 (khusus)
Tilman Hausherr
3
ganti Graphics g = b.getGraphics (); oleh Graphics2D g = b.createGraphics (); dan itu sempurna
Nadir
1
Saya pikir ini adalah jawaban terbersih. Meskipun apakah ada perbedaan performa antara ini dan jawaban yang diterima? Saya merasa diabaikan jika ada, tidak? Mungkinkah ini lebih cepat karena pembuatan objek dioptimalkan di jvm. Juga menggunakan openjdk 11. Jika ada yang bisa menjawab pertanyaan itu.
thekevshow
18

Prosedur yang disebutkan sebelumnya gagal saat diterapkan ke sub gambar. Berikut solusi yang lebih lengkap:

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);
}
pengguna1050755
sumber
Terima kasih, saya mendapatkan kesalahan offset saat mencoba mengkloning subimage. Versi ini persis seperti yang saya butuhkan.
rococo
5

Cara lain adalah menggunakan Graphics2Dkelas untuk menggambar gambar ke gambar kosong baru. Ini tidak benar-benar mengkloning gambar, tetapi menghasilkan salinan gambar yang diproduksi.

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;
}
HyperNeutrino
sumber
4

Saya tahu bahwa pertanyaan ini cukup lama, tetapi untuk pengunjung mendatang, inilah solusi yang akan saya gunakan:

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

Harap perbaiki saya jika mengubah yang baru saja diperoleh newImagejuga memengaruhi gambar asli dengan cara apa pun.
-> Javadoc untuk getScaledInstance
-> Javadoc untuk SCALE_DEFAULT (konstanta lain dicantumkan tepat di bawah yang satu itu)

PixelMaster
sumber
Saya pikir itu tidak akan benar-benar menyalin gambar, yaitu jika Anda mengubah aslinya, skala akan juga berubah, tetapi sudah lama sangat sakit biarkan orang lain mengatakan dengan pasti.
f1wade
1
Ini sebenarnya menyalin gambar, karena perubahan ke aslinya tidak akan mengubah salinan. Jawaban ini singkat dan ringkas, bahkan tidak terbatas pada BufferedImages. Satu-satunya masalah adalah ia kembali Image, bukan BufferedImage.
Kröw