2014-02-07 2 views
2

В основном я добавляю подборщик обоев для андроида 4.4.2 заставки экрана и когда изображение установлено, и я выключил экран, а затем вернулся, чтобы посмотреть экран блокировки, мой экран идет черным и logcat дает мне ошибку при распределении памяти. До сих пор я пробовал использовать Bitmap decodeFile (String pathName), и я также переустановил использование Bitmap decodeFile (String pathName, Options opts), но результат один и тот же каждый раз ...Недостаточно памяти на распределении байтов 16571536

Вот оригинальный метод, используемый для установки изображение:

private static final String WALLPAPER_IMAGE_PATH = 
     "/data/data/com.android.settings/files/lockscreen_wallpaper.png"; 

private KeyguardUpdateMonitorCallback mBackgroundChanger = new KeyguardUpdateMonitorCallback() { 
    @Override 
    public void onSetBackground(Bitmap bmp) { 
     if (bmp != null) { 
      mKeyguardHost.setCustomBackground(
        new BitmapDrawable(mContext.getResources(), bmp)); 
     } 
     else { 
      File file = new File(WALLPAPER_IMAGE_PATH); 
      if (file.exists()) { 
       mKeyguardHost.setCustomBackground(
         new BitmapDrawable(mContext.getResources(), WALLPAPER_IMAGE_PATH)); 
      } 
      else { 
       mKeyguardHost.setCustomBackground(null); 
      } 
     } 
     updateShowWallpaper(bmp == null); 
    } 
}; 

, который вызывается из корпуса 1 в:

public void setCustomBackground(Drawable d) { 
     if (!mAudioManager.isMusicActive()) { 

      int mBackgroundStyle = Settings.System.getInt(mContext.getContentResolver(), 
        Settings.System.LOCKSCREEN_BACKGROUND_STYLE, 2); 
      int mBackgroundColor = Settings.System.getInt(mContext.getContentResolver(), 
        Settings.System.LOCKSCREEN_BACKGROUND_COLOR, 0x00000000); 
      switch (mBackgroundStyle) { 
       case 0: 
        d = new ColorDrawable(mBackgroundColor); 
        d.setColorFilter(BACKGROUND_COLOR, PorterDuff.Mode.SRC_OVER); 
        mCustomBackground = d; 
        break; 
       case 1: 
        KeyguardUpdateMonitor.getInstance(getContext()).dispatchSetBackground(null); 
        break; 
       case 2: 
       default: 
        mCustomBackground = d; 
      } 
      computeCustomBackgroundBounds(mCustomBackground); 
      setBackground(mBackgroundDrawable); 
     } 

     if (!ActivityManager.isHighEndGfx()) { 
      mCustomBackground = d; 
      if (d != null) { 
       d.setColorFilter(BACKGROUND_COLOR, PorterDuff.Mode.SRC_OVER); 
      } 
      computeCustomBackgroundBounds(mCustomBackground); 
      invalidate(); 
     } else { 
      if (getWidth() == 0 || getHeight() == 0) { 
       d = null; 
      } 
      if (d == null) { 
       mCustomBackground = null; 
       setBackground(mBackgroundDrawable); 
       return; 
      } 
      Drawable old = mCustomBackground; 
      if (old == null) { 
       old = new ColorDrawable(0); 
       computeCustomBackgroundBounds(old); 
      } 

      d.setColorFilter(BACKGROUND_COLOR, PorterDuff.Mode.SRC_OVER); 
      mCustomBackground = d; 
      computeCustomBackgroundBounds(d); 
      Bitmap b = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); 
      Canvas c = new Canvas(b); 
      mBackgroundDrawable.draw(c); 

      Drawable dd = new BitmapDrawable(b); 

      mTransitionBackground = new TransitionDrawable(new Drawable[]{old, dd}); 
      mTransitionBackground.setCrossFadeEnabled(true); 
      setBackground(mTransitionBackground); 

      mTransitionBackground.startTransition(200); 

      mCustomBackground = dd; 
      invalidate(); 
     } 

     if (d != null) { 
      d.setColorFilter(BACKGROUND_COLOR, PorterDuff.Mode.SRC_OVER); 
     } 
     computeCustomBackgroundBounds(mCustomBackground); 
     invalidate(); 
    } 

