Этот ответ резюмируется
в статье « Эффективная загрузка больших растровых изображений», в которой объясняется, как использовать inSampleSize для загрузки уменьшенной версии растрового изображения.
В частности, растровые изображения с предварительным масштабированием объясняют детали различных методов, способы их комбинирования и наиболее эффективные с точки зрения памяти.
Существует три основных способа изменения размера растрового изображения на Android, которые имеют разные свойства памяти:
createScaledBitmap API
Этот API примет существующее растровое изображение и создаст НОВОЕ растровое изображение с точными размерами, которые вы выбрали.
С другой стороны, вы можете получить изображение именно того размера, который вам нужен (независимо от того, как оно выглядит). Но недостатком является то , что этому API для работы требуется существующее растровое изображение . Это означает, что изображение должно быть загружено, декодировано и создано растровое изображение, прежде чем можно будет создать новую, меньшую версию. Это идеально с точки зрения получения точных размеров, но ужасно с точки зрения дополнительных накладных расходов на память. Таким образом, это своего рода нарушение условий для большинства разработчиков приложений, которые склонны уделять внимание памяти.
флаг inSampleSize
BitmapFactory.Options
имеет свойство, отмеченное как inSampleSize
изменение размера изображения при его декодировании, чтобы избежать необходимости декодировать во временное растровое изображение. Это целое число, используемое здесь, загрузит изображение с уменьшенным размером в 1 / x. Например, установка значения inSampleSize
2 возвращает изображение, размер которого вдвое меньше, а установка значения 4 возвращает изображение, размер которого составляет 1/4. Обычно размеры изображений всегда будут в несколько раз меньше размера исходного изображения.
С точки зрения памяти использование inSampleSize
- действительно быстрая операция. Фактически, он будет декодировать только каждый X-й пиксель вашего изображения в полученное растровое изображение. Однако есть две основные проблемы inSampleSize
:
Он не дает вам точного разрешения . Он только уменьшает размер вашего растрового изображения на некоторую степень 2.
Изменение размера не самого лучшего качества . Большинство фильтров изменения размера создают красивые изображения, считывая блоки пикселей и затем взвешивая их, чтобы получить соответствующий пиксель с измененным размером. inSampleSize
позволяет избежать всего этого, просто считывая каждые несколько пикселей. Результат довольно производительный, мало памяти, но страдает качество.
Если вы имеете дело только с уменьшением изображения на некоторый размер pow2, и фильтрация не является проблемой, то вы не можете найти более эффективный с точки зрения памяти (или производительный) метод, чем inSampleSize
.
флаги inScaled, inDensity, inTargetDensity
Если вам нужно масштабировать изображение до размера, не равного степени двойки, вам понадобятся флаги inScaled
, inDensity
и . Когда флаг установлен, система вычислит значение масштабирования для применения к растровому изображению путем деления на значения.inTargetDensity
BitmapOptions
inScaled
inTargetDensity
inDensity
mBitmapOptions.inScaled = true;
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity = dstWidth;
// will load & resize the image to be 1/inSampleSize dimensions
mCurrentBitmap = BitmapFactory.decodeResources(getResources(),
mImageIDs, mBitmapOptions);
Использование этого метода изменит размер вашего изображения, а также применит к нему «фильтр изменения размера», то есть конечный результат будет выглядеть лучше, потому что на этапе изменения размера были учтены некоторые дополнительные математические вычисления. Но имейте в виду: этот дополнительный шаг фильтрации требует дополнительного времени обработки и может быстро складываться для больших изображений, что приводит к медленному изменению размера и дополнительному выделению памяти для самого фильтра.
Как правило, не рекомендуется применять эту технику к изображению, размер которого значительно превышает ваш желаемый размер, из-за дополнительных накладных расходов на фильтрацию.
Магическая комбинация
С точки зрения памяти и производительности вы можете комбинировать эти параметры для достижения наилучших результатов. (установив inSampleSize
, inScaled
, inDensity
и inTargetDensity
флаги)
inSampleSize
сначала будет применен к изображению, доведя его до следующей степени двойки БОЛЬШЕ, чем ваш целевой размер. Затем inDensity
& inTargetDensity
используются для масштабирования результата до точных размеров, которые вы хотите, применяя операцию фильтрации для очистки изображения.
Комбинирование этих двух параметров - намного более быстрая операция, поскольку inSampleSize
шаг уменьшит количество пикселей, к которым на итоговом шаге на основе плотности потребуется применить фильтр изменения размера.
mBitmapOptions.inScaled = true;
mBitmapOptions.inSampleSize = 4;
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity = dstWidth * mBitmapOptions.inSampleSize;
// will load & resize the image to be 1/inSampleSize dimensions
mCurrentBitmap = BitmapFactory.decodeFile(fileName, mBitmapOptions);
Если вам нужно подогнать изображение к определенным размерам и немного улучшить фильтрацию, то этот метод является лучшим мостом к получению нужного размера, но выполняется с помощью быстрой операции с низким объемом памяти.
Получение размеров изображения
Получение размера изображения без декодирования всего изображения Чтобы изменить размер растрового изображения, вам необходимо знать входящие размеры. Вы можете использовать inJustDecodeBounds
флаг, чтобы помочь вам получить размеры изображения, без необходимости фактического декодирования данных пикселей.
// Decode just the boundaries
mBitmapOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(fileName, mBitmapOptions);
srcWidth = mBitmapOptions.outWidth;
srcHeight = mBitmapOptions.outHeight;
//now go resize the image to the size you want
Вы можете использовать этот флаг, чтобы сначала декодировать размер, а затем вычислить правильные значения для масштабирования до вашего целевого разрешения.