2

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?

spierce7
  • 12,064
  • 11
  • 56
  • 91
  • Is the source of the image SVG or bitmap when you put through the "web-based image resizer". – Morrison Chang May 17 '21 at 03:20
  • png. It's the exact same file uploaded and labeled "Original Image". I just double checked, and it appears that StackOverflow doesn't seem to have modified the image. The original image is 4096 x 4096, and I'm displaying it as 214 x 214px – spierce7 May 17 '21 at 03:24
  • 1
    This is not an AA problem. It's due to the low-quality filter (algorithm) Android API uses when scaling images. See https://stackoverflow.com/questions/37763257/android-bitmap-resizing-using-better-resampling-algorithm-than-bilinear-like-l – H.D. May 17 '21 at 04:39

2 Answers2

1

The lack of smoothness in the trial image indicate some anti-aliasing is missing.

A relatively quick search show that Sub-pixel antialiasing rules can get complicated.

The next thing is to figure out which tool the "web-based image resizer" used to generate the trial image.

Nine times out of ten (or more) the website would be using FOSS software, which would lead to ImageMagick

A quick run of your source image through ImageMagick with a command like:

convert SO_source_image.png -resize 5% SO_result.png

Results in this similar but not exact (205x205 pixels) image:

Converted image

At this point you could either dive into the algorithms used by ImageMagick (see the command line options for the variety of methods) or see if you can get a similar result with an existing port like: cherryleafroad/Android-ImageMagick7 or paulasiimwe/Android-ImageMagick

Morrison Chang
  • 10,296
  • 3
  • 32
  • 60
1

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.

ardget
  • 1,116
  • 1
  • 2
  • 3
  • This works pretty well. It's not perfect, as it requires the creation of several smaller and smaller bitmaps, but it also achieves it without adding some external native library that's 5+MB. – spierce7 May 17 '21 at 14:52
  • 50% is also the perfect scaling number it seems. Anything beyond that and the jaggedness starts to come back. – spierce7 May 17 '21 at 15:14
  • 1
    Here's a gist of the Picasso Transformer I made to handle this for me - https://gist.github.com/ScottPierce/ca6d29233506695b3ee7ee1174c9485b – spierce7 May 18 '21 at 03:11
  • ok, great. thank you. – ardget May 18 '21 at 11:02