это мой выход LogCat:

 
I/dalvikvm-heap(13100): Forcing collection of SoftReferences for 16571536-byte allocation 
E/dalvikvm-heap(13100): Out of memory on a 16571536-byte allocation. 
I/dalvikvm(13100): "main" prio=5 tid=1 RUNNABLE 
I/dalvikvm(13100): | group="main" sCount=0 dsCount=0 obj=0x4159fe40 self=0x414d4548 
I/dalvikvm(13100): | sysTid=13100 nice=0 sched=0/0 cgrp=apps handle=1074098536 
I/dalvikvm(13100): | state=R schedstat=(0 0 0) utm=877 stm=93 core=1 
I/dalvikvm(13100): at android.graphics.BitmapFactory.nativeDecodeStream(Native Method) 
I/dalvikvm(13100): at android.graphics.BitmapFactory.decodeStreamInternal(BitmapFactory.java:613) 
I/dalvikvm(13100): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:589) 
I/dalvikvm(13100): at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:369) 
I/dalvikvm(13100): at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:395) 
I/dalvikvm(13100): at com.android.keyguard.KeyguardViewManager$1.onSetBackground(KeyguardViewManager.java:127) 
I/dalvikvm(13100): at com.android.keyguard.KeyguardUpdateMonitor.dispatchSetBackground(KeyguardUpdateMonitor.java:452) 
I/dalvikvm(13100): at com.android.keyguard.KeyguardViewManager$ViewManagerHost.setCustomBackground(KeyguardViewManager.java:302) 

ничего, что я пробовал, пока еще работал, никаких идей?

EDITED

для дальнейшего уточнения это то, что задает изображение в настройках:

 } else if (requestCode == REQUEST_PICK_WALLPAPER) { 
      FileOutputStream wallpaperStream = null; 
      try { 
       wallpaperStream = getActivity().openFileOutput(WALLPAPER_NAME, 
         Context.MODE_WORLD_READABLE); 

      } catch (FileNotFoundException e) { 
       return; // NOOOOO 
      } 
      Uri selectedImageUri = getLockscreenExternalUri(); 
      Bitmap bitmap; 
      if (data != null) { 
       Uri mUri = data.getData(); 
       try { 
        bitmap = MediaStore.Images.Media.getBitmap(getActivity().getContentResolver(), 
          mUri); 
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, wallpaperStream); 

        Toast.makeText(getActivity(), getResources().getString(R.string. 
          background_result_successful), Toast.LENGTH_LONG).show(); 
        Settings.System.putInt(getContentResolver(), 
          Settings.System.LOCKSCREEN_BACKGROUND_STYLE, 1); 
        updateVisiblePreferences(); 

       } catch (FileNotFoundException e) { 
        e.printStackTrace(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
      } else { 
       try { 
        bitmap = BitmapFactory.decodeFile(selectedImageUri.getPath()); 
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, wallpaperStream); 
       } catch (NullPointerException npe) { 
        Log.e(TAG, "SeletedImageUri was null."); 
        Toast.makeText(getActivity(), getResources().getString(R.string. 
          background_result_not_successful), Toast.LENGTH_LONG).show(); 
        super.onActivityResult(requestCode, resultCode, data); 
        return; 
       } 
      } 

     } 
+0

Возможно, попробуйте другое изображение с меньшим размером? – initramfs

+0

проблема заключается в том, что это выбираемое пользователем изображение, выбранное из галереи, поэтому изображение должно каким-то образом сжиматься ... возможность установки пользовательского фона стоп-кадра относительно бесполезна, если нормальное изображение не может быть загружено – cphelps76

+0

Не понимаю, почему вы пытаетесь сжать изображение в PNG, он ничего не делает для уменьшения объема памяти в изображении, и если изображение представляет собой изображение, полученный PNG-файл будет намного больше, чем оригинальный JPG-файл. – Kai

ответ

7

Вы работаете из памяти, потому что вы тщательно не обработки изображений. Взгляните на следующий вопрос/ответ, чтобы получить лучшее представление о том, что происходит при попытке загрузить изображение: Strange out of memory issue while loading an image to a Bitmap object

Если вы новый разработчик, я бы рекомендовал вам использовать любую хорошую библиотеку, которая загружает часть для вас в противном случае было бы очень сложно загружать изображения.

Android-Universal-Image-погрузчик: Широко используется библиотека https://github.com/nostra13/Android-Universal-Image-Loader

Alternative Пикассо библиотеки: одна строка кода делает работу для вас: http://square.github.io/picasso/

