Search code examples
androidiosimagescalingimage-scaling

Why different image sizes for different density buckets if Android/iOS scales them?


I'm working on an Android+iOS app where we need some images. I want the images to have a "touchable" size, say 15 mm on all devices. For devices with bigger screens I want to fit more images, not make the images bigger.

My problem is how to select a resolution (in pixels) for the images.

To make the images 15 mm on all devices there are two strategies:

  1. Supply images in different resolutions and select the closest matching
  2. Scale them so that they fit

A pro with the first strategy is that it's the only way to get pixel-perfect images. But there are cons as well:

In Android there are different "density buckets": ldpi, hdpi, mdpi, xhdpi, etc. Different devices belong to different density buckets. But the precise density may still vary greatly. So if I decide on the first strategy and supply the image in correct sizes for xhdpi (320dpi) a device with 350 or 300 dpi may still belong to that density bucket and the resulting image will vary in size.

Because of that I think the second strategy, scale the images so that they fit, is better. But then I wonder why should I supply the images in different resolutions? And what is the "optimal resolution" (given a size requirement in mm) for each density bucket?

I understand that an image to be displayed on a xxxhdpi display could be more detailed than an image on a low resolution display. So I can see that there is meaning in supplying different images for each density bucket. But I can't see why they should have different resolutions if they are to be scaled anyway?

Why can't all density buckets have images of size 1024x1024 for example? And, given that the originals are the same, why do I even have to supply different images for different density buckets?


Solution

  • So if I decide on the first strategy and supply the image in correct sizes for xhdpi (320dpi) a device with 350 or 300 dpi may still belong to that density bucket and the resulting image will vary in size.

    Only if you set your ImageView (or whatever widget is using the image) to be sized based on wrap_content. If you set the widget size to be based upon other dimensions (e.g., 15mm), then Android will choose the image based on density, then scale to fix the specified dimensions.

    why should I supply the images in different resolutions?

    Quality. Apparent image quality decreases the more you scale the image. This is particularly true for upscaling an image, though you will encounter problems downscaling as well.

    Also, particularly on Android 1.x/2.x devices, this sort of scaling was done using application memory (heap space); avoiding this sort of scaling would be beneficial for memory use. AFAIK, on modern devices, this scaling is done on the GPU, which helps somewhat. However, on the whole, you want to use the smallest resolution bitmap as possible as input that will give you a visual result that meets your needs and user expectations. This is why we use lower-resolution bitmaps for lower-density devices — scaling downward is guaranteed to waste RAM, and not all users have high-end devices with lots of RAM.

    And what is the "optimal resolution" (given a size requirement in mm) for each density bucket?

    Density is expressed in dots, or pixels, per inch. Convert your mm value to inches, then multiply by a density to get a value in pixels.

    Why can't all density buckets have images of size 1024x1024 for example?

    You are absolutely welcome to do that, if somehow that gives you the results that you want, and it does not waste disk space or heap space for the user.