Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS UIImageView scaling image down produces aliased image on iPad 2

I am using UIImageView to display thumbnails of images that can then be selected to be viewed at full size. The UIImageView has its content mode set to aspect fit.

The images are usually scaled down from around 500px x 500px to 100px x 100px. On the retina iPad they display really well while on the iPad2 they are badly aliased until the size gets closer to the native image size.

Examples:

Original Image

Original Image

Retina iPad 100x100

Retina iPad rendering at 100px x 100px

iPad 2 100x100

iPad 2 rendering at 100px x 100px

The difference between iPad 2 and new iPad might just be the screen resolution or could be that the GPU is better equipped to scale images. Either way, the iPad 2 rendering is very poor.

I have tried first reducing the image size by creating a new context, setting the interpolation quality to high and drawing the image into the context. In this case, the image looks fine on both iPads.

Before I continue down the image copy/resize avenue, I wanted to check there wasn't something simpler I was missing. I appreciate that UIImage isn't there to be scaled but I was under the impression UIImageView was there to handle scaling but at the moment it doesn't seem to be doing a good job scaling down. What (if anything) am I missing?

Update: Note: The drop shadow on the rendered / resized images is added in code. Disabling this made no difference to the quality of the scaling.

like image 554
howard10 Avatar asked Oct 04 '12 15:10

howard10


2 Answers

Another approach I've tried that does seem to be improving things is to set the minificationFilter:

[imageView.layer setMinificationFilter:kCAFilterTrilinear] 

The quality is certainly improved and I haven't noticed a performance hit.

like image 177
howard10 Avatar answered Sep 22 '22 11:09

howard10


Applying a small minification filter bias can help out with this if you don't want to resample the image yourself:

imageView.layer.minificationFilter = kCAFilterTrilinear imageView.layer.minificationFilterBias = 0.1 

enter image description here

The left image has no filtering applied to it. The right image has a 0.1 filter bias.

Note that no explicit rasterization is required.

Playing around with very small values, you can usually come up with a value that smooths out the scaling artifacts just enough, and it's a lot easier than resizing the bitmap yourself. Certainly, you lose detail as the bias increases, so values even less than 0.1 are probably sufficient, though it all depends on the size the image view's frame that's displaying the image.

Just realize that trilinear filtering effectively enables mipmapping on the layer, which basically means it generates extra copies of the bitmap at progressively smaller scales. It's a very common technique used in rendering to increase render speed and also reduce scaling aliasing. The tradeoff is that it requires more memory, though the memory usage for successive downsampled bitmaps reduces exponentially.

Another potential advantage to this technique, though I have not tried it myself, is that you can animate minificationFilterBias. So if you're going to be scaling an image view down quite a lot as part of an animation, consider also animating the filter bias from 0.0 to whatever small value you've determined is appropriate for the scaled down size.

Finally, as others have noted, if your source image is very large, this technique isn't appropriate if overused, because Core Animation will always keep around the original bitmap. It's better to resize the image then discard the source image instead of using mipmapping in most cases, but for one-offs or cases where your image views are going to be deallocated quickly enough, this is fine.

like image 27
CIFilter Avatar answered Sep 19 '22 11:09

CIFilter