Обновлено:

Bitmaps занимают много памяти, особенно для богатых изображений, таких как фотографий. Например, камера на Galaxy Nexus фотографирует до 2592x1936 пикселей (5 мегапикселей). Если используется битмап-конфигурация , это ARGB_8888 (по умолчанию от Android 2.3), тогда , загружая это изображение в память, занимает около 19 МБ памяти (2592 * 1936 * 4 байт), сразу же исчерпав ограничение для каждого приложения на некоторых устройствах.

http://developer.android.com/training/displaying-bitmaps/index.html

+0

Я добавил код, который я использую в настройках, чтобы установить изображение, чтобы выяснить, как я обрабатываю изображение. – cphelps76

+0

может использоваться для сжатия изображения с помощью общего булевого сжатия (формат Bitmap.CompressFormat, int quality, поток OutputStream)? – cphelps76

+0

Проблема не в функции, проблема в размере. В вашем устройстве не хватает памяти. Даже если вы оптимизируете свое решение, не гарантируется, что он будет работать на всех устройствах. Это лучший вариант использования библиотеки, которая была разработана и использована ведущими разработчиками. Это всего лишь одна строка кода. – Sharj

0

Попробуйте один

При показе Bitmap в ImageView из файла первого декодировать его с помощью BitmapHelper.decodeFile(picturePath, 200, 200, true) это вернет сжатый Bitmap так, что при кодировании этого растрового изображения может обрабатывать изображения с высоким разрешением, а также изображения большого размера до 100 МБ файла.

После того, как файл декодирования установил его на ваш ImageView и получить Base64 Строка формы над сжатым изображением с использованием BitmapHelper класс; получите Bitmap из вашего ImageView (т. е. уже сжатый) и используйте ImageBase64.encodeTobase64(bitmap), это снова сжимает файл и обрабатывает исключение OutOfMemory, а Encoding a Bitmap.

Для decoding сначала напишите Base64String, чтобы записать в память устройства. Затем прочитайте Bytes в кусках и декодируйте это ByteArray этим вы получите растровое изображение в своей памяти. После такого масштаба вниз этого растрового изображения с использованием decodeFile() метода, то вы будете иметь сжатый Bitmap от Base64String

Я искал различные блоги и пост, и из них я взял лучше подходящий код и объединил их в один, чтобы сделать более надежными. Попробуйте сделать код ниже, чтобы сделать encoding и decoding более быстрыми темпами.

Для декодирования Base64String

Bitmap bitmap = ImageBase64.decodeBase64(base64ImageStr,MainActivity.this); 
imageView.setImageBitmap(bitmap); 
bitmap = null; 
System.gc(); 

Для кодирования Bitmap Попробуйте это:

imageView.setImageBitmap(BitmapHelper.decodeFile(picturePath, 200, 200, true)); 

Bitmap bitmap = ((BitmapDrawable)imageView.getDrawable()).getBitmap();    
base64ImageStr = ImageBase64.encodeTobase64(bitmap); 

Попробуйте этот код для ImageBase64

public class ImageBase64 { 

    private ImageBase64() { 
     super(); 
    } 
    private static Context appContext; 

    public static String encodeTobase64(Bitmap image) { 

     ByteArrayOutputStream baos=new ByteArrayOutputStream(); 
     image.compress(Bitmap.CompressFormat.JPEG,100, baos); 
      byte [] b=baos.toByteArray(); 
      String temp=null; 
      try{ 
      System.gc(); 
      temp=Base64.encodeToString(b, Base64.DEFAULT); 
      }catch(Exception e){ 
       e.printStackTrace(); 
      }catch(OutOfMemoryError e){ 
       baos=new ByteArrayOutputStream(); 
       image.compress(Bitmap.CompressFormat.JPEG,50, baos); 
       b=baos.toByteArray(); 
       temp=Base64.encodeToString(b, Base64.DEFAULT); 
       Log.e("EWN", "Out of memory error catched"); 
      } 
      return temp; 
    } 


