Quality Problems When Resizing an Image at Runtime

Quality problems when resizing an image at runtime

After experimenting I have finally found a way to do this with good quality results. I'll write this up for anyone that might find this answer helpful in the future.

To solve the first problem, the artifacts and weird dithering introduced into the images, you need to insure your image stays as a 32-bit ARGB_8888 image. Using the code in my question, you can simply add this line to the options before the second decode.

options.inPreferredConfig = Bitmap.Config.ARGB_8888;

After adding that, the artifacts were gone but edges throughout the images came through jagged instead of crisp. After some more experimentation I discovered that resizing the bitmap using a Matrix instead of Bitmap.createScaledBitmap produced much crisper results.

With those two solutions, the images are now resizing perfectly. Below is the code I am using in case it benefits someone else coming across this problem.

// Get the source image's dimensions
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(STRING_PATH_TO_FILE, options);

int srcWidth = options.outWidth;
int srcHeight = options.outHeight;

// Only scale if the source is big enough. This code is just trying to fit a image into a certain width.
if(desiredWidth > srcWidth)
desiredWidth = srcWidth;



// Calculate the correct inSampleSize/scale value. This helps reduce memory use. It should be a power of 2
// from: https://stackoverflow.com/questions/477572/android-strange-out-of-memory-issue/823966#823966
int inSampleSize = 1;
while(srcWidth / 2 > desiredWidth){
srcWidth /= 2;
srcHeight /= 2;
inSampleSize *= 2;
}

float desiredScale = (float) desiredWidth / srcWidth;

// Decode with inSampleSize
options.inJustDecodeBounds = false;
options.inDither = false;
options.inSampleSize = inSampleSize;
options.inScaled = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap sampledSrcBitmap = BitmapFactory.decodeFile(STRING_PATH_TO_FILE, options);

// Resize
Matrix matrix = new Matrix();
matrix.postScale(desiredScale, desiredScale);
Bitmap scaledBitmap = Bitmap.createBitmap(sampledSrcBitmap, 0, 0, sampledSrcBitmap.getWidth(), sampledSrcBitmap.getHeight(), matrix, true);
sampledSrcBitmap = null;

// Save
FileOutputStream out = new FileOutputStream(NEW_FILE_PATH);
scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
scaledBitmap = null;

EDIT: After continual work on this I have found that the images still aren't 100% perfect. I'll make an update if I can improve it.

Update: After revisting this, I found this question on SO and there was an answer that mentioned the inScaled option. This helped with the quality as well so I added updated the answer above to include it. I also now null the bitmaps after they are done being used.

Also, as a side note, if you are using these images in a WebView, make sure you take this post into consideration.

Note: you should also add a check to make sure the width and height are valid numbers (not -1). If they are, it will cause the inSampleSize loop to become infinite.

android: quality of the images resized in runtime

Please refer to Romain's answer below.

I would like to delete this answer, but I am unable to since it's marked as accepted.


Note that Android [when this answer was originally written, without explicitly requesting 32-bit colour] would only do 16-bit colour, so there may be times when you get unwanted artifacts.

You can also try using the dither options to tell Android to automatically apply dithering which, while not perfect, can help make things look a bit better.

Bad image quality after resizing/scaling bitmap

I had blury images on low screen resolutions until I disabled scaling on bitmap load from resources:

Options options = new BitmapFactory.Options();
options.inScaled = false;
Bitmap source = BitmapFactory.decodeResource(a.getResources(), path, options);

Will PNG image lose quality when resized using HTML or an APP

Try it out and see if you can tell a difference.

If the image has a lot of details, you should be able to tell "the-resized-png-image.png" would look worse than the original. Now, this is assuming my past experience with chrome, the quality may vary from browser to browser due to differences in the way they downscale images.

There is also a possibility of browsers changing the way they downscale images in updates, so it may also vary with browser versions.

Here are other questions that are consistent with my findings:

  • Why does image lose quality when resized on the source but does not when resized using html

  • Make Firefox image scaling down similar to the results in Chrome or IE

  • Blurry downscaled images in Chrome

  • Has image downscaling improved in Safari 6 and 7? (5 used to be slightly blurred)

Doing your own downscaling:

  • HTML5 Canvas Resize (Downscale) Image High Quality?

So, to answer your question: Depends on the browser/app.

Resize image without loss of information

You're constantly losing information from your image after each resizing attempt. If you want solution (like in MS Word) you have to keep somewhere original image but show only resized copy.

The best solution would be creating an object to store original image and making resized copy on demand. You can improve quality of this solution adding simple cache so you don't actually generate another resized copy of your image for every request but only if your application demands image with different height or width than last time.

I hope I helped you a bit.



Related Topics



Leave a reply



Submit