У меня есть большое растровое изображение (скажем, 3888x2592) в файле. Теперь я хочу изменить размер этого растрового изображения до 800x533 и сохранить его в другом файле. Обычно я бы масштабировать растровое изображение с помощью вызова Bitmap.createBitmap
метода , но он нуждается в исходный битовый массив в качестве первого аргумента, который не может обеспечить загрузку , потому что исходное изображение в объект Bitmap бы, конечно , превышает память (см здесь , например).
Я также не могу прочитать растровое изображение, например, с BitmapFactory.decodeFile(file, options)
предоставлением BitmapFactory.Options.inSampleSize
, потому что я хочу изменить его размер до точной ширины и высоты. Использование inSampleSize
изменило бы размер растрового изображения до 972x648 (если я использую inSampleSize=4
) или до 778x518 (если я использую inSampleSize=5
, что даже не равно степени 2).
Я также хотел бы избежать чтения изображения с использованием inSampleSize, например, с 972x648 на первом этапе, а затем с изменением его размера до 800x533 на втором этапе, поскольку качество будет низким по сравнению с прямым изменением размера исходного изображения.
Подводя итог моему вопросу: есть ли способ прочитать большой файл изображения с разрешением 10MP или более и сохранить его в новый файл изображения с изменением размера до определенной новой ширины и высоты, без получения исключения OutOfMemory?
Я также попытался BitmapFactory.decodeFile(file, options)
установить значения параметров Options.outHeight и Options.outWidth вручную на 800 и 533, но это не сработало.
Ответы:
Нет . Я бы хотел , чтобы кто - то исправить меня, но я принял груз / изменения размера подход вы пытались в качестве компромисса.
Вот шаги для любого просмотра:
inSampleSize
что все еще дает изображение больше, чем ваша цель.BitmapFactory.decodeFile(file, options)
, передав inSampleSize в качестве опции.Bitmap.createScaledBitmap()
.источник
Джастин ответ переведен в код (отлично подходит для меня):
источник
System.gc()
пожалуйстаЭто «объединенные» решения Моджо Рисина и Офира. Это даст вам пропорционально измененное изображение с границами максимальной ширины и максимальной высоты.
Для меня это было хорошо на 5 мегапиксельных изображениях ниже.
источник
Почему бы не использовать API?
источник
Принимая во внимание другой отличный ответ, лучший код, который я когда-либо видел для этого, находится в документации к инструменту для фотосъемки.
См. Раздел «Декодирование масштабированного изображения».
http://developer.android.com/training/camera/photobasics.html
Решение, которое оно предлагает, представляет собой решение для изменения размера и масштаба, как и другие, но оно довольно аккуратное.
Я скопировал приведенный ниже код как готовую функцию для удобства.
источник
После прочтения этих ответов и документации Android приведен код для изменения размера растрового изображения без загрузки его в память:
источник
Когда у меня большие растровые изображения и я хочу декодировать их, я использую следующее
источник
Это может быть полезно для кого-то еще, смотрящего на этот вопрос. Я переписал код Джастина, чтобы метод также мог получить требуемый объект целевого размера. Это работает очень хорошо при использовании Canvas. Вся заслуга должна идти к Джастину за его отличный исходный код.
Код Джастина ОЧЕНЬ эффективен для сокращения накладных расходов при работе с большими растровыми изображениями.
источник
Я не знаю, является ли мое решение наилучшей практикой, но я достиг загрузки растрового изображения с желаемым масштабированием с помощью параметров
inDensity
иinTargetDensity
.inDensity
это0
изначально , когда не загружается растяжимой ресурс, поэтому этот подход для загрузки изображений без ресурсов.Переменные
imageUri
,maxImageSideLength
иcontext
являются параметрами моего метода. Для наглядности я разместил только реализацию метода без упаковки AsyncTask.источник
Учитывая, что вы хотите изменить размер до точного размера и сохранить столько качества, сколько необходимо, я думаю, вы должны попробовать это.
Мотивация: многошаговое масштабирование может обеспечить более высокое качество изображения, однако нет гарантии, что оно будет работать лучше, чем использование высокого inSampleSize. На самом деле, я думаю, что вы также можете использовать inSampleSize как 5 (не pow из 2), чтобы иметь прямое масштабирование в одной операции. Или просто используйте 4, а затем вы можете просто использовать это изображение в пользовательском интерфейсе. если вы отправляете его на сервер - вы можете выполнить масштабирование до точного размера на стороне сервера, что позволит вам использовать расширенные методы масштабирования.
Примечания: если растровое изображение, загруженное на шаге 3, по крайней мере, в 4 раза больше (так что 4 * targetWidth <width), вы, вероятно, можете использовать несколько изменяющих размеры для достижения лучшего качества. по крайней мере, это работает в общем Java, в Android у вас нет возможности указать интерполяцию, используемую для масштабирования http://today.java.net/pub/a/today/2007/04/03/perils-of- изображения getscaledinstance.html
источник
Я использовал такой код:
Я пробовал исходное изображение 1230 x 1230, и полученное растровое изображение говорит о 330 x 330.
И если я попробовал 2590 x 3849, я получу OutOfMemoryError.
Я проследил это, он все еще выбрасывает OutOfMemoryError в строку "BitmapFactory.decodeStream (is, null, options);", если исходное растровое изображение слишком большое ...
источник
Выше код сделал немного чище. InputStreams наконец-то закрыли обертку, чтобы убедиться, что они также закрыты:
* Примечание
Ввод: InputStream is, int w, int h
Вывод: растровое изображение
источник
Чтобы масштабировать изображение «правильным» способом, не пропуская ни одного пикселя, вам нужно подключиться к декодеру изображений, чтобы выполнить пост-дискретизацию построчно. Android (и лежащая в его основе библиотека Skia) не предоставляет таких хуков, поэтому вам придется свернуть свои собственные. Предполагая, что вы говорите с изображениями в формате jpeg, лучше всего было бы напрямую использовать libjpeg в C.
Учитывая все сложности, использование двухэтапной подвыборки, а затем масштабирования, вероятно, лучше всего подходит для приложений с предварительным просмотром изображений.
источник
Вот статья, которая использует другой подход к изменению размера. Он попытается загрузить максимально возможное растровое изображение в память на основе доступной памяти в процессе, а затем выполнить преобразования.
http://bricolsoftconsulting.com/2012/12/07/handling-large-images-on-android/
источник
Если вы абсолютно хотите сделать один шаг изменения размера, вы можете загрузить весь растровый файл, если android: largeHeap = true, но, как вы можете видеть, это не очень рекомендуется.
Из документации: android: largeHeap Должны ли процессы вашего приложения создаваться с большой кучей Dalvik. Это относится ко всем процессам, созданным для приложения. Это относится только к первому приложению, загруженному в процесс; если вы используете общий идентификатор пользователя, чтобы разрешить нескольким приложениям использовать процесс, все они должны использовать эту опцию последовательно, иначе они будут иметь непредсказуемые результаты. Большинству приложений это не нужно, и вместо этого следует сосредоточиться на снижении общего использования памяти для повышения производительности. Включение этого также не гарантирует фиксированного увеличения доступной памяти, потому что некоторые устройства ограничены их общей доступной памятью.
источник
На веб-сайте разработчиков Android есть отличная статья об этой проблеме: эффективная загрузка больших растровых изображений
источник
Это сработало для меня. Функция получает путь к файлу на SD-карте и возвращает растровое изображение в максимальном отображаемом размере. Код от Ofir с некоторыми изменениями, такими как файл изображения на sd, вместо Ressource, а witthth и heigth получаются из Display Object.
источник
Вот код, который я использую, у которого нет проблем с декодированием больших изображений в памяти на Android. Я смог декодировать изображения размером более 20 МБ, если мои входные параметры около 1024x1024. Вы можете сохранить возвращенное растровое изображение в другой файл. Ниже этого метода есть еще один метод, который я также использую для масштабирования изображений до нового растрового изображения. Не стесняйтесь использовать этот код по своему усмотрению.
ПРИМЕЧАНИЕ. Методы не имеют ничего общего друг с другом, кроме createScaledBitmap, вызывающего метод decode выше. Примечание ширина и высота могут отличаться от исходного изображения.
источник
или:
источник
я использую
Integer.numberOfLeadingZeros
чтобы рассчитать лучший размер выборки, лучшую производительность.Полный код в котлине:
источник
Измените размер растрового изображения, используя следующий код
То же самое объясняется и в следующем совете
http://www.codeproject.com/Tips/625810/Android-Image-Operations-Using-BitmapFactory
источник