You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.08 06:12:04