Загрузка больших изображений в виде миниатюр без проблем с памятью в Java? - PullRequest
10 голосов
/ 03 мая 2011

Я пытаюсь позволить пользователю загружать изображения со своего жесткого диска и визуально представлять их в графическом интерфейсе в виде списка миниатюр (JPanels с иконками, добавленными в JList).В настоящее время я использую ImageIO.read (), чтобы получить BufferedImage, и использую getScaledInstance для каждого изображения (слышал, что вы не должны использовать это, хотя).

Он работает достаточно хорошо с небольшими изображениями, но загружает более четырех фотографий (5000x3000 или около того), и я получаю «java.lang.OutOfMemoryError: Java heap space».Ссылка на полный размер BufferedImage не сохраняется, поэтому я решил, что сборщик мусора избавится от него и сохранит только масштабированное изображение (которое не должно занимать много памяти), но это не похоже на это.Я перехожу на getRuntime (). Gc () и System.gc (), но безрезультатно.

Есть ли хороший способ загрузки масштабированных изображений из файла без ошибок памяти?Очевидно, что многим программным продуктам удается делать именно это, хотя, может быть, и не в Java.Внешние библиотеки в порядке.


Текущий код:

BufferedImage unscaledImage = ImageIO.read(imageFile);

int unscaledHeight = unscaledImage.getHeight();
int unscaledWidth = unscaledImage.getWidth();

int imageRatio = unscaledHeight/unscaledWidth;

if (imageRatio >= 1) {
    return new ImageIcon(unscaledImage.getScaledInstance(width,-1,Image.SCALE_FAST));
} else {
    return new ImageIcon(unscaledImage.getScaledInstance(-1,height,Image.SCALE_FAST));
}

Ответы [ 2 ]

8 голосов
/ 03 мая 2011

Проблема заключается в использовании самого BufferedImage. К тому времени, когда файл будет считан в память, у вас не будет места в куче. В зависимости от того, для чего это нужно, вы можете использовать программу чтения изображений или увеличить размер кучи.

Я бы порекомендовал вам использовать программу для чтения изображений. Например, чтобы получить код для чтения изображений, вы должны написать что-то вроде этого:

  // Create an image input stream on the image
    ImageInputStream iis = ImageIO.createImageInputStream(o);

    // Find all image readers that recognize the image format
    Iterator iter = ImageIO.getImageReaders(iis);
    if (!iter.hasNext()) {
        // No readers found
        return null;
    }

    // Use the first reader
    ImageReader reader = (ImageReader)iter.next();

От: http://www.exampledepot.com/egs/javax.imageio/DiscType.html

Если у вас есть ImageReader, вы можете получить соотношение сторон, позвонив по номеру reader.getAspectRatio()

Я не уверен, как бы вы перешли от ImageReader к миниатюре.

0 голосов
/ 04 мая 2011

У JVM есть неприятная привычка кешировать изображения. Один из способов обойти это:

  1. Создание InputStream, указывающего на изображение.
  2. Считать все данные изображения в byte[] (используя стандартные API ввода-вывода - за пределами imageio и т. Д.).
  3. Создать ByteArrayInputStream из byte[].
  4. Используйте ByteArrayInputStream в качестве источника для ImageIO.read(InputStream).

Поскольку JVM не знает, из какого ресурса были получены байты изображения, она не может однозначно идентифицировать изображение и не будет его кэшировать.


Имейте в виду, я не могу найти никаких документов, подтверждающих то, что я говорю. Это только из прошлого опыта.

...