Thursday, August 23, 2012

[Android] Which alternative image resource will be chosen by the system?

This is a note from my experiments.

Let's say I've supplied images only in drawable-xhdpi and drawable-hdpi folders and now my app is running on device with mdpi screen density. My question is which folder will be chosen by Android system to scale an image to display in mdpi device. Below is a note from my experiments about how Android find the best matching image resource.

Drawable folders structure
drawable-xhdpi (density = 320)
drawable-hdpi (density = 240)
drawable-mdpi (density = 160)
drawable-ldpi (density = 120)

CAUTION: Screen density qualifiers are not supported in Android 1.5 and lower.

Code snippet
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
            
Log.v(TAG, "Options value before decode Bitmap");
Log.v(TAG, String.format("inDensity %d, inScaled %b, inScreenDensity %d, inTargetDensity %d", options.inDensity, options.inScaled, options.inScreenDensity, options.inTargetDensity));
            
BitmapFactory.decodeResource(getResources(), R.drawable.my_image, options);
            
Log.v(TAG, "Options value after decode Bitmap");
Log.v(TAG, String.format("inDensity %d, inScaled %b, inScreenDensity %d, inTargetDensity %d", options.inDensity, options.inScaled, options.inScreenDensity, options.inTargetDensity));

Experiment #1 Does the system scales image to matches screen density?

This experiment try to answers the question "Does the system chooses image from another folder if there is no image for current device screen density?"

A.      Supply only image in xhdpi folder.

Log result

o    On xhdpi device
inDensity 320, inScaled true, inScreenDensity 0, inTargetDensity 320
Meaning
System chooses image from xhdpi folder (inDensity = 320) for xhdpi density (inTargetDensity = 320)
 
o    On hdpi device
inDensity 320, inScaled true, inScreenDensity 0, inTargetDensity 240
Meaning
System chooses image from xhdpi folder (inDensity = 320) and scales it to current hdpi density (inTargetDensity = 240)


Conclusion from experiment #1
System scales image to matches current screen density.


Experiment #2 Does the system chooses bitmap from the most closely matches drawable folder?

This experiment try to answers the question "Does the system choose image from drawable folder that most closely matches device screen density?"

A.      Supply image in xhdpi and hdpi

Log result

o    On mdpi device
inDensity 240, inScaled true, inScreenDensity 0, inTargetDensity 160

Meaning
System chooses image from hdpi folder (inDensity = 240) which is the most closely matches current mdpi density (inTargetDensity = 160)
 
o    On ldpi device
inDensity 240, inScaled true, inScreenDensity 0, inTargetDensity 120
 
Meaning
System chooses image from hdpi folder (inDensity = 240) which is the most closely matches current ldpi density (inTargetDensity = 120) than xhdpi.

B.      Supply image in hdpi and mdpi

Log result
 
o    On xhdpi device
inDensity 240, inScaled true, inScreenDensity 0, inTargetDensity 320

Meaning
System chooses image from hdpi folder (inDensity = 240) which is the most closely matches current xhdpi density (inTargetDensity = 320) than mdpi.
 
o    On ldpi device
inDensity 160, inScaled true, inScreenDensity 0, inTargetDensity 120

Meaning
System chooses image from mdpi folder (inDensity = 160) which is the most closely matches current ldpi density (inTargetDensity = 120) than hdpi.
 
C.      Supply image in mdpi and ldpi

Log result

o    On xhdpi device
inDensity 160, inScaled true, inScreenDensity 0, inTargetDensity 320

Meaning
System chooses image from mdpi folder (inDensity = 160) which is the most closely matches current xhdpi density (inTargetDensity = 320) than ldpi.

o    On hdpi device
inDensity 160, inScaled true, inScreenDensity 0, inTargetDensity 240

Meaning
System chooses image from mdpi folder (inDensity = 160) which is the most closely matches current hdpi density (inTargetDensity = 240) than ldpi.

D.      Supply image in xhdpi and ldpi

Log result

o    On hdpi device
inDensity 320, inScaled true, inScreenDensity 0, inTargetDensity 240

Meaning
System chooses image from xhdpi folder (inDensity = 320) which is the most closely matches current hdpi density (inTargetDensity = 240) than ldpi
 
o    On mdpi device
inDensity 320, inScaled true, inScreenDensity 0, inTargetDensity 160

Meaning
System chooses image from xhdpi folder (inDensity = 320) which is not the most closely matches current mdpi density (inTargetDensity = 160).
In this case, the chosen image should be the image in ldpi folder (density = 120) which is the most closely matches mdpi but system picks an image from xhdpi folder. This could be the effect from scaling factor which describes in Android document that system prefer to scales down the image.