    public static Bitmap decodeBase64(String input,Context context) { 
     byte[] decodedByte = Base64.decode(input, 0); 

     appContext = context; 
     Boolean isSDPresent = android.os.Environment 
       .getExternalStorageState().equals(
         android.os.Environment.MEDIA_MOUNTED); 

     File sdCardDirectory; 
     if (isSDPresent) { 
      // yes SD-card is present 
      sdCardDirectory = new File(
         Environment 
           .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), 
         "IMG"); 

       if (!sdCardDirectory.exists()) { 
        if (!sdCardDirectory.mkdirs()) { 
         Log.d("MySnaps", "failed to create directory"); 

        } 
       } 
     } else { 
      // Sorry 
      sdCardDirectory = new File(context.getCacheDir(),""); 
     } 



     String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss") 
       .format(new Date()); 

     Random rand = new Random(); 

     // nextInt is normally exclusive of the top value, 
     // so add 1 to make it inclusive 
     int randomNum = rand.nextInt((1000 - 0) + 1) + 0; 

     String nw = "IMG_" + timeStamp + randomNum+".txt"; 
     File image = new File(sdCardDirectory, nw); 



     // Encode the file as a PNG image. 
     FileOutputStream outStream; 
     try { 


      outStream = new FileOutputStream(image); 
      outStream.write(input.getBytes()); 

      outStream.flush(); 
      outStream.close(); 
     } catch (FileNotFoundException e) { 
      e.printStackTrace(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 


     Log.i("Compress bitmap path", image.getPath()); 
     Bitmap bitmap; 
     try{ 
     bitmap = BitmapFactory.decodeByteArray(decodedByte, 0, decodedByte.length); 
     }catch(OutOfMemoryError e){ 
      e.printStackTrace(); 
      InputStream is = context.getResources().openRawResource(R.drawable.default_profile_pic); 
      bitmap = BitmapFactory.decodeStream(is); 

     }catch (Exception e) { 
      // TODO: handle exception 
      e.printStackTrace(); 
      bitmap=null; 
     } 

     return bitmap;//BitmapFactory.decodeByteArray(decodedByte, 0, decodedByte.length); 
     //return decodeFile(image); 
    } 

    private static Bitmap decodeFile(File f){ 
     try { 
      //Decode image size 
      BitmapFactory.Options o = new BitmapFactory.Options(); 
      o.inJustDecodeBounds = true; 
      BitmapFactory.decodeStream(new FileInputStream(f),null,o); 

      //The new size we want to scale to 
      final int REQUIRED_SIZE=70; 

      //Find the correct scale value. It should be the power of 2. 
      int scale=1; 
      while(o.outWidth/scale>=REQUIRED_SIZE && o.outHeight/scale>=REQUIRED_SIZE) 
       scale*=2; 

      //Decode with inSampleSize 
      BitmapFactory.Options o2 = new BitmapFactory.Options(); 
      o2.inSampleSize=scale; 

      Bitmap bmp = BitmapFactory.decodeStream(new FileInputStream(f), null, o2); 


      Boolean isSDPresent = android.os.Environment 
        .getExternalStorageState().equals(
          android.os.Environment.MEDIA_MOUNTED); 
      File sdCardDirectory; 
      if (isSDPresent) { 
       // yes SD-card is present 
       sdCardDirectory = new File(
          Environment 
            .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), 
          "IMG"); 

        if (!sdCardDirectory.exists()) { 
         if (!sdCardDirectory.mkdirs()) { 
          Log.d("MySnaps", "failed to create directory"); 

         } 
        } 
      } else { 
       // Sorry 
       sdCardDirectory = new File(appContext.getCacheDir(),""); 
      } 



      String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss") 
        .format(new Date()); 

      Random rand = new Random(); 

      // nextInt is normally exclusive of the top value, 
      // so add 1 to make it inclusive 
      int randomNum = rand.nextInt((1000 - 0) + 1) + 0; 

      String nw = "IMG_" + timeStamp + randomNum+".png"; 
      File image = new File(sdCardDirectory, nw); 



      FileOutputStream out = null; 
      try { 
       out = new FileOutputStream(image); 
       bmp.compress(Bitmap.CompressFormat.PNG, 100, out); // bmp is your Bitmap instance 
       // PNG is a lossless format, the compression factor (100) is ignored 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } finally { 
       try { 
        if (out != null) { 
         out.close(); 
        } 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
      } 

      String pathNew =compressImage(image.getAbsolutePath()); 
      Uri uri = Uri.parse(pathNew); 
      Bitmap bitmap=null ; 
      try { 
       bitmap  = MediaStore.Images.Media.getBitmap(appContext.getContentResolver(),uri); 
      } catch (IOException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 

      return bitmap; 
     } catch (FileNotFoundException e) {} 
     return null; 
    } 


    public static String compressImage(String imageUri) { 

     String filePath = imageUri;//getRealPathFromURI(imageUri); 
     Bitmap scaledBitmap = null; 

     BitmapFactory.Options options = new BitmapFactory.Options(); 

//  by setting this field as true, the actual bitmap pixels are not loaded in the memory. Just the bounds are loaded. If 
//  you try the use the bitmap here, you will get null. 
     options.inJustDecodeBounds = true; 
     Bitmap bmp = BitmapFactory.decodeFile(filePath, options); 

     int actualHeight = options.outHeight; 
     int actualWidth = options.outWidth; 

//  max Height and width values of the compressed image is taken as 816x612 

     float maxHeight = 816.0f; 
     float maxWidth = 612.0f; 
     float imgRatio = actualWidth/actualHeight; 
     float maxRatio = maxWidth/maxHeight; 

//  width and height values are set maintaining the aspect ratio of the image 

     if (actualHeight > maxHeight || actualWidth > maxWidth) { 
      if (imgRatio < maxRatio) {    imgRatio = maxHeight/actualHeight;    actualWidth = (int) (imgRatio * actualWidth);    actualHeight = (int) maxHeight;    } else if (imgRatio > maxRatio) { 
       imgRatio = maxWidth/actualWidth; 
       actualHeight = (int) (imgRatio * actualHeight); 
       actualWidth = (int) maxWidth; 
      } else { 
       actualHeight = (int) maxHeight; 
       actualWidth = (int) maxWidth; 

      } 
     } 

//  setting inSampleSize value allows to load a scaled down version of the original image 

     options.inSampleSize = calculateInSampleSize(options, actualWidth, actualHeight); 

//  inJustDecodeBounds set to false to load the actual bitmap 
     options.inJustDecodeBounds = false; 

//  this options allow android to claim the bitmap memory if it runs low on memory 
     options.inPurgeable = true; 
     options.inInputShareable = true; 
     options.inTempStorage = new byte[16 * 1024]; 

     try { 
//   load the bitmap from its path 
      bmp = BitmapFactory.decodeFile(filePath, options); 
     } catch (OutOfMemoryError exception) { 
      exception.printStackTrace(); 

     } 
     try { 
      scaledBitmap = Bitmap.createBitmap(actualWidth, actualHeight,Bitmap.Config.ARGB_8888); 
     } catch (OutOfMemoryError exception) { 
      exception.printStackTrace(); 
     } 

     float ratioX = actualWidth/(float) options.outWidth; 
     float ratioY = actualHeight/(float) options.outHeight; 
     float middleX = actualWidth/2.0f; 
     float middleY = actualHeight/2.0f; 

     Matrix scaleMatrix = new Matrix(); 
     scaleMatrix.setScale(ratioX, ratioY, middleX, middleY); 

     Canvas canvas = new Canvas(scaledBitmap); 
     canvas.setMatrix(scaleMatrix); 
     canvas.drawBitmap(bmp, middleX - bmp.getWidth()/2, middleY - bmp.getHeight()/2, new Paint(Paint.FILTER_BITMAP_FLAG)); 

//  check the rotation of the image and display it properly 
     ExifInterface exif; 
     try { 
      exif = new ExifInterface(filePath); 

      int orientation = exif.getAttributeInt(
        ExifInterface.TAG_ORIENTATION, 0); 
      Log.d("EXIF", "Exif: " + orientation); 
      Matrix matrix = new Matrix(); 
      if (orientation == 6) { 
       matrix.postRotate(90); 
       Log.d("EXIF", "Exif: " + orientation); 
      } else if (orientation == 3) { 
       matrix.postRotate(180); 
       Log.d("EXIF", "Exif: " + orientation); 
      } else if (orientation == 8) { 
       matrix.postRotate(270); 
       Log.d("EXIF", "Exif: " + orientation); 
      } 
      scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, 
        scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, 
        true); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

     FileOutputStream out = null; 
     String filename = getFilename(); 
     try { 
      out = new FileOutputStream(filename); 

//   write the compressed bitmap at the destination specified by filename. 
      scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 80, out); 

     } catch (FileNotFoundException e) { 
      e.printStackTrace(); 
     } 

     return filename; 

    } 

    public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { 
     final int height = options.outHeight; 
     final int width = options.outWidth; 
     int inSampleSize = 1; 

     if (height > reqHeight || width > reqWidth) { 
      final int heightRatio = Math.round((float) height/ (float) reqHeight); 
      final int widthRatio = Math.round((float) width/(float) reqWidth); 
      inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;  }  final float totalPixels = width * height;  final float totalReqPixelsCap = reqWidth * reqHeight * 2;  while (totalPixels/(inSampleSize * inSampleSize) > totalReqPixelsCap) { 
      inSampleSize++; 
     } 

     return inSampleSize; 
    } 

    public static String getFilename() { 
     /*File file = new File(Environment.getExternalStorageDirectory().getPath(), "IMG/Images"); 
     if (!file.exists()) { 
      file.mkdirs(); 
     } 
     String uriSting = (file.getAbsolutePath() + "/" + System.currentTimeMillis() + ".jpg"); 
     */ 


     Boolean isSDPresent = android.os.Environment 
       .getExternalStorageState().equals(
         android.os.Environment.MEDIA_MOUNTED); 

     File sdCardDirectory; 
     if (isSDPresent) { 
      // yes SD-card is present 
      sdCardDirectory = new File(
         Environment 
           .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getPath(), 
         "IMG/Images"); 

       if (!sdCardDirectory.exists()) { 
        if (!sdCardDirectory.mkdirs()) { 
         Log.d("MySnaps", "failed to create directory"); 

        } 
       } 
     } else { 
      // Sorry 
      sdCardDirectory = new File(appContext.getCacheDir(),""); 
     } 

     String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss") 
     .format(new Date()); 

     Random rand = new Random(); 

// nextInt is normally exclusive of the top value, 
// so add 1 to make it inclusive 
     int randomNum = rand.nextInt((1000 - 0) + 1) + 0; 

     String nw = "img_" + timeStamp + randomNum+".jpg"; 
     File image = new File(sdCardDirectory, nw); 

     String uriSting1 = (sdCardDirectory.getAbsolutePath() + "/" + nw);//System.currentTimeMillis() + ".jpg"); 

     return uriSting1; 

    } 
} 

Добавить этот класс для обработки тяжелых изображений

public class BitmapHelper 
{ 

