2013-02-28 37 views
7

Tôi muốn tải hình ảnh lớn (18000 x 18000) vào ứng dụng của mình. Nếu tôi sử dụng BufferedImage với loại int_rgb, tôi cần khoảng 1235mb bộ nhớ heap để tải. Đây là lượng bộ nhớ rất cao và người dùng cuối có thể sẽ có ít ram hơn (1GB hoặc ít hơn).Làm cách nào để tải hình ảnh khổng lồ đến Java qua BufferedImage?

Trên PC phát triển của tôi, khi tôi tải hình ảnh từ MyEclipse IDE, nó ném ra khỏi bộ nhớ Exception. Khi tôi đóng gói mã của tôi vào một jar thực thi và chạy nó trên máy tính của tôi bên ngoài Eclipse, nó vẫn ném một ngoại lệ.

Làm cách nào để tải hình ảnh lớn như vậy vào ứng dụng của tôi bằng hình ảnh đệm mà không sử dụng 1235MB bộ nhớ? Có một thủ thuật nào, như tách hình ảnh thành các phần nhỏ hơn như phân đoạn hình ảnh không?

Tôi tìm thấy this thread on SO, nhưng nó không hữu ích cho tôi; Tôi muốn tải hình ảnh đó vào BufferedImage và sau đó vẽ hình ảnh trên Panel bằng cách sử dụng lớp Graphics.

Trả lời

6

Bạn có thể đọc và các mảnh vỡ màn hình của hình ảnh sử dụng ImageReadParam từ ImageIO gói. Dưới đây là một ví dụ cơ bản để minh họa làm thế nào để đọc một đoạn đơn sử dụng ImageReadParam mà không đọc toàn bộ hình ảnh:

import java.awt.Image; 
import java.awt.Rectangle; 
import java.awt.image.BufferedImage; 
import java.io.IOException; 
import java.io.InputStream; 
import java.net.URL; 

import javax.imageio.ImageIO; 
import javax.imageio.ImageReadParam; 
import javax.imageio.ImageReader; 
import javax.imageio.stream.ImageInputStream; 
import javax.swing.*; 

public class TestImageChunks { 
    private static void createAndShowUI() { 
     try { 
      URL url = new URL(
        "http://duke.kenai.com/wave/.Midsize/Wave.png.png"); 
      Image chunk = readFragment(url.openStream(), new Rectangle(150, 
        150, 300, 250)); 
      JOptionPane.showMessageDialog(null, new ImageIcon(chunk), "Duke", 
        JOptionPane.INFORMATION_MESSAGE); 
     } catch (IOException e) { 
      JOptionPane.showMessageDialog(null, e.getMessage(), "Failure", 
        JOptionPane.ERROR_MESSAGE); 
      e.printStackTrace(); 
     } 
    } 

    public static BufferedImage readFragment(InputStream stream, Rectangle rect) 
      throws IOException { 
     ImageInputStream imageStream = ImageIO.createImageInputStream(stream); 
     ImageReader reader = ImageIO.getImageReaders(imageStream).next(); 
     ImageReadParam param = reader.getDefaultReadParam(); 

     param.setSourceRegion(rect); 
     reader.setInput(imageStream, true, true); 
     BufferedImage image = reader.read(0, param); 

     reader.dispose(); 
     imageStream.close(); 

     return image; 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       createAndShowUI(); 
      } 
     }); 
    } 
} 

Kết quả trông như thế này:

enter image description here

+1

cảm ơn những ý kiến ​​quý giá của bạn và tôi sẽ thử điều này và cho bạn biết. – Mihir

+0

tôi triển khai thành công giải pháp của bạn và nó đã hoạt động. hãy giúp tôi về vấn đề này cũng như http://stackoverflow.com/questions/15438506/how-do-i-convert-an-enormous-tiff-image-to-png-jpeg-without-out-of-memory -lỗi – Mihir

2

Nói chung, bạn sẽ cần phải làm một cái gì đó như thế này:

  • Phá vỡ hình ảnh vào tập tin hình ảnh kích thước dễ quản lý và lưu trữ chúng trên đĩa với ứng dụng của bạn.
  • Khi hiển thị một phần cụ thể của hình ảnh này, chỉ các đoạn hình ảnh tải và hiển thị chồng chéo lên chế độ xem của bạn.
  • Khi bạn xoay quanh hình ảnh, hãy cập nhật các đoạn hình ảnh được tải và hiển thị một cách thích hợp.
  • Hoặc là để cho các mảnh hình ảnh không cần thiết được GC thu thập hoặc tải các phần ảnh mới theo cách mà chúng ghi đè lên các tệp cũ hơn. (Lập luận cuối cùng này cho mảnh vỡ hình ảnh hệt cỡ đó nạp vào bộ đệm bộ nhớ gộp.)
+0

tôi đồng ý với lý thuyết của bạn. trong thực tế, tôi vui vì tôi đã suy nghĩ theo cùng một hướng, nhưng bạn có thể cho tôi một ví dụ hay đoạn mã? – Mihir

1

Một giải pháp hoàn chỉnh là BigBufferedImage. Nó có thể tải và lưu trữ hình ảnh lớn hơn nhiều so với giới hạn bộ nhớ. Bí quyết là bộ đệm của nó được thay thế bằng một tệp dựa trên việc thực hiện DataBuffer. Nó lưu trữ hình ảnh trên ổ đĩa cứng. Không sử dụng RAM. Điều này có thể ngăn chặn OutOfMemoryException.

Tạo một BigBufferedImage từ một file image:

BigBufferedImage image = BigBufferedImage.create(
     inputFile, tempDir, TYPE_INT_RGB); 

Tạo một BigBufferedImage trống:

BigBufferedImage image = BigBufferedImage.create(
     tempDir, width, height, TYPE_INT_RGB); 

Render phần của hình ảnh:

part = image.getSubimage(x, y, width, height); 

Để biết thêm thông tin về xử lý ảnh lớn read this article.

Các vấn đề liên quan