如何在Android平台上将所有EXIF标签从一个JPEG复制到另一个JPEG?
跨JPEG全量复制EXIF标签的最优实现方案
方案1:直接复制EXIF二进制段(优先推荐)
- 实现逻辑:JPEG文件的EXIF内容全部存储在独立的APP1标记段(以
0xFFE1开头),不需要解析任何标签定义,直接从源文件提取完整的EXIF段二进制数据,写入目标JPEG的对应位置即可,支持所有新增的自定义/官方EXIF标签,无需后续迭代维护 - 代码示例(Kotlin):
fun copyExifSegment(sourceJpeg: File, targetJpeg: File) { val sourceBytes = sourceJpeg.readBytes() var exifStart = -1 var exifLength = 0 // 遍历查找APP1(EXIF)段 for (i in 0 until sourceBytes.size - 1) { if (sourceBytes[i] == 0xFF.toByte() && sourceBytes[i+1] == 0xE1.toByte()) { exifStart = i // 段长度占2字节,包含长度字段本身 exifLength = (sourceBytes[i+2].toInt() and 0xFF shl 8) or (sourceBytes[i+3].toInt() and 0xFF) + 2 break } // 扫到图像数据段就停止 if (sourceBytes[i] == 0xFF.toByte() && sourceBytes[i+1] == 0xDA.toByte()) break } if (exifStart == -1) return // 源文件无EXIF val targetBytes = targetJpeg.readBytes() // 先删除目标文件原有EXIF段 val targetWithoutOldExif = ByteArrayOutputStream().use { bos -> var i = 0 while (i < targetBytes.size - 1) { if (targetBytes[i] == 0xFF.toByte() && targetBytes[i+1] == 0xE1.toByte()) { val skipLen = (targetBytes[i+2].toInt() and 0xFF shl 8) or (targetBytes[i+3].toInt() and 0xFF) + 2 i += skipLen } else if (targetBytes[i] == 0xFF.toByte() && targetBytes[i+1] == 0xD8.toByte()) { // SOI段之后插入新EXIF bos.write(targetBytes, i, 2) bos.write(sourceBytes, exifStart, exifLength) i += 2 } else { bos.write(targetBytes[i]) i++ } } bos.toByteArray() } targetJpeg.writeBytes(targetWithoutOldExif) }
方案2:反射动态获取ExifInterface所有标签(适合需要标签级处理的场景)
- 实现逻辑:通过反射遍历
android.media.ExifInterface类中所有public static final String类型的TAG常量,动态生成全量标签列表,不需要手动硬编码100+标签名,Android系统升级新增标签也能自动识别 - 代码示例(Java):
List<String> getAllExifTags() throws NoSuchFieldException, IllegalAccessException { List<String> tags = new ArrayList<>(); Field[] fields = ExifInterface.class.getFields(); for (Field field : fields) { if (field.getType() == String.class && Modifier.isStatic(field.getModifiers()) && field.getName().startsWith("TAG_")) { tags.add((String) field.get(null)); } } return tags; }
- 注意事项:需要在混淆规则中添加如下配置,避免TAG字段被混淆删除:
-keep class android.media.ExifInterface { public static final java.lang.String TAG_*; }
内容的提问来源于stack exchange,提问作者lostintranslation
相关产品推荐
相关产品推荐

