我可以从android中的uri获取图像文件的宽度和高度吗?

问题描述 投票:0回答:11

我可以通过

MediaStore.Images.Media
正常获取图像宽度

但是我需要从从 dropbox 中选择的图像中获取图像的宽度和高度

所以目前我有以下方法从 dropbox 获取图像大小

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

但我真正需要的是获取文件的宽度和高度值

有人知道如何实现吗?请帮忙!

android image height width uri
11个回答
120
投票
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;
 
}

没有办法。您必须创建一个位图对象。如果你使用

inJustDecodeBounds
标志位图将不会加载到内存中。事实上
BitmapFactory.decodeFile
将返回null。在我的例子中
uri
是图片的物理路径


23
投票

如果你有文件 uri,Blackbelt 的答案是正确的。但是,如果您使用 官方相机教程 中的新文件提供程序,它将不起作用。这适用于那种情况:

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;

16
投票

Blackbelt 的答案大部分时间都可以使用

Options
,但我想通过使用
ExifInterface
提出另一种解决方案或后备解决方案。如果您有图像 URI,则可以使用完整路径创建
ExifInterface
,不需要位图对象或
BitmapFactory.Options

例如

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

3
投票

解决方案是使用

new File(uri.getPath()).getAbsolutePath()
代替
uri.toString()


3
投票

通过将 uri.getPath() 替换为 uri.getLastPathSegment(),接受的答案返回宽度/高度为 0,它返回正确的尺寸

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};
}

2
投票

除了@Blackbelt 的回答,您还应该使用以下代码从 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;
}

2
投票

对于拥有内容 uri(以

content://
开头)的人,打开一个
InputStream
并解码该流以避免宽度和高度为 0。我会用 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

2
投票

请使用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};
}

会以数组形式返回:

int[]{ width , height }

1
投票

这是@simplatek

提出的
ExifInterface解决方案的具体工作示例,使用
Uri
类型的扩展功能:

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)
}

0
投票

如果你们一直在宽度和高度上得到 (0,0),您可能想要解码流,而不是文件。

这可能是因为您正在尝试从资产中读取图像。试试这个:

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

0
投票

如果您难以获得恢复尺寸 - 宽度和高度相互发生 - 对于肖像图像,这是一个扩展的解决方案:

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)
}

重要的一点是 decodeStream 在完成其工作时关闭 inputStream。所以需要重新打开才能从ExifInterface获取方向。

对了,ExifInterface来自

androidx.exifinterface:exifinterface:x.x.x

© www.soinside.com 2019 - 2024. All rights reserved.