Làm cách nào để bạn sao chép một Hình ảnh đệm


120

Tôi có một đối tượng có nhiều bộ đệm trong đó, tôi muốn tạo một đối tượng mới sao chép tất cả các bộ đệm vào đối tượng mới, nhưng những hình ảnh mới này có thể bị thay đổi và tôi không muốn hình ảnh đối tượng ban đầu bị thay đổi bằng cách thay đổi hình ảnh đối tượng mới.

rõ chưa?

Điều này có thể làm được không và bất cứ ai có thể đề xuất một cách tốt để làm điều đó không? Tôi đã nghĩ đến getSubImage nhưng đọc ở đâu đó rằng bất kỳ thay đổi nào đối với hình ảnh con đều được phản hồi trở lại hình ảnh gốc.

Tôi chỉ muốn có thể nhận được một bản sao hoặc bản sao hoàn toàn riêng biệt của BufferedImage


1
bạn không thể gọi clone()phương thức? Hay tôi đã bỏ lỡ điều gì đó? Tôi không biết nhiều về BufferedImagelớp học
Noel M

1
clone chỉ cung cấp một bản sao cạn để nó chứa các tham chiếu đến các hình ảnh được đệm; không phải bản sao của chúng.
Ultimate Gobblement

7
@NoelM, UltimateGobblement: BufferedImagekhông triển khai Cloneableclone()phương thức có quyền truy cập được bảo vệ.
Robert

Câu trả lời:


173

Một cái gì đó như thế này?

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
Mình cũng đang mượn cái này trong chương trình của mình =)
Daniel Kats

có vấn đề với phương pháp này trên sao chép subimage
mishka

7
Mặc dù điều này hoạt động trong hầu hết các trường hợp, nhưng nó không hoạt động bình thường khi BufferedImage đó đã bị cắt (nó trả về toàn bộ hình ảnh trước khi được cắt). Một sửa chữa đơn giản cho điều này là để thay đổi điều đó dòng cuối cùng để:
HaydenStudios

3
trả về BufferedImage mới (cm, raster, isAlphaPremultiplied, null) .getSubimage (0, 0, bi.getWidth (), bi.getHeight ());
HaydenStudios

copyData (null) không phải lúc nào công việc bởi vì nó có thể làm việc trên một raster phụ huynh, xem câu trả lời của tôi được sửa đổi (tức là khi hình ảnh là một hình ảnh phụ.)
user1050755

46

Tôi làm việc này:

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

Nó hoạt động khá tốt và sử dụng đơn giản.


3
Điều này trông khá đơn giản. Tại sao đây không phải là câu trả lời tốt nhất? Có một lỗ hổng nào mà tôi không biết?
WVrock

2
@WVrock Nó không làm việc nếu loại hình ảnh là 0 (tùy chỉnh)
Tilman Hausherr

3
thay thế Graphics g = b.getGraphics (); bởi Graphics2D g = b.createGraphics (); và nó thật hoàn hảo
Nadir

1
Tôi nghĩ đây là câu trả lời rõ ràng nhất. Mặc dù có sự khác biệt về hiệu suất giữa câu trả lời này và câu trả lời được chấp nhận không? Tôi cảm thấy như không đáng kể nếu có không? Điều này có thể nhanh hơn hoàn toàn vì việc tạo đối tượng được tối ưu hóa trong jvm. Cũng sử dụng openjdk 11. Nếu ai đó có thể trả lời câu hỏi đó.
thekevshow

18

Quy trình đã đề cập trước đó không thành công khi áp dụng cho hình ảnh phụ. Đây là một giải pháp hoàn chỉnh hơn:

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

Cảm ơn bạn, tôi đã gặp lỗi bù khi cố sao chép một hình ảnh phụ. Phiên bản này là chính xác những gì tôi cần.
rococo

5

Một cách khác là sử dụng Graphics2Dlớp để vẽ hình ảnh lên một hình ảnh trống mới. Điều này không thực sự sao chép hình ảnh, nhưng nó dẫn đến một bản sao của hình ảnh được tạo ra.

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

Tôi biết rằng câu hỏi này khá cũ, nhưng đối với những khách truy cập trong tương lai, đây là giải pháp tôi sẽ sử dụng:

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

Vui lòng sửa cho tôi nếu việc thay đổi newImagehình ảnh vừa thu được cũng ảnh hưởng đến hình ảnh gốc theo bất kỳ cách nào.
-> Javadoc cho getScaledInstance
-> Javadoc cho SCALE_DEFAULT (các hằng số khác được liệt kê ngay bên dưới hằng số đó)


Tôi nghĩ rằng điều đó sẽ không thực sự sao chép hình ảnh, tức là nếu bạn thay đổi bản gốc, tỷ lệ sẽ thay đổi, nhưng đã lâu rồi nên hãy để người khác nói chắc chắn.
f1wade 14/12/16

1
Điều này thực sự sao chép hình ảnh, trong đó thay đổi đối với bản gốc sẽ không thay đổi bản sao. Câu trả lời này ngắn gọn và súc tích và thậm chí không giới hạn ở BufferedImages. Vấn đề duy nhất là nó trả về Image, không phải BufferedImage.
Kröw
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.