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


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

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.


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

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


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)


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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.