Conclusion from experiment #2

·         System is not always choose the image from the most closely matches folder. In the experiment #2-D mdpi device case, system chooses to scale down the image from xhdpi folder instead of scale up the image from ldpi folder which is the most closely matches. This could be the effect from the scaling factor which scale down the image can produces better image quality than scale it up. We will try experiment more about scaling factor in the experiment #3.

·         Another interesting case is experiment #2-B ldpi device case. The system chooses image from mdpi folder and scale it down. This should not be a problem since mdpi is the most closely matches but, according to this Android document which describes this case that system would prefer to scale down the hdpi image instead of mdpi one because of scaling hdpi to ldpi by a factor of 0.5 has fewer artifacts compared to scaling mdpi to ldpi by a factor of 0.75. I'm not sure why my experiment result is conflicted with the one in Android document perhaps I'm running my test case on Android emulator (Froyo) or something else?

Experiment #3 Which one to be chosen? Scale up or scale down?

This experiment try to find the answer in the situation that the system cannot find an image for the current screen density but the images exist in drawable folders which are next to the current device screen density folder  e.g. current screen density is hdpi but the images are stored in drawable-xhdpi and drawable-mdpi, system will scale down an image from xhdpi folder or scale up an image from mdpi folder?

A.      Supply image in xhdpi and ldpi (experiment #2-D)

Log result

o    On hdpi device
inDensity 320, inScaled true, inScreenDensity 0, inTargetDensity 240

Meaning
System scales down the image from xhdpi folder (inDensity = 320) to current hdpi density (inTargetDensity = 240).

o    On mdpi device
inDensity 320, inScaled true, inScreenDensity 0, inTargetDensity 160

Meaning
System scales down the image from xhdpi folder (inDensity = 320) to current mdpi density (inTargetDensity = 160).

B.      Supply image in xhdpi and mdpi

Log result

o    On hdpi device
inDensity 320, inScaled true, inScreenDensity 0, inTargetDensity 240

Meaning
System scales down the image from xhdpi folder (inDensity = 320) to current hdpi density (inTargetDensity = 240).

o    On ldpi device
inDensity 160, inScaled true, inScreenDensity 0, inTargetDensity 120

Meaning
System scales down the image from mdpi folder (inDensity = 160) to current ldpi density (inTargetDensity = 160) which is also the most closely matches.

C.      Supply image in hdpi and ldpi

Log result

o    On mdpi device
inDensity 240, inScaled true, inScreenDensity 0, inTargetDensity 160

Meaning
System scales down image from hdpi folder (inDensity = 240) to current mdpi density (inTargetDensity = 160).

o    On xhdpi device
inDensity 240, inScaled true, inScreenDensity 0, inTargetDensity 320

Meaning
System scales up image from hdpi folder (inDensity = 240) to current xhdpi density (inTargetDensity = 320) which is also the most closely matches.

Conclusion from experiment #3
System prefer to scales down the image.

Experiment #4 Three image candidates.

The goal of this experiment is to determine which image will be chosen by the system if all folders has an image but the current device density folder.

A.      Supply image in xhdpi, hdpi and mdpi

Log result on ldpi device
inDensity 160, inScaled true, inScreenDensity 0, inTargetDensity 120

Meaning
System scales down image from mdpi folder (inDensity = 160) which is most closely matches current ldpi density (inTargetDensity = 120).

B.      Supply image in xhdpi, hdpi and ldpi

Log result
inDensity 240, inScaled true, inScreenDensity 0, inTargetDensity 160

Meaning
System scales down image from hdpi folder (inDensity = 240) to current mdpi density (inTargetDensity = 160).

C.      Supply image in xhdpi, mdpi and ldpi.

Log result
inDensity 320, inScaled true, inScreenDensity 0, inTargetDensity 240

Meaning
System scales down image from xhdpi folder (inDensity = 320) to current hdpi density (inTargetDensity = 240).

D.      Supply image in hdpi, mdpi and ldpi.

Log result
inDensity 240, inScaled true, inScreenDensity 0, inTargetDensity 320

Meaning
System scales up image from hdpi folder (inDensity = 240) which is most closely matches current xhdpi density (inTargetDensity = 320).

Conclusion from experiment #3
System prefer to scales down from the larger image in the most closely matches folder or scales up from the smaller image in the most closely matches folder if there are no image in higher resolution.

Conclusion
From all experiment results, below is the behavior of the Android system when finding best matching image.

Precondition
The desired image does not exist in the drawable folder of the current device screen density.

1.       System chooses the higher resolution image which is most closely matches the current device screen density.
2.       If no higher resolution image exist then chooses the lower resolution image which is most closely matches the current device screen density.