Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What size to store image on server to use with Android app

I have an Android app that allows the user to upload profile pics. They are stored 300px X 300px on the server.

In the app, I use them in either 40dp X 40dp or sometimes 100dp X 100dp. The 40dp's images are in ListView's. I actually use a very popular third party LazyList to store the images (using an ImageLoader class) in a cache. Here is the exact library.

I simply show image in my adapter like this:

imageLoader.DisplayImage(profileUrl, holder.iv1);

I take the web URL and display it directly into the ImageView 40dp x 40dp.

Sometimes I notice image degradation. Where the image is partially loaded, then is corrupted.

One theory is that going from a large image on the server and trying to store it in a small area in the actual app, then doing this many times in a ListView, is causing some loading issues.

The question: What is the best way to handle this situation when you have a much larger image in the server than you need to display? I am assuming I may need to use BitMapFactory or a similar class to build a new image. But I am not sure. I feel like I am missing a step.

Here is an example of an image in a ListView that has become corrupted, notice this does not happen to all. (And yes that is Tobias from Arrested Development.)

Follow-up: And how do we take in consideration file size for xxhdpi, xhdpi, etc when the image is coming from server and not the resources folder?

enter image description here

like image 557
TheLettuceMaster Avatar asked May 06 '14 21:05

TheLettuceMaster


People also ask

What size should images be for app?

If you want the In-App to appear like a modal, you need to upload a square image, with a width of 1200px. If you want the In-App to appear like a fullscreen, you need to upload an image with a 2:1 ratio (for example 1200x600 pixels).

What is the recommended image format in Android?

Android 12 (API level 31) and higher support images that use the AV1 Image File Format (AVIF). AVIF is a container format for images and sequences of images encoded using AV1. AVIF takes advantage of the intra-frame encoded content from video compression.

Which of the following format is used for saving images in Android application?

Compressed JPEG format. YCbCr format, used for video. YCrCb format used for images, which uses the NV21 encoding format.


1 Answers

The library you are using looks like it is barely maintained anymore (last update is at least a year old). There are several newer and likely better libraries that solve the same problem. My favorite is Square's Picasso. It is very simple to use and solves the image loading inside a ListView problem very well.

To more directly answer some of your questions:

What is the best way to handle this situation when you have a much larger image in the server than you need to display?

You need to subsample the Bitmap down to the target size. Google has a pretty good write up on all of this here.

First you have to decode the bitmap setting the inJustDecodeBounds boolean to get the bitmap size.

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;

Then you can compute your sample size based on your target height and width.

public static int calculateInSampleSize(
            BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        final int halfHeight = height / 2;
        final int halfWidth = width / 2;

        // Calculate the largest inSampleSize value that is a power of 2 and keeps both
        // height and width larger than the requested height and width.
        while ((halfHeight / inSampleSize) > reqHeight
                && (halfWidth / inSampleSize) > reqWidth) {
            inSampleSize *= 2;
        }
    }

    return inSampleSize;
}

Then you can use the computed sample size to load the down sampled Bitmap. The final code would look something like

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
        int reqWidth, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
}

And how do we take in consideration file size for xxhdpi, xhdpi, etc when the image is coming from server and not the resources folder?

You can compute the target pixel size you want to downsize your bitmap to using the following snippet:

float pixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, "10", context.getResources().getDisplayMetrics());

TL;DR

Use Square's Picasso and it will solve all of your problems.

like image 51
James McCracken Avatar answered Nov 02 '22 02:11

James McCracken