- 核心类 ExifInterface 传入path获取详细信息,引用
ExifInterface
implementation "androidx.exifinterface:exifinterface:1.3.6"
获取信息如下,具体以值含义和转换以官方API为准
val dateTime = exifInterface!!.getAttribute(ExifInterface.TAG_DATETIME)
val longitude =
exifInterface!!.getAttributeDouble(ExifInterface.TAG_GPS_LONGITUDE, 0.0)
val latitude =
exifInterface!!.getAttributeDouble(ExifInterface.TAG_GPS_LATITUDE, 0.0)
val gps_altitude_ref =
exifInterface!!.getAttributeDouble(
ExifInterface.TAG_GPS_ALTITUDE_REF,
0.0
) //海拔高度
val length = exifInterface!!.getAttribute(ExifInterface.TAG_IMAGE_LENGTH)
val width = exifInterface!!.getAttribute(ExifInterface.TAG_IMAGE_WIDTH)
val aperture = exifInterface!!.getAttribute(ExifInterface.TAG_APERTURE_VALUE) //光圈
val iso =
exifInterface!!.getAttribute(ExifInterface.TAG_PHOTOGRAPHIC_SENSITIVITY) //ISO
val balance = exifInterface!!.getAttribute(ExifInterface.TAG_WHITE_BALANCE) //白平衡
val exposure = exifInterface!!.getAttribute(ExifInterface.TAG_EXPOSURE_TIME) //曝光时间
val foch_length = exifInterface!!.getAttribute(ExifInterface.TAG_FOCAL_LENGTH) //焦距
val device_type = exifInterface!!.getAttribute(ExifInterface.TAG_MODEL) //获取相机型号
val make = exifInterface!!.getAttribute(ExifInterface.TAG_MAKE) //设备品牌
} catch (IOException e) {
e.printStackTrace();
}
- 选取相册照片 添加权限 Activity中使用
registerForActivityResult请求文件权限,单个权限申请ActivityResultContracts.RequestPermission(),多个权限申请ActivityResultContracts.RequestMultiplePermissions 如下单个权限申请封装
private fun requestPermissions(permission: String, onResult: (Boolean) -> Unit) {
if (ActivityCompat.checkSelfPermission(
this,
permission
) != PackageManager.PERMISSION_GRANTED
) {
registerForActivityResult(ActivityResultContracts.RequestPermission()) { result ->
onResult(result)
}.launch(permission)
} else {
onResult(true)
}
}
- 清单文件中声明权限,有些权限可能不需要没深究,注意Android13
READ_MEDIA_IMAGES
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION"/>
<uses-permission android:name="android.permission.MANAGE_MEDIA"
tools:ignore="ProtectedPermissions" />
- 图片选择器用compose提供的方法
val launch = rememberLauncherForActivityResult(
contract = ActivityResultContracts.GetContent()
) { selectedImageUri: Uri? ->}
- 图片选择器用
Uri转path,Uri路径格式存在content://需要通过ContentResolver查数据库
ContentResolver.SCHEME_FILE == contentUri.scheme直接获取路径 contentUri.lastPathSegment else contentUri.path
DocumentsContract.isDocumentUri(context, contentUri)分为 com.android.providers.media.documents和com.android.providers.downloads.documents
- content Uri 是目录
MediaStore.Images.Media.DATA + "=?"传入contentUri
val fileName =
if (ContentResolver.SCHEME_FILE == contentUri.scheme) contentUri.lastPathSegment else contentUri.path
val docId = DocumentsContract.getDocumentId(contentUri)
if ("com.android.providers.media.documents" == contentUri.authority) {
val selection = MediaStore.Images.Media._ID + "=${docId.split(":")[1]}"
getParentPathFromContentUri(
context,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
selection
)
} else if ("com.android.providers.downloads.documents" == contentUri.authority) {
val contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"),
docId.toLong()
)
getParentPathFromContentUri(context, contentUri, null.toString())
} else {
""
}
@Throws(java.lang.Exception::class)
private fun getParentPathFromContentUri(
context: Context,
contentUri: Uri,
selection: String = MediaStore.Images.Media.DATA + "=?"
): String? {
var path: String? = null
val cursor: Cursor =
context.contentResolver.query(contentUri, null, selection, null, null)!!
if (cursor != null && cursor.moveToFirst()) {
val dataIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
path = cursor.getString(dataIndex)
}
cursor.close()
return path
}
- 图片compose图片展示用到加载库 Coil或Glide,这里选Glide,model直接打开Uri类型
var uri: Uri? by remember { mutableStateOf(null) }
Card(
modifier = Modifier
.fillMaxWidth()
.height(300.dp)
.padding(12.dp)
) {
GlideImage(
model = uri,
contentDescription = null,
modifier = Modifier.fillMaxSize(),
transition = CrossFade,
failure = placeholder(ColorPainter(Color.LightGray)),
contentScale = ContentScale.FillBounds
)
}
- 最终效果

- 需要完成Exif和水印可借鉴这位作者equationl。随着软件版本更新内容是否有效自行验证,加水印之前做过View转bitmap,可以自己找相关文章