Search code examples
androidimage-scaling

Downsizing Android Bitmap always results in jagged edges


I'm seeing very ugly artifacting / jagged edges when I downsize an image on an Android device no matter what I try. I've gone through several potential solutions I found on StackOverflow and blogs, and everything seems to give me similar results.

Original Image (4096 x 4096): original image

Scaled Image (214 x 214) (notice the jagged edges): scaled image

What I have tried:

  1. Drawing the image to a Canvas using a Paint with anti-aliasing, and filtering enabled
  2. Multiple variations of BitmapFactory.decode
  3. bitmap.scale()
  4. Compressor - an Android Image Scaling Library

All of the above trials have yielded almost the exact same result. This is such a common problem though, that surely I'm overlooking something, or not doing something properly.

If I use a web-based image-resizer, here is the result: What it should look like: enter image description here

What can I do to get the same results as the above image?


Solution

  • There is a tricky way to (manage to) achieve that only with standard APIs. Just avoid scaling down the bitmap at once.

    Bitmap bitmap = BitmapFactory.decodeStream(stream);
    
    :
        
    Matrix m = new Matrix();
    m.setScale(0.5F, 0.5F);
    while (bitmap.getWidth() > 256)
    {
        Bitmap bitmap_half = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m, true);
        bitmap.recycle();
        bitmap = bitmap_half;
    }
    
    imageView.setImageBitmap(bitmap);
    

    Result:

    Result

    How this works:

    Since the filter is short-ranged (primarily designed for scaling up e.g. bilinear or bicubic), it's useless for scaling down (=discrete resampling) in general cases. However it does refer neighboring pixels for calculating new pixel colors. So by avoiding too sparse resampling, it's possible to make it work as a smoothing filter for scaling down. maybe.