Optimizing image size for quality display on image view - android

I want to download image from my server and display it on an image view.
My main concern is to not damage the image quality on different devices (with different screen sizes, resolutions and densities)
I want to figure out exactly how to measure what image size i need to fit the image view keeping its quality
For the sake of the question,
Say i have an image view with 100dp * 100dp size what image resolution do i need to download in order to keep the quality for hdpi, xhdpi, xxhdpi and xxxhdpi devices?
I already know how to get the resolution and desisty of the device
DisplayMetrics displaymetrics = new DisplayMetrics();
WindowManager windowManager = (WindowManager) m_context.getSystemService(Context.WINDOW_SERVICE);
windowManager.getDefaultDisplay().getMetrics(displaymetrics);
int height = displaymetrics.heightPixels;
int wwidth = displaymetrics.widthPixels;
Log.d(Utils.TAG,"displaymetrics : Hieght: "+ height + " width: " + wwidth);
switch (m_context.getResources().getDisplayMetrics().densityDpi) {
case DisplayMetrics.DENSITY_LOW:
Log.d(Utils.TAG,"Low desity");
break;
case DisplayMetrics.DENSITY_MEDIUM:
Log.d(Utils.TAG,"medium desity");
break;
case DisplayMetrics.DENSITY_HIGH:
Log.d(Utils.TAG,"high desity");
break;
case DisplayMetrics.DENSITY_XHIGH:
Log.d(Utils.TAG,"xhigh desity");
break;
case DisplayMetrics.DENSITY_XXHIGH:
Log.d(Utils.TAG,"xxhigh desity");
break;
case DisplayMetrics.DENSITY_XXXHIGH:
Log.d(Utils.TAG,"xxxhigh desity");
break;
}

Low density (ldpi): 75x75
Medium density (mdpi): 100x100, baseline
High density (hdpi) 150x150
Extra high density (xhdpi) 200x200
Extra x2 high density (xxhdpi) 300x300
Extra x3 high density (xxxhdpi) 400x400
See Range of screens supported | Android Developers

Related

What image size should I ask from UI developer?

