以下为您介绍如何使用 HEIF 编码库来实现常见 Exif 处理,包括获取 Exif 信息、获取 Exif 中旋转信息、新增/更新指定 Tag、删除指定 Tag、在编码过程中写入 Exif 信息。
Exif(Exchangeable Image File Format)是用于存储数码照片中的元数据的标准格式。Exif 数据通常嵌入在图像文件中,包含了关于图像及其创建过程的各种信息,如基本图像信息、相机信息、GPS 信息等。
在 Exif 中,Tag 是用于标识和存储特定元数据信息的单元。Exif 数据是由多个不同的 Tag 组成的,每个 Tag 都有特定的编号、名称和数据格式,用于存储某一方面的信息。例如,有一个 Tag 用于存储照片的拍摄时间,另一个 Tag 用于存储相机的光圈值等。
当需要读取或修改 Exif 数据时,实际上是对其中的各个 Tag 进行操作。例如,在编程中,如果要获取一张照片的拍摄时间,就需要找到对应的表示拍摄时间的 Exif Tag,然后按照其数据格式读取其中的数据。
veImageX 提供了多个 Exif 相关接口,支持多种处理能力。以下是两个典型应用场景:
保持图像方向一致:例如,在将 jpeg 原图编码为 HEIC 的过程中,可以通过提取 Exif 信息中的旋转信息,确保生成的 Heic 编码产物与原图方向保持一致,避免出现图像显示角度异常的情况,提升用户查看图像的体验。
保护用户隐私:例如,当上传照片时,可删除与隐私相关的 Exif 数据,例如 GPS 位置信息、相机的唯一标识符等。在节省网络带宽的同时,还能保护用户的隐私安全。
HEIF 编码库为白名单能力,使用前请提交工单联系技术支持配置白名单。
您需要在集成 HEIF 编码库前,在 veImageX 获取以下配置信息。
获取 APPID:在 veImageX 控制台 的应用管理页面,创建 APP 类型应用后。在应用卡片中查看 AppID 。
获取 Token:在上面应用卡片中,单击 查看 Token,获取账号唯一的 Token 值。
购买授权:在上面应用卡片中的 License 授权区域,单击 购买授权 按钮。在购买弹窗中,SDK 类型选择客户端 HEIF 库,版本类型选择 HEIF 编码。调试期间,建议您购买一个月有效期的免费试用版授权。购买完成后,获取授权码。
类型 | Android 端 | iOS 端 |
---|---|---|
集成文档 | 集成 HEIF 编码库-Android | 集成 HEIF 编码库-iOS |
集成流程 |
说明 请使用 3.2.1-tob 及之后版本。
说明 请务必添加 authorization 、nativeheifencoder 和 nativelibexif 依赖。
说明 填入获取的 AppID、Token、授权码。
|
说明 请使用 1.44.1.6-premium 及之后版本
说明 请务必接入 ImageHeifEncoder 和 ImageExifEditor。
说明 填入获取的 AppID、Token、授权码。 |
接入 HEIF 编码库后,您可按照以下内容实现对图片 Exif 信息的获取、新增、更新、删除,以及在编码过程中写入 Exif 信息,使编码后 HEIC 图携带指定的 Exif 信息。
在手机中传入一张测试图片。例如,可以使用 adb 命令将 PC 端图片导入到手机中。
adb push /Users/xxxxx/Desktop/ExifPics/exif.png /storage/emulated/0/ExifPic/exif.png
支持提取 WebP、JPEG、PNG、HEIC 格式图片内的 Exif 信息,并以 Map 的形式展示,key 为具体 Tag 名称,Value 为 Tag 的内容。具体代码示例如下所示:
说明
因为提取 Exif 信息操作涉及到 IO 操作,往往较为耗时,因此建议在子线程中调用该方法。
具体接口描述请参考集成 HEIF 编码库-Android。
thread { val inputFilePath = "/storage/emulated/0/ExifPic/exif.png" //指定要获取 Exif 信息的图片文件在 Android 设备存储中的路径 val exifHelper = BDExifHelper(inputFilePath) // 获取经过解析的 exif 的 map 信息 exifHelper.exifTagMap?.let { runOnUiThread { mTvExifInfo1.text = it.toString() } } }
示例:获取的 Exif 信息如下所示。
{YResoution=72,ExifVersion=Exif Version 2.1,FlashpixVersion=FlashPix Version 1.0,XResolution=72,ColorSpace=sRGB,PixelXDimension=3264,PixelYDimension=2448,Orientation=Right-top,Resolution=lnch}
具体接口描述请参考集成 HEIF 编码库-Android。
thread { val inputFilePath = "/storage/emulated/0/ExifPic/exif.png" //指定要获取 Exif 旋转信息的图片文件在 Android 设备存储中的路径 val exifHelper = BDExifHelper(inputFilePath) // 获取 Exif 中旋转信息 val oriInfo = exifHelper.obtainOriInfo() runOnUiThread { mTvExifInfo2.text = "Note == Ori:{val:${oriInfo.value}, rotation:${oriInfo.rotation}, flipInHorizontal:${oriInfo.flipInHorizontal}, flipInVertical:${oriInfo.flipInVertical}}" } }
示例:获取的 Exif 旋转信息如下所示。
Note == Ori:{val:6,rotation:270,flipInHorizontal:false,flipinVertical:false}
通过指定要编辑的 Tag 以及该 Tag 对应的 IFD、格式等信息,实现新增 Tag 或更新 Tag。您可参考 Exif 标准文档查询指定 Tag 对应信息。
若原图中 Tag
内容为空,则表示新增内容;
若原图中 Tag
内容不为空,则表示更新内容。
具体接口描述请参考集成 HEIF 编码库-Android。
//指定 Tag 的内容 val str = "用户评论:xxxxxx" val strBytes = str.toByteArray(Charsets.UTF_8) //设置 Exif 相关配置 this.exifHelper.setExifTag( //指定 Tag 名称,具体取值请见 BDExifTags。这里以 UserComment 为例 BDExifTags.BDEXIF_TAG_USER_COMMENT, //指定 UserComment 对应的 ifd,取值如下所示 // 0:对应 EXIF_IFD_0th 内的 Tag,如 Xresolution // 1:对应 EXIF_IFD_1st 内的 Tag,如 Artist // 2:对应 EXIF_IFD_EXIF 内的 Tag,如 UserComment // 3:对应 EXIF_IFD_GPS 内的 Tag,如 GPSVersionID // 4:对应 EXIF_IFD_INTEROPERABILITY 内的 Tag,如 RelatedImageFileFormat 2, //指定 Tag 对应的格式,根据官方 Exif 标准可知 UserComment 的 Type为 ASCII 格式 BDExifFormats.BDEXIF_FORMAT_ASCII, //传入前面准备好的用户评论字符串字节数组的长度 strBytes.size, //传入实际的用户评论字符串对应的字节数组内容 strBytes ) runOnUiThread { val oriInfo = this.exifHelper.obtainOriInfo() mTvExifInfo.text = "after update:" + this.exifEditor!!.exifTagMap.toString() + "Note == Ori:{val:${oriInfo.value}, rotation:${oriInfo.rotation}, flipInHorizontal:${oriInfo.flipInHorizontal}, flipInVertical:${oriInfo.flipInVertical}}" }
示例:
{YResoution=72,ExifVersion=Exif Version 2.1,FlashpixVersion=FlashPix Version 1.0,XResolution=72,ColorSpace=Uncalibrated,ResolutionUnit=lnch}
{Resoution=72,ExifVersion=Exif Version 2.1,FlashpixVersion=FlashPix Version 1.0,XResolution=72,UserComment=用户评论:xxxxxx,ColorSpace=Uncalibrated,ResolutionUnit=lnch}
通过指定 Tag 名称删除图片中的 Exif 信息。您可在获取解析后图片的 Exif 信息后,选择要删除的 Tag。解析后 Exif 内容为 Map 类型,key 为具体 Tag 名称,Value 为 Tag 的内容。
说明
在 Exif 的众多 Tag 中,YResolution、ExifVersion、FlashpixVersion、XResolution、ColorSpace、ResolutionUni 被称为 Base Exif Tag。
如果删除时指定了 Base Exif Tag,那么 Tag 对应的值将恢复为默认值。
如果删除时指定了非 Base Exif Tag,那么 Tag 则会被删除。
具体接口描述请参考集成 HEIF 编码库-Android。
thread { val inputFilePath = "/storage/emulated/0/ExifPic/exif.png" val exifHelper = BDExifHelper(inputFilePath) val deleteTags: Array<String>? = arrayOf("Orientation", "xxx", ...) exifHelper.deleteExifTag(deleteTags) }
示例:
{YResoution=72,ExifVersion=Exif Version 2.1,FlashpixVersion=FlashPix Version 1.0,XResolution=72,ColorSpace=sRGB,PixelXDimension=3264,PixelYDimension=2448,Orientation=Right-top,Resolution=lnch}
after delete:{YResoution=72,ExifVersion=Exif Version 2.1,FlashpixVersion=FlashPix Version 1.0,XResolution=72,ColorSpace=Uncalibrated,ResolutionUnit=lnch}Note == Ori:{Val:0,rotation:0,flipInHorizontal:false,flipinVertical:false}
您需要在获取图片 Exif 信息后,参考以下内容在原始图片编码为 Heic 的过程中,写入您指定的 Exif 数据,从而获取带有指定 Exif 数据的 HEIC 图。
例如,可以将 jpeg 原图编码为 Heic 的过程中,可以通过提取 Exif 信息中的旋转信息,并在编码过程写入使生成的 Heic 产物与原 jpeg 的方向保持一致。
具体接口描述请参考集成 HEIF 编码库-Android。
val inputFilePath = getInputFilePath() val exifHelper = BDExifHelper(inputFilePath) val outputStream : FileOutputStream = FileOutputStream( getOutFilePath( withCreate = true, index = infoBean?.index ) ) var heifEncodeConfig: HeifEncodeConfig = HeifEncodeConfig(inputFilePath, outputStream) heifEncodeConfig.setExifData(exifHelper.exifData) HeifEncoder.encode(heifEncodeConfig) //编码后的 Heic 图片会保存在 outputStream 中,并持有对应 Exif 数据