    //decodes image and scales it to reduce memory consumption 
    public static Bitmap decodeFile(String bitmapFile, int requiredWidth, int requiredHeight, boolean quickAndDirty) 
    { 
     try 
     { 
      //Decode image size 
      BitmapFactory.Options bitmapSizeOptions = new BitmapFactory.Options(); 
      bitmapSizeOptions.inJustDecodeBounds = true; 
      BitmapFactory.decodeStream(new FileInputStream(bitmapFile), null, bitmapSizeOptions); 

      // load image using inSampleSize adapted to required image size 
      BitmapFactory.Options bitmapDecodeOptions = new BitmapFactory.Options(); 
      bitmapDecodeOptions.inTempStorage = new byte[16 * 1024]; 
      bitmapDecodeOptions.inSampleSize = computeInSampleSize(bitmapSizeOptions, requiredWidth, requiredHeight, false); 
      bitmapDecodeOptions.inPurgeable = true; 
      bitmapDecodeOptions.inDither = !quickAndDirty; 
      bitmapDecodeOptions.inPreferredConfig = quickAndDirty ? Bitmap.Config.RGB_565 : Bitmap.Config.ARGB_8888; 

      Bitmap decodedBitmap = BitmapFactory.decodeStream(new FileInputStream(bitmapFile), null, bitmapDecodeOptions); 

      // scale bitmap to mathc required size (and keep aspect ratio) 

      float srcWidth = (float) bitmapDecodeOptions.outWidth; 
      float srcHeight = (float) bitmapDecodeOptions.outHeight; 

      float dstWidth = (float) requiredWidth; 
      float dstHeight = (float) requiredHeight; 

      float srcAspectRatio = srcWidth/srcHeight; 
      float dstAspectRatio = dstWidth/dstHeight; 

      // recycleDecodedBitmap is used to know if we must recycle intermediary 'decodedBitmap' 
      // (DO NOT recycle it right away: wait for end of bitmap manipulation process to avoid 
      // java.lang.RuntimeException: Canvas: trying to use a recycled bitmap [email protected] 
      // I do not excatly understand why, but this way it's OK 

      boolean recycleDecodedBitmap = false; 

      Bitmap scaledBitmap = decodedBitmap; 
      if (srcAspectRatio < dstAspectRatio) 
      { 
       scaledBitmap = getScaledBitmap(decodedBitmap, (int) dstWidth, (int) (srcHeight * (dstWidth/srcWidth))); 
       // will recycle recycleDecodedBitmap 
       recycleDecodedBitmap = true; 
      } 
      else if (srcAspectRatio > dstAspectRatio) 
      { 
       scaledBitmap = getScaledBitmap(decodedBitmap, (int) (srcWidth * (dstHeight/srcHeight)), (int) dstHeight); 
       recycleDecodedBitmap = true; 
      } 

      // crop image to match required image size 

      int scaledBitmapWidth = scaledBitmap.getWidth(); 
      int scaledBitmapHeight = scaledBitmap.getHeight(); 

      Bitmap croppedBitmap = scaledBitmap; 

      if (scaledBitmapWidth > requiredWidth) 
      { 
       int xOffset = (scaledBitmapWidth - requiredWidth)/2; 
       croppedBitmap = Bitmap.createBitmap(scaledBitmap, xOffset, 0, requiredWidth, requiredHeight); 
       scaledBitmap.recycle(); 
      } 
      else if (scaledBitmapHeight > requiredHeight) 
      { 
       int yOffset = (scaledBitmapHeight - requiredHeight)/2; 
       croppedBitmap = Bitmap.createBitmap(scaledBitmap, 0, yOffset, requiredWidth, requiredHeight); 
       scaledBitmap.recycle(); 
      } 

      if (recycleDecodedBitmap) 
      { 
       decodedBitmap.recycle(); 
      } 
      decodedBitmap = null; 

      scaledBitmap = null; 
      return croppedBitmap; 
     } 
     catch (Exception ex) 
     { 
      ex.printStackTrace(); 
     } 
     return null; 
    } 

