Подтвердить что ты не робот

Ошибка OutOfMemory при соединении больших изображений

Я соединяю два изображения, используя приведенный ниже код, но он выдает ошибку OutOfMemory. Мои изображения составляют около 1 МБ.

private Bitmap overlayMark(String first, String second)
{
    Bitmap bmp1, bmp2;
    bmp1 = BitmapFactory.decodeFile(first);
    bmp2 = BitmapFactory.decodeFile(second);
    if (bmp1 == null || bmp2 == null)
        return bmp1;

    int height = bmp1.getHeight();
    if (height < bmp2.getHeight())
        height = bmp2.getHeight();

    Bitmap bmOverlay = Bitmap.createBitmap(bmp1.getWidth() + bmp2.getWidth(), height,
            Bitmap.Config.ARGB_8888);// Out of memory
    Canvas canvas = new Canvas(bmOverlay);
    canvas.drawBitmap(bmp1, 0, 0, null);
    canvas.drawBitmap(bmp2, bmp1.getWidth(), 0, null);
    bmp1.recycle();
    bmp2.recycle();
    return bmOverlay;
}

Обновление:. Я пробовал два ответа, но мне все равно не нравится создавать растровые изображения такого большого размера, проблема в том, что результирующая растровая карта слишком большая по размеру около 2400x3200, поэтому ее выход из памяти.

Как подключиться к большим изображениям без исчерпания памяти?

4b9b3361

Ответ 1

Без загрузки изображения в память вы можете получить размер изображения, используя inJustDecodeBounds. Bitmap возвращает null, но все параметры установлены. Вы можете масштабировать изображение соответствующим образом.

Если ваши изображения в формате JPEG равны 1 MiB, преобразование в BMP действительно займет много памяти. Вы можете легко вычислить свой BMP-эквивалент по размерам изображения. Ожидается, что преобразование такого большого изображения будет катастрофой. Android ограничивает свои приложения только 16 виртуальными машинами MiB.

Также используйте RGB_565 вместо ARGB_8888.

Итак, ваше единственное решение: (a) Использовать BitmapFactory.Options.inSampleSize для масштабирования изображения или (b) Использовать Android NDK, где 16 предел MiB не существует.

Ответ 2

Я использую это простое правило большого пальца: тяжелая работа (как памяти, так и процессора) выполняется на сервере.

Итак, напишите некоторый сервлет, который принимает изображение, изменяет его размер до определенного размера (возможно, также уменьшает глубину пикселя) и возвращает результат.

Кусок торта, и он работает на любом мобильном устройстве, которое вам нужно.

Удачи!

Ответ 3

Я думаю, что решение вроде вроде сумоновских предложений может сработать.

  • Выясните размер финального изображение, основанное на том, что экран.
  • Получить размер первого изображения, используя метод inJustDecodeBounds. Выясните размер первого изображение в конечном изображении. подсчитывать параметры повторной калибровки.
  • Изменение размера изображения, загрузка в память.
  • Запись измененного изображения обратно на диск. Переработайте растровое изображение. (Это поможет при изменении размера второго изображения)
  • Повторите для второго изображения, только вы может пропустить запись на диск.
  • Загрузите первое изображение.

Если вам нужно только отобразить, тогда просто сделайте это. Если нет, тогда вы можете объединить в одно растровое изображение в этот момент и записать на диск. Если это так, это может быть сложно, потому что у вас будет по существу 2x размер экрана в памяти. В этом случае я бы рекомендовал изменить размер меньше. Если вы не можете пойти меньше, то вам придется идти по маршруту NDK, подумал, что я не уверен сколько это поможет. Здесь забавное введение в NDK и JNI. Наконец, я настоятельно рекомендую разработать это с помощью телефона под управлением Android 2.3+, так как его использование распределенных по кустам растровых изображений сделает отладку намного проще. Подробнее о тех здесь.

Ответ 4

Не обязательно, чтобы пространство, занимаемое представлением битмапов в памяти, соответствовало размеру файла. Таким образом, даже если у вас есть 3-мегабайтная память для jvm, вы все равно можете получить OutOfMemoryException.

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

Ответ 5

вы можете получить представление от здесь.

Ответ 6

Вы пытаетесь отобразить это супербольшое изображение или просто пытаетесь его сохранить?

  • Если вы пытаетесь его отобразить. Разрежьте изображения на плитки. Затем отобразите только просматриваемые фрагменты. Если пользователь масштабируется, вам необходимо уменьшить размер растрового изображения, прежде чем показывать все это.

  • Если вы пытаетесь сохранить его, попробуйте сохранить его в разделах в один и тот же файл, отредав изображение вверх.

Загрузка 2 1 м файлов в память, а затем создание 2-м файла оставляет вам 4M в памяти только для ваших изображений. Динамическая загрузка и выгрузка памяти решает эту проблему аналогично плиткам на картах Google или динамическому масштабированию в других картографических решениях.

Ответ 7

Если вам нужно вернуть этот огромный растровый растровый 2400x3200 в качестве результата, невозможно реализовать эту цель. Причина в том, что 2400 * 3200 * 4 байта ~ 30 Мб! Как вы можете надеяться реализовать этот метод, когда даже вы не можете даже поместить возвращаемое значение в свое ограниченное пространство кучи (т.е. 16 Мб)?

И даже если вы использовали 16-битный цвет, он все равно потерпит неудачу, потому что вы в конечном итоге будете использовать около 15 МБ, что не оставит вам достаточно места для времени выполнения языка.