У меня есть приложение, которое позволяет пользователю делать снимок. После того, как снимок сделан, пользователь может отправить его на мой веб-сервер. Но прежде чем я это сделаю, он должен изменить размер растрового изображения, потому что мне нравится иметь согласованные размеры, отправляемые на мой веб-сервер.Эффективная обработка битмапов с памятью в моно для android
В любом случае, код, который я использую для загрузки растрового изображения в память, а затем манипулировать им, похоже, занимает много памяти. Этот код в настоящее время используется:
/*
* This method is used to calculate image size.
* And also resize/scale image down to 1600 x 1200
*/
private void ResizeBitmapAndSendToWebServer(string album_id) {
Bitmap bm = null;
// This line is taking up to much memory each time..
Bitmap bitmap = MediaStore.Images.Media.GetBitmap(Android.App.Application.Context.ApplicationContext.ContentResolver,fileUri);
/*
* My question is : Could i do the next image manipulation
* before i even load the bitmap into memory?
*/
int width = bitmap.Width;
int height = bitmap.Height;
if (width >= height) { // <-- Landscape picture
float scaledWidth = (float)height/width;
if (width > 1600) {
bm = Bitmap.CreateScaledBitmap (bitmap, 1600, (int)(1600 * scaledWidth), true);
} else {
bm = bitmap;
}
} else {
float scaledHeight = (float)width/height;
if (height > 1600) {
bm = Bitmap.CreateScaledBitmap (bitmap, (int)(1600 * scaledHeight), 1600 , true);
} else {
bm = bitmap;
}
}
// End of question code block.
MemoryStream stream = new MemoryStream();
bitmap.Compress (Bitmap.CompressFormat.Jpeg, 80, stream);
byte[] bitmapData = stream.ToArray();
bitmap.Dispose();
app.api.SendPhoto (Base64.EncodeToString (bitmapData, Base64Flags.Default), album_id);
}
Что было бы хорошим и чистым способом решения таких проблем памяти?
EDIT 1:
После прочтения других сообщений, то мне стало ясно, что я делаю некоторые неэффективные вещи с моим кодом. Это поэтапно, что я делаю:
- Загрузить полный растровый файл в память.
- Решите, что это пейзаж или нет.
- Затем создайте новое растровое изображение с правильными размерами.
- Затем преобразование этого растрового изображения в байтовый массив
- Устранение исходного растрового изображения. (Но никогда не удаляйте масштабированное растровое изображение из памяти).
Что я на самом деле должны делать:
Определить размеры реального растровой без загрузки его в память с:
private void FancyMethodForDeterminingImageDimensions() { BitmapFactory.Options options = new BitmapFactory.Options(); options.InJustDecodeBounds = true; BitmapFactory.DecodeFile(fileUri.Path, options); // Now the dimensions of the bitmap are known without loading // the bitmap into memory. // I am not further going to explain this, i think the purpose is // explaining enough. int outWidth = options.OutWidth; int outHeight = options.OutHeight; }
Если установлено значение TRUE, декодер (no bitmap), но поля out ... по-прежнему будут установлены, что позволяет вызывающему абоненту запросите растровое изображение , не выделяя память для своих пикселей.
- Теперь я знаю реальные размеры. Поэтому я могу уменьшить его до того, как загрузить его в память.
- (в моем случае) Преобразуйте битмап в base64 строку и отправьте ее.
- Утилизируйте все, чтобы память очистилась.
В настоящее время я не могу проверить это, потому что я не на своей машине разработки. Может ли кто-нибудь дать мне обратную связь, если это правильный путь? Это будет оценено.
Невозможно изменить размер страницы на стороне сервера? Вы также не используете (или не распоряжаетесь) свою переменную 'bm', почему? –
см. Мой ответ http://stackoverflow.com/questions/16183635/out-of-memory-error-on-setimageresource/16184893#16184893 –
@Chintan, хотя ваш метод верен, он не всегда дает право inSampleSize. Смотрите мой комментарий здесь: [link] (http://stackoverflow.com/questions/17319361/best-practis-for-handling-bitmaps-in-android-with-mono-droid-xamarin-android/17330028?noredirect=1 # comment25150832_17330028) – jHogen