I have an ImageView with these attributes:
android:layout_width="match_parent"
android:layout_height="160dp"
UI developer asks me for the size of Image that I want in px. What size should I ask? Should I ask different size for different devices?
Note
I don't have an ImageView with specific height and width. My ImageView width is match_parent not a specific width.
All the answers say that I should use a converter, How can I convert match_parent to px?
According to answers, I should ask about six images, shouldn't I?
You should give highest screen density in pixels to your UI developer then scale to lower densities on your own.
Normally an android app will support screen densities ldpi at min and xxxhdpi at max.
Step1: If you want the image size is 160 x 160 dp then give the UI developer the highest image size associated with max screen density.
160 x 4 = 640x640 px (why multiply by 4? I will explain later)
Step 2: Scale the image 640x640 px to lower size based on screen densities
ldpi: 160 x 0.75 = 120x120 px
mdpi: 160 x 1 = 160x160 px
hdpi: 160 x 1.5 = 240x240 px
xhdpi: 160 x 2 = 320x320 px
xxhdpi: 160 x 3 = 480x480 px
xxxhdpi: 160 x 4 = 640x640 px
Tips: Find your image size corresponds with mdpi density screen (known as base density or 1X density) then scale to other densities by the following formula
Update: From https://material.io/tools/devices/, screen size for base density screen is 360x640 px. So your ImageView size will be 360x160 px on 1X density screen.
ldpi: 270x120 px
mdpi: 360x160 px
hdpi: 540x240 px
xhdpi: 720x320 px
xxhdpi: 1280x480 px
xxxhdpi: 1440x640 px
Why are you not using Vector drawable?
Why use Vectors?
Data can be represented in original resolution without generalization.
Graphical outputs of the images are more pleasing than the created as raster image
Another very important reason of using vector graphics rather than raster is their size. Vector objects are much smaller than raster image format. If we have the full-size image to update, the vector file might only take few kilobytes of space on your system, where the same image in medium resolution bitmap format might not place on CD ROM.
You should use SVG images in your project.
Create SVG instead of PNG files
Ok, you want to set image height of size 160dp (since it is in dp, this is the size in mdpi). So you to have to ask UI developer to make you image of height 4 times of that. Image Height = 4 * 160. After that you can use Batch drawable importer from android studio, to make image for all differrent resolutions. Hope it helps.
Different Devices has Different sizes
android:adjustViewBounds="true" is automaticaly pickup height of image
so you can this,
<ImageView
android:id="#+id/ivImage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"/>
You should go with 1440x640 for largest size.
If you want to support multiple devices with multiple images you can have 5 standard image slicings.
mdpi : 360x160
hdpi : 540x240
xhdpi : 720x320
xxhdpi : 1080x480
xxxhdpi : 1440x640
I came up with these image sizes, because if you look at most common display sizes, largest of them is 1440x2960 of Samsung Galaxy S8. (I am aware of 2160x3840, but it is not main stream and I would even say its outright crazy).
In your case you have width set to match_parent which in every case of largest (or even custom) DPI, will be 1440px at most, so you can be damn sure that 99% of the time it will not exceed it. (Most current devices with 9:18 or 9:X ratio devices also feature 1440 px width in almost every case if they go more than 1080. Check out resolutions of latest devices released.)
So you can settle at 1440 px of width. Now height of your ImageView is 160dp. Which can be (as suggested by everyone else) 160*4 = 640 px for largest default DPI xxxhdpi. The reason that you should consider height for standard dpis because it is fixed to some dp (160dp) and this may change for custom dpi devices, so you can support maximum devices with this, 640px size. Hope I was clear about size suggestion.
To provide good graphical qualities on devices with different pixel densities, you should provide multiple versions of each bitmap in your app - one for each density bucket, at a corresponding resolution. Otherwise, Android must scale your bitmap so it occupies the same visible space on each screen, resulting in scaling artifacts such as blurring.
Figure 1. Relative sizes for bitmaps at different density sizes
There are several density buckets available for use in your apps. Table 1 describes the different configuration qualifiers available and what screen types they apply to.
Table 1. Configuration qualifiers for different pixel densities.
To create alternative bitmap drawables for different densities, you should follow the 3:4:6:8:12:16 scaling ratio between the six primary densities. For example, if you have a bitmap drawable that's 48x48 pixels for medium-density screens, all the different sizes should be:
36x36 pixels (0.75x) for low-density (ldpi)
48x48 pixels (1.0x baseline) for medium-density (mdpi)
72x72 pixels (1.5x) for high-density (hdpi)
96x96 pixels (2.0x) for extra-high-density (xhdpi)
144x144 pixels (3.0x) for extra-extra-high-density (xxhdpi)
192x192 pixels (4.0x) for extra-extra-extra-high-density (xxxhdpi)
Then, place the generated image files in the appropriate subdirectory under res/ and the system will pick the correct one automatically based on the pixel density of the device your app is running on:
res/
drawable-xxxhdpi/
awesome-image.png
drawable-xxhdpi/
awesome-image.png
drawable-xhdpi/
awesome-image.png
drawable-hdpi/
awesome-image.png
drawable-mdpi/
awesome-image.png
Then, any time you reference #drawable/awesomeimage, the system selects the appropriate bitmap based on the screen's dpi. If you don't provide a density-specific resource for that density, the system picks the next best match and scales it to fit the screen.
Tip: If you have some drawable resources that the system should never scale (perhaps because you perform some adjustments to the image yourself at runtime), you should place them in a directory with the nodpi configuration qualifier. Resources with this qualifier are considered density-agnostic and the system will not scale them.
Official Source: Screen Densities
This is an official size chart given by Material Design Or you can ask for xxxhpdi which is 1440 x 2960 px based image and use this site to get all the images with various densities.
When you get images with various densities, no need to specify height and width in px layout. Keep the images with same name and use match_parent. Android will automatically choose the image according to the device.
try this source code
Display display = getWindowManager().getDefaultDisplay();
String displayName = display.getName(); // minSdkVersion=17+
Log.i(TAG, "Pantalla = " + displayName);
// Tamaño en píxeles
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
Log.i(TAG, "Ancho = " + width);
Log.i(TAG, "Alto = " + height);
// dpi
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int heightPixels = metrics.heightPixels;
int widthPixels = metrics.widthPixels;
int densityDpi = metrics.densityDpi;
float xdpi = metrics.xdpi;
float ydpi = metrics.ydpi;
Log.i(TAG, "Ancho en píxeles = " + widthPixels);
Log.i(TAG, "Alto en píxeles = " + heightPixels);
Log.i(TAG, "Densidad dpi = " + densityDpi);
Log.i(TAG, "x dpi = " + xdpi);
Log.i(TAG, "y dpi = " + ydpi);
// Deprecated
int screenHeight = display.getHeight();
int screenWidth = display.getWidth();
Log.i(TAG, "Alto de pantalla = " + screenHeight);
Log.i(TAG, "Ancho de pantalla = " + screenWidth);
// Orientación
int orientation = getResources().getConfiguration().orientation;
Log.i(TAG, "Orientación = " + orientation);
Yes you would need to take multiple images for different screen sizes, if you do not want to use vectors and wish to use images (png,etc.) instead.
Since you have width as match_parent, in this case take the images with the max screen width for different density buckets:-
MDPI -> 320 px
HDPI -> 480 px
XHDPI -> 640 px
XXHDPI -> 1080 px
One dp is a virtual pixel unit that's roughly equal to one pixel on a medium-density screen (160dpi; the "baseline" density).
According to the above statement , you the find the heigth for the images :-
MDPI -> 160 px
HDPI -> 240 px
XHDPI -> 320 px
XXHDPI -> 480 px
How to calculate :-
Consider, 160 dp would be 160 px in mdpi(1x).
160 dp would be 240 px in hdpi (1.5x).
and so on..
OR using the function px = dp * (dpi / 160)
For HDPI , dpi is 240
px = 160 * 240/160
px = 240
For dpi list refer this
This helped me to figure it out, and make things clear
You can refer this
ldpi: 270x120 px
mdpi: 360x160 px
hdpi: 540x240 px
xhdpi: 720x320 px
xxhdpi: 1280x480 px
xxxhdpi: 1440x640 px