    /** 
    * compute powerOf2 or exact scale to be used as {@link BitmapFactory.Options#inSampleSize} value (for subSampling) 
    * 
    * @param requiredWidth 
    * @param requiredHeight 
    * @param powerOf2 
    *   weither we want a power of 2 sclae or not 
    * @return 
    */ 
    public static int computeInSampleSize(BitmapFactory.Options options, int dstWidth, int dstHeight, boolean powerOf2) 
    { 
     int inSampleSize = 1; 

     // Raw height and width of image 
     final int srcHeight = options.outHeight; 
     final int srcWidth = options.outWidth; 

     if (powerOf2) 
     { 
      //Find the correct scale value. It should be the power of 2. 

      int tmpWidth = srcWidth, tmpHeight = srcHeight; 
      while (true) 
      { 
       if (tmpWidth/2 < dstWidth || tmpHeight/2 < dstHeight) 
        break; 
       tmpWidth /= 2; 
       tmpHeight /= 2; 
       inSampleSize *= 2; 
      } 
     } 
     else 
     { 
      // Calculate ratios of height and width to requested height and width 
      final int heightRatio = Math.round((float) srcHeight/(float) dstHeight); 
      final int widthRatio = Math.round((float) srcWidth/(float) dstWidth); 

      // Choose the smallest ratio as inSampleSize value, this will guarantee 
      // a final image with both dimensions larger than or equal to the 
      // requested height and width. 
      inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; 
     } 

     return inSampleSize; 
    } 

    public static Bitmap drawableToBitmap(Drawable drawable) 
    { 
     if (drawable instanceof BitmapDrawable) 
     { 
      return ((BitmapDrawable) drawable).getBitmap(); 
     } 

     Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Config.ARGB_8888); 
     Canvas canvas = new Canvas(bitmap); 
     drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); 
     drawable.draw(canvas); 

     return bitmap; 
    } 

    public static Bitmap getScaledBitmap(Bitmap bitmap, int newWidth, int newHeight) 
    { 
     int width = bitmap.getWidth(); 
     int height = bitmap.getHeight(); 
     float scaleWidth = ((float) newWidth)/width; 
     float scaleHeight = ((float) newHeight)/height; 

     // CREATE A MATRIX FOR THE MANIPULATION 
     Matrix matrix = new Matrix(); 
     // RESIZE THE BIT MAP 
     matrix.postScale(scaleWidth, scaleHeight); 

     // RECREATE THE NEW BITMAP 
     Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false); 
     return resizedBitmap; 
    } 

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