Android应用上传图片至后端丢失EXIF数据,如何解决?
解决上传图片丢失EXIF数据的问题
1. 确保图片选择器获取原始图片URI
部分设备或第三方图库应用中,默认的PickMultipleVisualMedia可能返回压缩后的图片URI,导致EXIF数据丢失。你可以通过明确请求原始尺寸图片来避免这个问题:
private fun launchNewPhotoPicker(){ val request = PickVisualMediaRequest.Builder() .setMediaType(PickVisualMedia.ImageOnly) // 设置为0表示请求原始尺寸图片,不做压缩 .setPreferredWidth(0) .setPreferredHeight(0) .build() newPicker.launch(request) }
2. 正确读取图片原始文件流
当前代码使用openInputStream(uri)读取文件的方式,在部分场景下可能获取到经过处理的数据流。改用openFileDescriptor获取完整的原始文件流,确保读取到包含EXIF的完整图片数据:
// 替换Worker中原有的流读取逻辑 val parcelFileDescriptor = applicationContext.contentResolver.openFileDescriptor(uri, "r") ?: return Result.failure() val fileDescriptor = parcelFileDescriptor.fileDescriptor val inputStream = FileInputStream(fileDescriptor) val fileBytes = inputStream.readBytes() parcelFileDescriptor.close() // 获取图片真实MIME类型,替代泛用的image/*,避免后端解析异常 val mimeType = applicationContext.contentResolver.getType(uri) ?: "image/jpeg" val requestBody = fileBytes.toRequestBody(mimeType.toMediaTypeOrNull())
3. 可选:上传前验证EXIF数据
可以在上传前读取EXIF数据,确认是否成功获取,方便排查问题:
// 需添加依赖:implementation 'androidx.exifinterface:exifinterface:1.3.6' val exifInterface = ExifInterface(inputStream) val orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL) Log.d("EXIF", "图片方向:$orientation") inputStream.reset() // 重置流,用于后续上传操作
完整修改后的Worker代码
class UploadImageWorker(appContext: Context, workerParams: WorkerParameters) : Worker(appContext, workerParams) { override fun doWork(): Result { val uris = inputData.getStringArray("uris") ?: return Result.failure() val client = okhttp3.OkHttpClient() for (uriString in uris) { val uri = Uri.parse(uriString) // 获取原始文件流 val parcelFileDescriptor = applicationContext.contentResolver.openFileDescriptor(uri, "r") ?: return Result.failure() val fileDescriptor = parcelFileDescriptor.fileDescriptor val inputStream = FileInputStream(fileDescriptor) val fileBytes = inputStream.readBytes() parcelFileDescriptor.close() // 获取真实MIME类型 val mimeType = applicationContext.contentResolver.getType(uri) ?: "image/jpeg" val requestBody = fileBytes.toRequestBody(mimeType.toMediaTypeOrNull()) ?: return Result.failure() val body = MultipartBody.Part.createFormData( "picture", UUID.randomUUID().toString(), requestBody ) val multipartBody = MultipartBody.Builder() .setType(MultipartBody.FORM) .addPart(body) .build() val request = okhttp3.Request.Builder() .url("https://mywonderfullfakeurl.com/api/pictures") .post(multipartBody) .build() val response = client.newCall(request).execute() if (!response.isSuccessful) { val errorBody = response.body?.string() ?: "Unknown error" Log.d("error", errorBody) return Result.failure() } } return Result.success() } }
额外注意事项
- 确保应用拥有对应权限:Android 13+需申请
READ_MEDIA_IMAGES,Android 12及以下需申请READ_EXTERNAL_STORAGE,否则无法访问完整图片文件和EXIF数据。 - 若使用第三方图库仍出现异常,可引导用户切换至系统原生图库选择图片。
内容的提问来源于stack exchange,提问作者MrSolarius
相关产品推荐
相关产品推荐

