2013-07-12 3 views
1

У меня есть приложение, которое позволяет пользователю делать снимок. После того, как снимок сделан, пользователь может отправить его на мой веб-сервер. Но прежде чем я это сделаю, он должен изменить размер растрового изображения, потому что мне нравится иметь согласованные размеры, отправляемые на мой веб-сервер.Эффективная обработка битмапов с памятью в моно для 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:

После прочтения других сообщений, то мне стало ясно, что я делаю некоторые неэффективные вещи с моим кодом. Это поэтапно, что я делаю:

  1. Загрузить полный растровый файл в память.
  2. Решите, что это пейзаж или нет.
  3. Затем создайте новое растровое изображение с правильными размерами.
  4. Затем преобразование этого растрового изображения в байтовый массив
  5. Устранение исходного растрового изображения. (Но никогда не удаляйте масштабированное растровое изображение из памяти).

Что я на самом деле должны делать:

  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 ... по-прежнему будут установлены, что позволяет вызывающему абоненту запросите растровое изображение , не выделяя память для своих пикселей.

  1. Теперь я знаю реальные размеры. Поэтому я могу уменьшить его до того, как загрузить его в память.
  2. (в моем случае) Преобразуйте битмап в base64 строку и отправьте ее.
  3. Утилизируйте все, чтобы память очистилась.

В настоящее время я не могу проверить это, потому что я не на своей машине разработки. Может ли кто-нибудь дать мне обратную связь, если это правильный путь? Это будет оценено.

+0

Невозможно изменить размер страницы на стороне сервера? Вы также не используете (или не распоряжаетесь) свою переменную 'bm', почему? –

+0

см. Мой ответ http://stackoverflow.com/questions/16183635/out-of-memory-error-on-setimageresource/16184893#16184893 –

+0

@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

ответ

2
 private void ResizeBitmapAndSendToWebServer(string album_id) { 

      BitmapFactory.Options options = new BitmapFactory.Options(); 
      options.InJustDecodeBounds = true; // <-- This makes sure bitmap is not loaded into memory. 
      // Then get the properties of the bitmap 
      BitmapFactory.DecodeFile (fileUri.Path, options); 
      Android.Util.Log.Debug ("[BITMAP]" , string.Format("Original width : {0}, and height : {1}", options.OutWidth, options.OutHeight)); 
      // CalculateInSampleSize calculates the right aspect ratio for the picture and then calculate 
      // the factor where it will be downsampled with. 
      options.InSampleSize = CalculateInSampleSize (options, 1600, 1200); 
      Android.Util.Log.Debug ("[BITMAP]" , string.Format("Downsampling factor : {0}", CalculateInSampleSize (options, 1600, 1200))); 
      // Now that we know the downsampling factor, the right sized bitmap is loaded into memory. 
      // So we set the InJustDecodeBounds to false because we now know the exact dimensions. 
      options.InJustDecodeBounds = false; 
      // Now we are loading it with the correct options. And saving precious memory. 
      Bitmap bm = BitmapFactory.DecodeFile (fileUri.Path, options); 
      Android.Util.Log.Debug ("[BITMAP]" , string.Format("Downsampled width : {0}, and height : {1}", bm.Width, bm.Height)); 
      // Convert it to Base64 by first converting the bitmap to 
      // a byte array. Then convert the byte array to a Base64 String. 
      MemoryStream stream = new MemoryStream(); 
      bm.Compress (Bitmap.CompressFormat.Jpeg, 80, stream); 
      byte[] bitmapData = stream.ToArray(); 
      bm.Dispose(); 

      app.api.SendPhoto (Base64.EncodeToString (bitmapData, Base64Flags.Default), album_id); 

     } 
Смежные вопросы