jk jk
jk jk

Reputation: 1075

can i get image file width and height from uri in android?

i can getting the image width through MediaStore.Images.Media normally

but i need to getting the image width and height from image which selected from dropbox

so currently i have following method to getting image size from dropbox

private void getDropboxIMGSize(Uri uri){
    String size = Long.toString(new File(uri.getPath()).length());
    return size;
}

but what i actually need are getting the file width and height value

anyone know how to achieve that?please help!

Upvotes: 52

Views: 60175

Answers (11)

charman
charman

Reputation: 143

If you struggle with getting reverted dimensions - width and height taking place each other - for portrait images, this is an extended solution:

private fun getImageSize(uri: Uri): Size {
    var input = activity?.contentResolver?.openInputStream(uri)!!
    val options = BitmapFactory.Options()
    options.inJustDecodeBounds = true
    BitmapFactory.decodeStream(input, null, options)

    input = activity?.contentResolver?.openInputStream(uri)!!

    var orientation = ExifInterface(input).getAttribute(TAG_ORIENTATION)?.toInt()
    if (orientation == null) {
        orientation = ORIENTATION_NORMAL
    }
    if (orientation == ORIENTATION_ROTATE_90 || orientation == ORIENTATION_ROTATE_270) {
        val outWidth = options.outWidth
        val outHeight = options.outHeight
        options.outWidth = outHeight
        options.outHeight = outWidth
    }

    return Size(options.outWidth, options.outHeight)
}

An important point is that decodeStream closes the inputStream when finishes its job. So it is required to be opened again to be able to get orientation from ExifInterface.

By the way, ExifInterface comes from androidx.exifinterface:exifinterface:x.x.x

Upvotes: 0

Raj Narayanan
Raj Narayanan

Reputation: 3412

This is a concrete working example of the ExifInterface solution proposed by @simplatek, using an extension function on the Uri type:

fun Uri.getImageDimensions(context: Context): Pair<Int, Int> {
    val inputStream = context.contentResolver.openInputStream(this)!!
    val exif = ExifInterface(inputStream)

    val width = exif.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, defaultValue)
    val height = exif.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, defaultValue)

    return Pair(width, height)
}

Upvotes: 1

Oz Shabat
Oz Shabat

Reputation: 1612

If you guys keep getting (0,0) in the width and height, you probably want to decode a stream, and not a file.

It probably because you're trying to read an image from the assets. Try this:

val b = BitmapFactory.decodeStream(context.assets.open("path/in/assets/img.png"))
val width = b.width
val height = b.height

Upvotes: 0

phnghue
phnghue

Reputation: 1686

Please use InputStream:

public int[] getImageSize(Uri uri){
    try {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        InputStream input = this.getContentResolver().openInputStream(uri);
        BitmapFactory.decodeStream(input, null, options);  input.close();
        return new int[]{options.outWidth, options.outHeight};
    }
    catch (Exception e){}
    return new int[]{0,0};
}

It'll return in array form:

int[]{ width , height }

Upvotes: 3

Blackbelt
Blackbelt

Reputation: 157437

private void getDropboxIMGSize(Uri uri){
   BitmapFactory.Options options = new BitmapFactory.Options();
   options.inJustDecodeBounds = true;
   BitmapFactory.decodeFile(new File(uri.getPath()).getAbsolutePath(), options);
   int imageHeight = options.outHeight;
   int imageWidth = options.outWidth;
 
}

no there is no way. You have to create a Bitmap object. if you use the inJustDecodeBounds flag the bitmap would not be loaded in memory. In fact BitmapFactory.decodeFile will return null. In my example uri is the phisical path to the image

Upvotes: 124

Naveen
Naveen

Reputation: 31

For folks having content uri (starting with content://), open an InputStream & decode that stream to avoid getting 0 width and height. I'll use Kotlin

val uri: Uri = ....

val options = BitmapFactory.Options().apply { inJustDecodeBounds = true }
val inputStream = contentResolver.openInputStream(uri)
BitmapFactory.decodeStream(inputStream, null, options)

val width = options.outWidth
val height = options.outHeight

Upvotes: 3

Zain
Zain

Reputation: 40810

The accepted answer returns with me a 0 of width/height, by replacing uri.getPath() with uri.getLastPathSegment(), it returns the correct dimensions

public static int[] getImageDimension(Uri uri){
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(new File(uri.getLastPathSegment()).getAbsolutePath(), options);
    return new int[]{options.outWidth, options.outHeight};
}

Upvotes: 3

simplatek
simplatek

Reputation: 637

Blackbelt's answer will work most of the time using Options, but I would like to propose another solution or fallback solution by using the ExifInterface. If you have the image URI, you can create the ExifInterface using the full path, no need for Bitmap object nor BitmapFactory.Options.

ex.

int width = exif.getAttributeInt( ExifInterface.TAG_IMAGE_WIDTH, defaultValue );
int height = exif.getAttributeInt( ExifInterface.TAG_IMAGE_LENGTH, defaultValue ); 

Upvotes: 16

Gazihan Alankus
Gazihan Alankus

Reputation: 11984

Blackbelt's answer is correct if you have a file uri. However, if you are using the new file providers as in the official camera tutorial, it won't work. This works for that case:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(
        getContext().getContentResolver().openInputStream(mPhotoUri),
        null,
        options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;

Upvotes: 25

amukhachov
amukhachov

Reputation: 5900

In addition to @Blackbelt answer you should use the following code to retrieve file path from Uri:

public static String getPathFromURI(Context context, Uri contentUri) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT &&
            DocumentsContract.isDocumentUri(context, contentUri)) {
        return getPathForV19AndUp(context, contentUri);
    } else {
        return getPathForPreV19(context, contentUri);
    }
}

private static String getPathForPreV19(Context context, Uri contentUri) {
    String[] projection = { MediaStore.Images.Media.DATA };
    Cursor cursor = context.getContentResolver().query(contentUri, projection, null, null, null);
    if (cursor != null && cursor.moveToFirst()) {
        try {
            int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            return cursor.getString(columnIndex);
        } finally {
            cursor.close();
        }
    }

    return null;
}

@TargetApi(Build.VERSION_CODES.KITKAT)
private static String getPathForV19AndUp(Context context, Uri contentUri) {
    String documentId = DocumentsContract.getDocumentId(contentUri);
    String id = documentId.split(":")[1];

    String[] column = { MediaStore.Images.Media.DATA };
    String sel = MediaStore.Images.Media._ID + "=?";
    Cursor cursor = context.getContentResolver().
            query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    column, sel, new String[]{ id }, null);

    if (cursor != null) {
        try {
            int columnIndex = cursor.getColumnIndex(column[0]);
            if (cursor.moveToFirst()) {
                return cursor.getString(columnIndex);
            }
        } finally {
            cursor.close();
        }
    }

    return null;
}

Upvotes: 2

jk jk
jk jk

Reputation: 1075

the solution is use new File(uri.getPath()).getAbsolutePath() instead of uri.toString()

Upvotes: 3

Related Questions