Ошибка 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, поэтому ее выход из памяти.
Как подключиться к большим изображениям без исчерпания памяти?
Ответы
Ответ 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 МБ, что не оставит вам достаточно места для времени выполнения языка.