Difficulty in xhdpi screen resolution

eg:- Samsung Galaxy S III (1280 x 720) and Samsung Galaxy S 4 (1920 x 1080) uses resources from xhdpi. I'm hvaing 3 icons in a row aligned left, centre and right with size of (256 x 256) but it gets overlapped on SIII and on s4 their is a wide gap between icons.
What should be the size of icon to fit it as 1/3 of screen's width or is there any workaround to do so?
here is sample snapshot of layout after following mentioned solutions.
http://postimg.org/image/97aabr2wd/
its getting scaled properly but leaves space on top and bottom. I want result similar to snapshot in this image http://postimg.org/image/r6ico4vil/
where 1, 2 and 3 should be of same height. Its just a space after 3 consecutive red, green and blue images. how to achieve this? thanks in advance.
The samsung Galaxy S4 is XXHDPI, and not XHDPI.
Here is a way to check for the device density :
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int density = dm.densityDpi;
switch(density)
{
case DisplayMetrics.DENSITY_LOW:
Toast.makeText(context, "ldpi", Toast.LENGTH_SHORT).show();
break;
case DisplayMetrics.DENSITY_MEDIUM:
Toast.makeText(context, "mdpi", Toast.LENGTH_SHORT).show();
break;
case DisplayMetrics.DENSITY_HIGH:
Toast.makeText(context, "hdpi", Toast.LENGTH_SHORT).show();
break;
case DisplayMetrics.DENSITY_XHIGH:
Toast.makeText(context, "xhdpi", Toast.LENGTH_SHORT).show();
break;
case DisplayMetrics.DENSITY_XXHIGH:
Toast.makeText(context, "xxhdpi", Toast.LENGTH_SHORT).show();
break;
}
I took if from this answer.
About having 3 images filling the whole screen width you can use a linear layout with layout weight.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:weightSum="9" >
<ImageView
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="3" />
<ImageView
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="3" />
<ImageView
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="3" />
</LinearLayout>
In android-
px = dp * (dpi / 160)
1.So in your first question 960dp x 720dp at 320dpi means 1920px x 1440px for xlarge screen in landscape mode using above formula.
2.640dp x 480dp at 240dpi means 960px x 720px for large screen in landscape mode.
enter link description here
You can't guaranty a 1/3 of the screen with just an image. even if two devices have the same dpi (or XHdpi) it doesn't mean they have the same size.
The only way to do that is with code or in the layout xml.
Try use wights.
android:layout_width="0dp"
android:layout_weight="0.33"
with this code you guaranty that the view will be a 1/3 of the screen if width.

Android drawable for Samsung Galaxy S4 and Nexus 10

