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

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

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

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

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

Solutions Collecting From Web of "Ошибка OutOfMemory при соединении больших изображений"

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

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

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

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

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

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

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

Удачи!

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

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

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

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

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

Вы можете получить некоторые идеи отсюда .

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

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

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

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

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

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