คุณจะโคลน BufferedImage ได้อย่างไร


120

ฉันมีวัตถุที่มีบัฟเฟอร์รูปภาพจำนวนมากอยู่ในนั้นฉันต้องการสร้างวัตถุใหม่โดยคัดลอกรูปภาพที่บัฟเฟอร์ทั้งหมดไปยังวัตถุใหม่ แต่รูปภาพใหม่เหล่านี้อาจมีการเปลี่ยนแปลงและฉันไม่ต้องการให้ภาพวัตถุต้นฉบับถูกแก้ไขโดยการแก้ไข ภาพวัตถุใหม่

ชัดเจนไหม

เป็นไปได้ไหมและใครสามารถแนะนำวิธีที่ดีได้โปรด? ฉันเคยนึกถึง getSubImage แต่อ่านที่ไหนสักแห่งว่าการเปลี่ยนแปลงใด ๆ ในภาพย่อยจะถูกเลือกกลับไปที่อิมเมจหลัก

ฉันแค่อยากได้สำเนาใหม่ทั้งหมดหรือโคลนของ BufferedImage


1
เรียกclone()เมธอดไม่ได้เหรอ หรือฉันพลาดอะไรไป? ฉันไม่รู้อะไรมากมายเกี่ยวกับBufferedImageชั้นเรียน
Noel M

1
การโคลนจะให้สำเนาตื้น ๆ เท่านั้นดังนั้นจึงมีการอ้างอิงถึงภาพที่บัฟเฟอร์ ไม่ใช่สำเนาของพวกเขา
Ultimate Gobblement

7
@NoelM, UltimateGobblement: BufferedImageไม่ได้ใช้งานCloneableและclone()วิธีนี้ได้ป้องกันการเข้าถึง
Robert

คำตอบ:


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

มีปัญหากับวิธีนี้ในการคัดลอกภาพย่อย
mishka

7
แม้ว่าจะใช้งานได้ในสถานการณ์ส่วนใหญ่ แต่ก็ทำงานไม่ถูกต้องเมื่อ BufferedImage นั้นถูกครอบตัด (จะส่งคืนภาพทั้งหมดก่อนที่จะถูกครอบตัด) วิธีแก้ไขง่ายๆคือเปลี่ยนบรรทัดสุดท้ายเป็น:
HaydenStudios

3
ส่งคืน BufferedImage ใหม่ (cm, raster, isAlphaPremultiplied, null) .getSubimage (0, 0, bi.getWidth (), bi.getHeight ());
HaydenStudios

copyData (null) ไม่ทำงานเสมอไปเนื่องจากอาจทำงานบนแรสเตอร์หลัก (เช่นเมื่อรูปภาพเป็นรูปภาพย่อย) ดูคำตอบที่แก้ไขของฉัน
user1050755

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

ขอบคุณฉันได้รับข้อผิดพลาดออฟเซ็ตขณะพยายามโคลนภาพย่อย เวอร์ชันนี้คือสิ่งที่ฉันต้องการ
rococo

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มีผลกระทบต่อภาพต้นฉบับไม่ว่าในทางใดก็ตาม
-> Javadoc สำหรับ getScaledInstance
-> Javadoc สำหรับ SCALE_DEFAULT (ค่าคงที่อื่น ๆ อยู่ด้านล่างค่าหนึ่ง)


ฉันคิดว่าจะไม่คัดลอกรูปภาพจริง ๆ นั่นคือถ้าคุณเปลี่ยนต้นฉบับความตั้งใจที่ปรับขนาดก็จะเปลี่ยนไปเช่นกัน แต่มันก็ไม่ดีพอให้คนอื่นพูดได้อย่างแน่นอน
f1wade

1
นี่เป็นการคัดลอกรูปภาพจริงโดยการเปลี่ยนแปลงที่เป็นต้นฉบับจะไม่เปลี่ยนสำเนา คำตอบนี้สั้นและกระชับและไม่ได้ จำกัด เฉพาะ BufferedImages ปัญหาเดียวก็คือว่ามันกลับไม่ได้Image BufferedImage
Kröw
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.