Resize a large bitmap file to scaled output file on Android

前端 未结 21 922
执念已碎
执念已碎 2020-11-22 05:51

I have a large bitmap (say 3888x2592) in a file. Now, I want to resize that bitmap to 800x533 and save it to another file. I normally would scale the bitmap by calling

相关标签:
21条回答
  • 2020-11-22 06:13

    There is a great article about this exact issue on the Android developer website: Loading Large Bitmaps Efficiently

    0 讨论(0)
  • 2020-11-22 06:13

    I use Integer.numberOfLeadingZeros to calculate the best sample size, better performance.

    Full code in kotlin:

    @Throws(IOException::class)
    fun File.decodeBitmap(options: BitmapFactory.Options): Bitmap? {
        return inputStream().use {
            BitmapFactory.decodeStream(it, null, options)
        }
    }
    
    @Throws(IOException::class)
    fun File.decodeBitmapAtLeast(
            @androidx.annotation.IntRange(from = 1) width: Int,
            @androidx.annotation.IntRange(from = 1) height: Int
    ): Bitmap? {
        val options = BitmapFactory.Options()
    
        options.inJustDecodeBounds = true
        decodeBitmap(options)
    
        val ow = options.outWidth
        val oh = options.outHeight
    
        if (ow == -1 || oh == -1) return null
    
        val w = ow / width
        val h = oh / height
    
        if (w > 1 && h > 1) {
            val p = 31 - maxOf(Integer.numberOfLeadingZeros(w), Integer.numberOfLeadingZeros(h))
            options.inSampleSize = 1 shl maxOf(0, p)
        }
        options.inJustDecodeBounds = false
        return decodeBitmap(options)
    }
    
    0 讨论(0)
  • 2020-11-22 06:15

    Why not use the API?

    int h = 48; // height in pixels
    int w = 48; // width in pixels    
    Bitmap scaled = Bitmap.createScaledBitmap(largeBitmap, w, h, true);
    
    0 讨论(0)
  • 2020-11-22 06:16

    Taking into account that you want to resize to exact size and want to keep as much quality as needed I think you should try this.

    1. Find out the size of the resized image with call of BitmapFactory.decodeFile and providing the checkSizeOptions.inJustDecodeBounds
    2. Calculate the maximum possible inSampleSize you can use on your device to not exceed the memory. bitmapSizeInBytes = 2*width*height; Generally for your picture inSampleSize=2 would be fine since you will need only 2*1944x1296)=4.8Mbб which should feet in memory
    3. Use BitmapFactory.decodeFile with inSampleSize to load the Bitmap
    4. Scale the bitmap to exact size.

    Motivation: multiple-steps scaling could give you higher quality picture, however there is no guarantee that it will work better than using high inSampleSize. Actually, I think that you also can use inSampleSize like 5 (not pow of 2) to have direct scaling in one operation. Or just use 4 and then you can just use that image in UI. if you send it to server - than you can do scaling to exact size on server side which allow you to use advanced scaling techniques.

    Notes: if the Bitmap loaded in step-3 is at least 4 times larger (so the 4*targetWidth < width) you probably can use several resizing to achieve better quality. at least that works in generic java, in android you don't have the option to specify the interpolation used for scaling http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html

    0 讨论(0)
  • 2020-11-22 06:16

    I used code like this:

      String filePath=Environment.getExternalStorageDirectory()+"/test_image.jpg";
      BitmapFactory.Options options=new BitmapFactory.Options();
      InputStream is=new FileInputStream(filePath);
      BitmapFactory.decodeStream(is, null, options);
      is.close();
      is=new FileInputStream(filePath);
      // here w and h are the desired width and height
      options.inSampleSize=Math.max(options.outWidth/460, options.outHeight/288); //Max 460 x 288 is my desired...
      // bmp is the resized bitmap
      Bitmap bmp=BitmapFactory.decodeStream(is, null, options);
      is.close();
      Log.d(Constants.TAG, "Scaled bitmap bytes, "+bmp.getRowBytes()+", width:"+bmp.getWidth()+", height:"+bmp.getHeight());
    

    I tried original image is 1230 x 1230, and got bitmap says is 330 x 330.
    And if tried 2590 x 3849, I'll got OutOfMemoryError.

    I traced it, it still throw OutOfMemoryError on line "BitmapFactory.decodeStream(is, null, options);", if original bitmap too large...

    0 讨论(0)
  • 2020-11-22 06:16

    Here is an article that takes a different approach to resizing. It will attempt to load the largest possible bitmap into memory based on available memory in the process and then perform the transforms.

    http://bricolsoftconsulting.com/2012/12/07/handling-large-images-on-android/

    0 讨论(0)
提交回复
热议问题