Декодирование растровых изображений в Android с правильным размером
Я декодирую растровые изображения с SD-карты с помощью BitmapFactory.decodeFile. Иногда растровые изображения больше, чем то, что нужно приложению или что позволяет куча, поэтому я использую BitmapFactory.Options.inSampleSize для запроса подвыборки (меньшего размера) растрового изображения.
проблема в том, что платформа не обеспечивает точное значение inSampleSize, и я иногда получаю растровое изображение либо слишком маленькое, либо все еще слишком большое для доступной памяти.
от http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html#inSampleSize:
Примечание: декодер будет пытаться выполнить
этот запрос, но результирующее растровое изображение
могут иметь различные размеры, что
именно то, что было предложено.
Кроме того, полномочия 2 часто
быстрее / проще для декодера, чтобы
честь.
как я должен декодировать растровые изображения с SD-карты, чтобы получить растровое изображение точного размера, который мне нужен при потреблении как можно меньше памяти, чтобы расшифровать его?
Edit:
текущий исходный код:
BitmapFactory.Options bounds = new BitmapFactory.Options();
this.bounds.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, bounds);
if (bounds.outWidth == -1) { // TODO: Error }
int width = bounds.outWidth;
int height = bounds.outHeight;
boolean withinBounds = width <= maxWidth && height <= maxHeight;
if (!withinBounds) {
int newWidth = calculateNewWidth(int width, int height);
float sampleSizeF = (float) width / (float) newWidth;
int sampleSize = Math.round(sampleSizeF);
BitmapFactory.Options resample = new BitmapFactory.Options();
resample.inSampleSize = sampleSize;
bitmap = BitmapFactory.decodeFile(filePath, resample);
}
10 ответов:
вы находитесь на правильном пути, однако вы пытаетесь сделать две вещи одновременно: читать файл в и масштабировать его до нужного размера.
первым шагом является чтение файла в растровое изображение немного больше, чем требуется, с помощью BitmapFactory.Опции.inSampleSize, чтобы гарантировать, что вы не потребляете чрезмерную память, читая большое растровое изображение, когда все, что вам нужно, это меньший эскиз или изображение с разрешением экрана.
второй шаг-вызвать Bitmap.createScaledBitmap() чтобы создать новое растровое изображение с требуемым разрешением.
убедитесь, что вы очистите после временного растрового изображения, чтобы восстановить его память. (Либо пусть переменная выходит из области видимости и пусть GC справится с ней, либо вызовите .recycle () на нем, если вы загружаете много изображений и работаете плотно на памяти.)
вы можете использовать
inJustDecodeBounds. Установите его вTRUEи загрузите файл как есть.изображение не будет загружено в память. Но это outheight и outwidth свойства BitmapFactory.Варианты будет содержать фактические параметры размер изображения указан. Вычислите, сколько вы хотите, чтобы подвыборка его. т. е. 1/2 или 1/4 или 1/8 и т. д. и назначить 2/4/8 и т. д. соответственно inSampleSize.
сейчас поставил
inJustDecodeBoundsдоFALSEи звонокBitmapFactory.decodeFile()чтобы загрузить изображение точного размера, как рассчитано выше.
сначала вам нужно попробовать изображение до ближайшего значения выборки, чтобы растровое изображение стало эффективным для памяти, которое вы описали отлично. Как только это будет сделано, вы можете масштабировать его, чтобы соответствовать вашему экрану.
// This function taking care of sampling backImage =decodeSampledBitmapFromResource(getResources(),R.drawable.back, width, height); // This will scale it to your screen width and height. you need to pass screen width and height. backImage = Bitmap.createScaledBitmap(backImage, width, height, false);
так как API уже заявляет, что размер выборки может или не может быть соблюден. Так что я думаю, УР не повезло при использовании
BitmapFactory.но выход будет использовать свой собственный растровый читатель. Но я бы предложил вам придерживаться BitmapFactory, поскольку он довольно хорошо протестирован и стандартизирован.
Я бы постарался не слишком беспокоиться о небольшом дополнительном потреблении памяти, но попробуйте выяснить, почему он не соблюдает значения. К сожалению, я понятия не имею об этом : (
ThumbnailUtils.extractThumbnail(BitmapFactory.decodeFile(filesPath), THUMBSIZE, THUMBSIZE))вы можете напрямую установить THUMBSIZE в зависимости от вашего требования,однако я не уверен в деталях реализации нижнего уровня,качестве выходного изображения и его производительности, но я обычно предпочитаю его, когда мне нужно показать миниатюру.
для тех, кто ищет точный размер изображения из ресурсов.
для точной ширины прохода reqHight=0 и для точной высоты прохода reqWidth=0
public static Bitmap decodeBitmapResource(Context context, int resId, int reqWidth, int reqHeight) { final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(context.getResources(), resId, options); float scale = 1; if (reqWidth != 0 && reqHeight == 0) { options.inSampleSize = (int) Math.ceil(options.outWidth / (float) reqWidth); scale = (float) options.outWidth / (float) reqWidth; } else if (reqHeight != 0 && reqWidth == 0) { options.inSampleSize = (int) Math.ceil(options.outHeight / (float) reqHeight); scale = (float) options.outHeight / (float) reqHeight; } else if (reqHeight != 0 && reqWidth != 0) { float x = (float) options.outWidth / (float) reqWidth; float y = (float) options.outHeight / (float) reqHeight; scale = x > y ? x : y; } reqWidth = (int) ((float) options.outWidth / scale); reqHeight = (int) ((float) options.outHeight / scale); options.inJustDecodeBounds = false; Bitmap tmp = BitmapFactory.decodeResource(context.getResources(), resId, options); Bitmap out = Bitmap.createScaledBitmap(tmp, reqWidth, reqHeight, false); tmp.recycle(); tmp = null; return out; }
Так как я использую inSampleSize я никогда не сталкиваюсь с проблемами из памяти больше. Так что inSampleSize работает довольно стабильно для меня. Я бы рекомендовал вам дважды проверить эту проблему. Размер может быть не точно такой же, как вы и просили. Но он должен быть уменьшен в любом случае, и больше не должно быть "из памяти". Я бы также рекомендовал разместить свой фрагмент кода здесь, возможно, с ним что-то не так.
Как сказал the100rabh, если вы используете BitmapFactory, у вас действительно нет большого выбора. Однако декодирование растровых изображений очень просто, и в зависимости от алгоритма масштабирования, который вы хотите использовать, обычно довольно просто масштабировать его на лету, не считывая большие части исходного растрового изображения в память (в общем случае вам понадобится только удвоить память, необходимую для 1-2 строк исходного растрового изображения).
когда установлен флаг inScaled (по умолчанию это TRUE), если inDensity и inTargetDensity не равны 0, растровое изображение будет масштабироваться в соответствии с inTargetDensity при загрузке, а не полагаться на графическую систему, масштабирующую его каждый раз, когда он рисуется на холсте. Поэтому просто установите inScaled в false.
BitmapFactory.Options options = new BitmapFactory.Options(); options.inScaled = false;
я смог приблизительно получить "правильный размер", масштабируя декодированный файл изображения до 70% его размера растрового изображения.
Bitmap myBitmap = BitmapFactory.decodeFile(path); if(myBitmap != null) { //reduce to 70% size; bitmaps produce larger than actual image size Bitmap rescaledMyBitmap = Bitmap.createScaledBitmap( myBitmap, myBitmap.getWidth()/10*7, myBitmap.getHeight()/10*7, false); image.setImageBitmap(rescaledMyBitmap); }Я надеюсь, что это помогает вам как-то! Мир!
Comments