2010-08-18 10 views
98

Tôi có một đối tượng có nhiều bộ đệm trong nó, 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 gốc được thay đổi bằng cách thay đổi hình ảnh đối tượng mới.Làm thế nào để bạn sao chép một BufferedImage

có rõ ràng không?

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

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

+1

bạn không thể gọi() 'phương pháp 'bản sao? Hay tôi đã bỏ lỡ điều gì đó? Tôi không biết nhiều về lớp 'BufferedImage' –

+1

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

+7

@NoelM, UltimateGobblement: 'BufferedImage' không thực hiện' Cloneable' và phương thức 'clone()' có quyền truy cập được bảo vệ. – Robert

Trả lời

147

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

cảm ơn ive đã sử dụng cái này để sao chép bufferedimage của tôi – f1wade

+3

Tôi cũng đang mượn cái này trong chương trình của mình =) – BlackSheep

+0

Không làm việc cho tôi! Bản sao kết thúc rộng hơn một pixel. –

2

Đây là điên cuồng hữu ích cho một chương trình mà tôi đang sử dụng để vẽ các công cụ, và không thể thực hiện chức năng Undo/Redo bang do BufferedImages trên Stacks là hầu như cùng một điều.

Nhân tiện, tôi đề nghị tất cả các cách sử dụng một vài ngăn xếp cho các loại hoạt động này! Mỗi lần bạn làm điều gì đó, ngay lập tức tạo ra một hình ảnh mới, sử dụng phương pháp deepCopy nêu trên

image = deepCopy((BufferedImage) stackUndo.peek()); 

làm thay đổi hình ảnh như bạn vui lòng, sau đó khi bạn ngừng chỉnh sửa (như khi bạn nhả chuột) làm

stackUndo.push(image);                                  

và luôn vẽ các phần tử ở phía trên cùng của ngăn xếp trái

g.drawImage(stackUndo.peek(),x,y,null); 

và sau đó nếu bạn một số undo/redo hoạt động, hãy làm theo một cái gì đó như thế này

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

hãy chắc chắn luôn để nguyên thứ gì đó trong ngăn bên trái, vì vẽ nó sẽ luôn sử dụng phần tử ở trên cùng (peek) của nó!

34

Tôi làm điều 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à nó là đơn giản để sử dụng.

+2

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

+2

@WVrock Nó không hoạt động nếu loại hình ảnh là 0 (tùy chỉnh) –

+1

thay thế Đồ họa g = b.getGraphics(); bởi Graphics2D g = b.createGraphics(); và nó là hoàn hảo – Nadir

13

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

Một cách khác là sử dụng lớp Graphics2D để 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; 
} 
0

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

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

Xin vui lòng sửa tôi nếu thay đổi chỉ thu được newImage cũng ảnh hưởng đến hình ảnh ban đầu bằng mọi cách.
->Javadoc for getScaledInstance
->Javadoc for SCALE_DEFAULT (các hằng số khác được liệt kê ngay dưới một mà)

+0

Tôi nghĩ rằng 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 willalso quy mô thay đổi, nhưng nó được một thời gian để bệnh cho phép người khác nói chắc chắn. – f1wade