Java chuyển đổi Image thành BufferedImage


82

Đã có câu hỏi như liên kết này trên StackOverflow và câu trả lời được chấp nhận là "đang truyền":

Image image = ImageIO.read(new File(file));
BufferedImage buffered = (BufferedImage) image;

Trong chương trình của tôi, tôi thử:

final float FACTOR  = 4f;
BufferedImage img = ImageIO.read(new File("graphic.png"));
int scaleX = (int) (img.getWidth() * FACTOR);
int scaleY = (int) (img.getHeight() * FACTOR);
Image image = img.getScaledInstance(scaleX, scaleY, Image.SCALE_SMOOTH);
BufferedImage buffered = (BufferedImage) image;

Rất tiếc, tôi gặp lỗi thời gian chạy:

sun.awt.image.ToolkitImage không thể được truyền sang java.awt.image.BufferedImage

Rõ ràng là đúc không hoạt động.
Câu hỏi là: (hoặc có) cách thích hợp để chuyển đổi Image thành BufferedImage là gì?


nếu bạn muốn mở rộng hình ảnh đệm, hãy thử này thử [này stackoverflow.com/questions/4216123/... [1]: stackoverflow.com/questions/4216123/...
user902383

7
Đối với bản ghi, nó KHÔNG phải là trình biên dịch đang nói điều đó. Bạn đang thực sự thấy lỗi thời gian chạy ... không phải lỗi biên dịch.
Stephen C

1
Bạn đúng rồi. Cảm ơn vì đã chỉ ra điều này. Tôi sẽ chỉnh sửa câu hỏi cho phù hợp.
Arek Wilk

@ user902383 Ngay cả khi họ không trả lời trực tiếp câu hỏi của tôi - đó cũng là những giải pháp tuyệt vời.
Arek Wilk

Small Thing to OP: Phương thức ImageIO.read(File)trả về a BufferedImagebằng chữ ký của nó. ( Tham khảo ) Đầu tiên không cần phải gán cho một Imagebiến sau đó ép kiểu BufferedImage. Điều đó có thể khiến mọi người nhầm lẫn khi đọc mã của bạn.
kevinarpe

Câu trả lời:


123

Từ một Công cụ trò chơi Java :

/**
 * Converts a given Image into a BufferedImage
 *
 * @param img The Image to be converted
 * @return The converted BufferedImage
 */
public static BufferedImage toBufferedImage(Image img)
{
    if (img instanceof BufferedImage)
    {
        return (BufferedImage) img;
    }

    // Create a buffered image with transparency
    BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);

    // Draw the image on to the buffered image
    Graphics2D bGr = bimage.createGraphics();
    bGr.drawImage(img, 0, 0, null);
    bGr.dispose();

    // Return the buffered image
    return bimage;
}

6
@SriHarshaChilakapati You shouldn't be worrying about the memory when using Java.Đánh giá mức tiêu thụ bộ nhớ trung bình của các ứng dụng Java, các nhà phát triển khác chắc chắn không lo lắng về bộ nhớ một chút.
Tomáš Zato - Phục hồi Monica

1
@ TomášZato Đối với tôi, dường như bạn đến từ thế giới C ++, đang nghĩ đến việc sử dụng lại bộ nhớ các pixel của dữ liệu hình ảnh. Ý tôi là trong nhận xét trước đây của tôi rằng không cần phải lo lắng về bộ nhớ trong trường hợp này, vì GC sẽ xử lý nó trong Java.
Sri Harsha Chilakapati

2
@SriHarshaChilakapati Vậy những người thu gom rác không tiêu tốn bất kỳ tài nguyên nào? GC chỉ lưu bạn khỏi bộ nhớ xung quanh . Nó không xóa giới hạn phần cứng.
Andrew Sannier

5
Điều này sẽ không hoạt động nếu Imagechưa được tải, vì getWidth(null)hoặc getHeight(null)sẽ trở lại -1trong trường hợp
Dims 22/09/15

1
Tôi đã phải sử dụng BufferedImage.TYPE_INT_RGBthay vì ARGB để có được màu sắc của hình ảnh thu nhỏ của tôi ngay
Stephanie

20

Một cách để xử lý điều này là tạo một BufferedImage mới và yêu cầu đối tượng đồ họa đó vẽ hình ảnh được chia tỷ lệ của bạn vào BufferedImage mới:

final float FACTOR  = 4f;
BufferedImage img = ImageIO.read(new File("graphic.png"));
int scaleX = (int) (img.getWidth() * FACTOR);
int scaleY = (int) (img.getHeight() * FACTOR);
Image image = img.getScaledInstance(scaleX, scaleY, Image.SCALE_SMOOTH);
BufferedImage buffered = new BufferedImage(scaleX, scaleY, TYPE);
buffered.getGraphics().drawImage(image, 0, 0 , null);

Điều đó sẽ thực hiện thủ thuật mà không cần đúc.


2
Đừng bao giờ quên để xử lý các trường hợp đồ họa tạo
Sri Harsha Chilakapati

Làm thế nào để "thanh lý các giao diện đồ họa đã tạo"?
Buffalo

Kiểu trong phương thức khởi tạo BufferedImage có nên khớp với kiểu trong getScaledInstance không?
Drazen Bjelovuk

Không, TYPE là một cái gì đó giống như ARGB hoặc RGBA, cách dữ liệu hình ảnh được lưu trữ bên trong - chọn những gì cảm thấy tự nhiên nhất cho ứng dụng của bạn; Chỉ cần nhìn vào Autocomplete của bạn khi gõ BufferedImage [Autocomplete] để xem tất cả các lựa chọn.
salbeira

3

Nếu bạn đang lấy lại a sun.awt.image.ToolkitImage, bạn có thể truyền Hình ảnh tới đó, rồi sử dụng getBufferedImage () để lấy BufferedImage.

Vì vậy, thay vì dòng mã cuối cùng mà bạn đang truyền, bạn chỉ cần làm:

BufferedImage buffered = ((ToolkitImage) image).getBufferedImage();

7
1) Việc sử dụng các lớp từ sungói sẽ không được như ý muốn. Chúng không được đảm bảo có sẵn trong các JDK không phải Oracle. 2) Phương thức getBufferedImage()chỉ hoạt động nếu hình ảnh được lưu trong bộ đệm đã được tạo ra bên trong bởi TookitImage. Thông thường (99%) thì không, vì vậy giá trị trả về là null. Tham khảo nguồn
kevinarpe

3

Nếu bạn sử dụng Kotlin, bạn có thể thêm một phương thức mở rộng vào Hình ảnh theo cách giống như Sri Harsha Chilakapati đề xuất.

fun Image.toBufferedImage(): BufferedImage {
    if (this is BufferedImage) {
        return this
    }
    val bufferedImage = BufferedImage(this.getWidth(null), this.getHeight(null), BufferedImage.TYPE_INT_ARGB)

    val graphics2D = bufferedImage.createGraphics()
    graphics2D.drawImage(this, 0, 0, null)
    graphics2D.dispose()

    return bufferedImage
}

Và sử dụng nó như thế này:

myImage.toBufferedImage()
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.