Android API26+保存照片到DCIM后读取丢失ExifInterface信息问题
根因分析
你遇到的Exif丢失问题出在两个核心环节:
- 保存拍摄照片到DCIM的环节直接丢失Exif:你当前的实现是把相机返回的
Bitmap直接压缩写入DCIM文件,Bitmap是解码后的纯像素数据,解码过程已经完全剥离了原始照片携带的所有Exif元数据(包括旋转角度、拍摄时间等核心信息),所以存到DCIM的照片从一开始就没有Exif信息,后续选中时自然读不到旋转参数。 - 选图环节如果读取Exif的方式不对,也会出现读不到的问题:如果你选的是系统原生相机拍摄的照片(本身带Exif),但用文件路径直接读取content://类型Uri对应的Exif,就会因为权限、路径映射问题读不到有效信息。
解决方案
1. 修复保存到DCIM的逻辑,保留Exif
优先选择直接写入相机返回的原始字节流,不要经过Bitmap转码:
String imagesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).toString(); File image = new File(imagesDir, imageFileNameToUseAtWebServerEnd); // cameraData是相机onPictureTaken回调返回的原始字节数组,自带完整Exif try (FileOutputStream fos = new FileOutputStream(image)) { fos.write(cameraData); // 保存后发广播通知系统媒体库更新,避免相册看不到新照片 sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(image))); } catch (IOException e) { Log.d(TAG, e.toString()); } // 后续需要Bitmap的话,直接从上述保存的文件解码即可
如果你的业务必须先处理Bitmap再保存,需要手动迁移原始Exif到新文件:
// 先读取原始照片的Exif信息 ExifInterface originalExif = new ExifInterface(原始照片路径); int orientation = originalExif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); // 其他你需要保留的Exif字段都可以按上述方式读取 // Bitmap压缩写入新文件后,把Exif写回 ExifInterface newExif = new ExifInterface(新保存的DCIM文件路径); newExif.setAttribute(ExifInterface.TAG_ORIENTATION, String.valueOf(orientation)); // 其他字段也按上述方式写入后调用保存 newExif.saveAttributes();
2. 修复选图环节的Exif读取逻辑
请引入AndroidX的ExifInterface兼容库,直接通过Uri对应的InputStream读取Exif,避免路径适配问题:
try (InputStream inputStream = getContentResolver().openInputStream(originalUri)) { // 用兼容库的ExifInterface,不要用系统原生的 ExifInterface exif = new ExifInterface(inputStream); int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); // 拿到的orientation就是正确的旋转角度,直接传入你的旋转校正逻辑即可 } catch (IOException e) { Log.d(TAG, e.toString()); }
如果你需要用到选图生成的临时文件的Exif,确认你的copyStream方法是完整拷贝所有字节,不要做任何截断操作,完整拷贝后的临时文件会保留原始文件的所有Exif信息。
注意事项
- 低版本Android(<API29)需要提前申请
WRITE_EXTERNAL_STORAGE、READ_EXTERNAL_STORAGE权限,权限缺失会导致写DCIM、读相册Exif失败。 - 所有Exif操作都建议用AndroidX兼容库的
androidx.exifinterface.media.ExifInterface,避免不同系统版本的兼容性问题。
内容的提问来源于stack exchange,提问作者Tony
相关产品推荐
相关产品推荐