I have an image that is the background of one activity in my app.
For the Samsung Galaxy S4 this image should be 1920x1080 and placed at the xxhdpi folder.
For the Nexus 10 this image should be 2560x1600 and placed at the xhdpi folder.
It's nonsense to place an image bigger in the xhpdi folder than an image placed at the xxhdpi folder.
And because that I believe that I misunderstood something.
Can someone explain what I misunderstood?
--edit--
For all the answer questioning if the nexus10 is really xhdpi and the S4 xxhdpi:
The answer of prijupaul is good, but I don't have any Nexus 10 or Galaxy S4 to test. I discovered the resolution trying to create AVDs for both, in the device configuration creation it says what configuration it one will be.
The resource classes 'hdpi', 'xhdpi' and 'xxhdpi' have nothing to do with resolution (width and height in plain pixels) but everything to do with density (number of pixels per inch of screen).
The S4 has a lower resolution but can have a higher density because it screen is smaller.
I think it is quite well explained in the documentation (developer.android.com). Check that for more details.
You should then use another qualifier than xhdpi if resolution does really matter. You can use for example drawable-sw720dp (targets 10" tablets).
My personal opinion though is that you should just have a version for each aspect ratio in the biggest size. Then compute that aspect ratio at runtime and pick the best image from assets.
Isnt S4 is xhdpi? Did you verify using
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int density = dm.densityDpi;
switch(density)
{
case DisplayMetrics.DENSITY_LOW:
Toast.makeText(context, "ldpi", Toast.LENGTH_SHORT).show();
break;
case DisplayMetrics.DENSITY_MEDIUM:
Toast.makeText(context, "mdpi", Toast.LENGTH_SHORT).show();
break;
case DisplayMetrics.DENSITY_HIGH:
Toast.makeText(context, "hdpi", Toast.LENGTH_SHORT).show();
break;
case DisplayMetrics.DENSITY_XHIGH:
Toast.makeText(context, "xhdpi", Toast.LENGTH_SHORT).show();
break;
case DisplayMetrics.DENSITY_XXHIGH:
Toast.makeText(context, "xxhdpi", Toast.LENGTH_SHORT).show();
break;
}
This does not answer the question. But, This could will be useful to double check it again.
I think it's about to 'PPI'. Galaxy s4 has 441 ppi but Nexus 10 has 300 ppi.
Are you sure image for nexus10 should be in xhdpi folder?
Nexus10 has 300ppi,which is different to dip.
Visit Android XXHDPI resources
It should be like this,
s4:xhdpi
nexus10:xxhdpi

How to change image according resolution?

I am working on an android application. i have used different layout folder. Like layout,layout-large,layout-xlarge. So that it can adjust for all resolutions. But i am setting images dynamically in activity. How can i change them according to screen resolution? How too big image will replace smaller if we change resolution?
Android works with density buckets, which go from l(low)dpi to xx(extra extra)h(high)dpi.
You want to create different versions of your images in folders as
drawable-ldpi
drawable-mdpi
drawable-hdpi
drawable-xhdpi
and drawable-xxhdpi if you want to support the Nexus 10.
That's kind of loose from the layout-large folders, which enable you to define different layouts for different sizes.
2 pretty different things, which you can read much more about at
screen practices in Android.
=======
Edit; Seems this wasn't exactly the question.
If you're doing it 'the right way' the Android system will choose the correct image for you, even when adding them dynamically (you can still call R.drawable.my_image from java code).
If for some reason you do have to choose, you can simply check for the current density with something like (a little outdated);
public String getDensity() {
String density;
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
// will either be DENSITY_LOW (120) , DENSITY_MEDIUM (160) or
// DENSITY_HIGH (240)
switch (dm.densityDpi) {
case 120:
density = "ldpi";
break;
case 160:
density = "mdpi";
break;
case 240:
density = "hdpi";
break;
// use hdpi as default, because flurry shows this will be suited for
// most of our users.
default:
density = "hdpi";
break;
}
return density;
}

Remote images and sizes for hdpi/mdpi/ldpi etc

So on device there's the drawable directories for hdpi, mdpi, ldpi etc...
Now lets say I want to download images from the internet to view in the app (on the fly).
Can I have the three different densities of image available for download? Is there some way I can check if the current device is hdpi/mdpi/ldpi and download the right resolution accordingly? Or is it much more simple than that?
I guess if I download a high res image onto a hdpi phone then it will assume its a mdpi image that just has larger dimensions than intended?
Thanks
This is how you get the density programatically
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
switch(metrics.densityDpi){
case DisplayMetrics.DENSITY_LOW:
break;
case DisplayMetrics.DENSITY_MEDIUM:
break;
case DisplayMetrics.DENSITY_HIGH:
break;
}

Categories

Resources