tliebeck
tliebeck

Reputation: 836

Cleanly down-scaling images in Android: can it be done?

I'm having trouble cleanly down-scaling images on Android. I'm looking to scale small PNG images between arbitrary sizes of about 10-100% of their original size.

I've created a sample image to demonstrate the problem and exacerbate the unusual behaviors I'm seeing in Android's image scaler:

NOTE: you will want to right-click on the image and view it directly...this page may downscale the image again The above image is a screenshot from an Android device with some annotations added. I've also added the same images in a second column on the left side showing how they are rendered with a linear scaling by "The GIMP" (GNU Image Manipulation Program).

The base image consists of a checkerboard pattern background of red and blue pixels. On that background I've drawn some 1px-wide yellow lines and fairly thin green text. The image is 288x288 pixels.

When scaling the image to 1/3 of its original dimensions, Android seems to simply grab one in nine pixels, throwing out all other data. Some of the yellow lines disappear entirely as a result. Remarkably, the checkerboard pattern remains intact (which is simply a result of every 3rd pixel being used).

When scaling the image to a dimension of near-but-not-exactly 50% of its original size, e.g., 142x142 or 143x143, the scaler creates some fairly large anomalies/artifacts on the image.

At 50% size (144x144), the image looks correct.

The test image does bring out the worst of the image scaler, but "normal" PNG icon images are severely impacted as well. From 10-33% or so the images aren't properly resampled, and thus appear extremely "bitmapped". And certain larger size images have very strange anomalies in them at certain sizes.

If anyone knows a means to disable this strange scaling behavior, even at a performance cost, I'd greatly appreciate knowing about it. It can certainly be solved by writing an algorithm that works directly on the pixels of bitmaps, but I'm hopeful that isn't the only option.

Also noteworthy is the fact that all image work is being done with ARGB_8888 Bitmap.Configs. I've tried manipulating image size by setting maxwidth/maxheight on ImageViews, by using Bitmap.createScaledBitmap(), and by using Bitmap.createBitmap with a Matrix. All attempts have this same result. Bitmap filtering is enabled.

Thanks again for any suggestions!

Upvotes: 4

Views: 700

Answers (1)

ElementW
ElementW

Reputation: 824

Using Bitmap.createScaledBitmap() and Bitmap.createBitmap with a Matrix is the same; see the source for Bitmap.createScaledBitmap (which hasn't changed since Android 2).

On Android 4.0+, using a matrix (as in Bitmap.createScaledBitmap) allows hardware-accelerated operations if enabled (enabled by default on 4.1+ IIRC), thus we doesn't have direct control over what is being done and how it is done.

That means you'll have to implement your own scaling method using the desired (here, linear) filtering; either by pixel processing; or using OpenGL ES with the good filter, but it may not be available on all devices.

Upvotes: 2

Related Questions