Compose Android 获取 相册Exif信息

169 阅读2分钟
  1. 核心类 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();
}
  1. 选取相册照片 添加权限 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)
  }

}
  1. 清单文件中声明权限,有些权限可能不需要没深究,注意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" />
  1. 图片选择器用compose提供的方法
val launch = rememberLauncherForActivityResult(
    contract = ActivityResultContracts.GetContent()
) { selectedImageUri: Uri? ->}
  1. 图片选择器用UripathUri路径格式存在content://需要通过ContentResolver查数据库
    • ContentResolver.SCHEME_FILE == contentUri.scheme直接获取路径 contentUri.lastPathSegment else contentUri.path
    • DocumentsContract.isDocumentUri(context, contentUri)分为 com.android.providers.media.documentscom.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 projection = arrayOf("_id", "_data")
//    val selection = MediaStore.Images.Media.DATA + "=?"
//    val selectionArgs = arrayOf<String>(contentUri.toString())
  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
}
  1. 图片compose图片展示用到加载库 CoilGlide,这里选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
    )
}
  1. 最终效果

5EF16D83-AB83-4802-9D99-F91871CF8477.png

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