本文为您介绍 veImageX 自研 iOS 端 HEIF 编码库的接入流程。
类别 | 说明 |
---|---|
开发环境 | Xcode 11 及以上版本(推荐使用最新版本) |
系统版本 | iOS 10.0 及以上版本 |
像素数据:UIImage、YUV、YUVA、RGB、RGBA
说明
UIImage 格式原图支持的编码功能有限,如您有相关编码需求,使用前请联系商务人员。
本地图片:建议为 jpeg、png、webp 等系统原生解码支持良好的图片格式
您已完成独立 HEIF 编解码库的集成准备。
参考发布历史获取 SDK 最新版本号。
使用 CocoaPods 集成编解码库,支持两种集成方式:静态库(TTSDK
)和动态库(TTSDKFramework
)。您需要在工程的 Podfile
文件中添加相关依赖,并执行 pod install
下载 SDK。
source 'https://github.com/CocoaPods/Specs.git' source 'https://github.com/bytedance/cocoapods_sdk_source_repo.git' source 'https://github.com/volcengine/volcengine-specs.git' pod 'TTSDKFramework', 'x.x.x.x', :subspecs => [ # x.x.x.x 代表版本号,推荐使用最新版本 'ImageHeifEncoder', # 可选 ImageExifEditor 'ImageExifEditor' ]
source 'https://github.com/CocoaPods/Specs.git' source 'https://github.com/bytedance/cocoapods_sdk_source_repo.git' source 'https://github.com/volcengine/volcengine-specs.git' pod 'TTSDK', 'x.x.x.x', :subspecs => [ # x.x.x.x 代表版本号,推荐使用最新版本 'ImageHeifEncoder', # 可选 ImageExifEditor 'ImageExifEditor' ]
说明
使用 TTSDK
静态库时,如果与其他 SDK 存在符号冲突,需要切换到动态库避免符号冲突。
在引入头文件后,请完成初始化配置。代码示例如下所示:
// 引入头文件 // 动态库 #import <TTSDKFramework/TTSDKFramework.h> // 静态库 #import "BDWebImageStartUpConfig.h" #import "BDHeifCloudManagerConfig.h" // 在 AppDelegate.m 中添加初始化配置 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // 配置图片库 SDK 的使用参数并开始使用 TTSDKImagexConfiguration *imagexConfig = [TTSDKImagexConfiguration defaultImagexConfig]; imagexConfig.token = @"xxxxxxx"; // 传入获取的 Token 值 imagexConfig.authCodes = @[@"xxxx", @"xxxx", @"xxxx"]; // 传入获取的授权码 TTSDKConfiguration *config = [TTSDKConfiguration defaultConfigurationWithAppID:@"xxx"]; //传入获取的应用 ID config.imagexConfiguration = imagexConfig; config.bizType = TTSDKServiceBizType_Heif; config.shouldInitAppLog = NO; [TTSDKManager startWithConfiguration:config]; }
BDImageHeicEncoderConfig
类为编码 heic 静图的配置类,代码示例如下所示:
警告
若原图是 RGB 图片并设置hasAlpha
为YES
,将导致偶现 crash。
@interface BDImageHeicEncoderConfig : NSObject /** * @typedef imageWidth * @discussion 源图片的宽 */ @property (nonatomic, assign) uint32_t imageWidth; /** * @typedef imageHeight * @discussion 源图片的高 */ @property (nonatomic, assign) uint32_t imageHeight; /** * @typedef imageData * @discussion 源图片的 data 数据,支持像素数据(UIImage、YUV、YUVA、RGB、RGBA) */ @property (nonatomic, copy) NSData *imageData; /** * @typedef hasAlpha * @discussion 源图片是否带有 alpha */ @property (nonatomic, assign) BOOL hasAlpha; /** * @typedef quality * @discussion 指定的图片质量参数,取值范围为[1, 100],值越大编码后图片体积越大、画质越好 */ @property (nonatomic, assign) int quality; /** * @typedef format * @discussion 需要传递的编码数据的格式 * typedef NS_ENUM(NSInteger, BDEncodeFmt) { * BDImageRGBA, * BDImageRGB, * BDImageYUV, * BDImageYUVA, * }; */ @property (nonatomic, assign) BDEncodeFmt format; /** * @typedef exifData * @discussion 可传入源图片数据中的 exif 数据,可为空。传入后可使编码后图片自动旋转并保留 EXIF 信息。您可参考 BDImageExifEditor 提取解析图片中的 EXIF 信息。 */ @property (nonatomic, strong) NSData *exifData; /** * @brief 使编码图片时会使用更少的内存完成编码,编码后文件体积可能会增大约 2%。 * @typedef useGrid * @discussion 是否开启 Grid 编码,可节省一部分编码时所用内存 */ @property (nonatomic, assign) BOOL useGrid; /** * @typedef sourceSize * @discussion 原始图片的体积大小,单位为字节。 * @brief 如果传入为像素数据进行编码,则推荐手动传入该值(传入像素数据解码前原图大小),否则 sdk 内部会自行计算 */ @property (nonatomic, assign) NSUInteger sourceSize; /** * @typedef sourceImageType * @discussion 原始图片的格式图片 * @brief 如果传入为像素数据进行编码,则推荐手动传入该值(传入像素数据解码前原图格式),否则 sdk 内部会自行计算 */ @property (nonatomic, strong) NSString *sourceImageType; /** * @typedef writeSourceSize * @discussion 是否将原始图片体积写入编码后 heic 文件 * @brief 开启后,通过 sourceSize 传入的原始图片体积大小将被指定为编码后 heic 的体积,使编码前后体积基本保持一致。适用于所有类型的图片。例如在 jpeg 转 heic 转 jpeg 这种特定场景使用,使编码前后两个 jpeg 的图片体积大小基本保持一致。详见 https://www.volcengine.com/docs/508/116621#%E5%BD%93-jpeg-%E8%BD%AC-heic-%E8%BD%AC-jpeg-%E6%97%B6%EF%BC%8C%E5%A6%82%E4%BD%95%E4%BD%BF%E6%9C%80%E7%BB%88%E8%BE%93%E5%87%BA%E7%9A%84-jpeg-%E4%B8%8E%E6%9C%80%E5%88%9D-jpeg-%E5%8E%9F%E5%9B%BE%E7%9A%84%E4%BD%93%E7%A7%AF%E5%A4%A7%E5%B0%8F%E5%9F%BA%E6%9C%AC%E4%BF%9D%E6%8C%81%E4%B8%80%E8%87%B4%EF%BC%9F */ @property (nonatomic, assign) BOOL writeSourceSize; /** * @typedef fileUrl * @discussion 本地图片 url ,支持jpeg、png、webp等系统原生解码支持良好的格式图片 */ @property (nonatomic, strong) NSURL *fileUrl; /** * @typedef encodedImageData * @discussion 源图片的 data 数据,支持jpeg、png、webp等系统原生解码支持良好的格式图片 */ @property (nonatomic, strong) NSData *encodedImageData; @end
BDImageHeicEncoder
类为编码 heic 静图的接口类,代码示例如下所示:
@interface BDImageHeicEncoder : NSObject @property (nonatomic, strong) BDImageHeicEncoderConfig *encoderConfig; - (instancetype)initWithEncoderConfig:(BDImageHeicEncoderConfig *)config; //初始化方法 /** * @brief 开始编码。默认 preset 为 fast 档位进行编码,需配合 BDImageHeicEncoderConfig 使用。 */ - (BDImageHeicEncoderResult *)encode; /** * @brief 开始编码。支持设置 preset 编码档位,slow、fast,详见枚举 BDImageEncoderPreset,需配合 BDImageHeicEncoderConfig 使用。 */ - (BDImageHeicEncoderResult *)encode:(BDImageEncoderPreset)preset; /** 支持在特定配置(如 alpha 编码)和图片大小下,判断内存是否能够成功编码。 * 以下配置不影响实际编码效果,但请与实际编码时保持一致,以免影响判断结果。 * @param count 图片像素数量,即宽 * 高 * @param useGrid 是否开启 grid 编码 * @param hasAlpha 是否开启 alpha 通道编码 * @param memoryRatio 内存比例,用于判断当前可用内存是否存在 OOM 风险,判断逻辑为:若 needMemory < freeMemory * memoryRatio ,则认为没有 OOM 风险,反之则可能存在风险。 * @param pixelFromImage 是否需要从图片中获取 RGBA 数据 * @brief 该函数会根据当前内存使用情况,判断内存使用是否有 OOM 风险 */ + (BOOL)canEncode:(unsigned long long)count useGrid:(BOOL)useGrid hasAlpha:(BOOL)hasAlpha memoryRatio:(double)memoryRatio pixelFromImage:(BOOL)pixelFromImage; /** 支持在特定配置(如 alpha 编码)下,判断当前内存能够成功编码的像素数量。 * 以下配置不影响实际编码效果,但请与实际编码时保持一致,以免影响判断结果。 * @param useGrid 是否开启 grid 编码 * @param hasAlpha 是否开启 alpha 通道编码 * @param memoryRatio 内存比例,用于判断当前可用内存是否存在 OOM 风险,判断逻辑为:若 needMemory < freeMemory * memoryRatio ,则认为没有 OOM 风险,反之则可能存在风险。 * @param pixelFromImage 是否需要从图片中获取 RGBA 数据 * @brief 该函数会根据当前内存使用情况,判断安全可编码的像素数量 */ + (double)getSafePixelCountWithUseGrid:(BOOL)useGrid hasAlpha:(BOOL)hasAlpha memoryRatio:(double)memoryRatio pixelFromImage:(BOOL)pixelFromImage; @end
BDImageHeicEncoderResult
类为编码 heic 静图的结果类,代码示例如下所示:
@interface BDImageHeicEncoderResult : NSObject /** * @typedef heifData * @discussion 编码后heif图片的data */ @property (nonatomic, copy) NSData *heifData; /** * @typedef heifWidth * @discussion 编码后heif图片的宽 */ @property (nonatomic, assign) uint32_t heifWidth; /** * @typedef heifHeight * @discussion 编码后heif图片的高 */ @property (nonatomic, assign) uint32_t heifHeight; /** * @typedef errorCode * @discussion 编码错误码,成功为0 */ @property (nonatomic, assign) BDImageHeicEncodeError errorCode; @end
使用 rgba 数据编码成 heic,代码示例如下所示:
BDImageHeicEncoderConfig *config = [BDImageHeicEncoderConfig new]; config.imageWidth = imageWidth; // 设置源图片的宽 config.imageHeight = imageHeight; // 设置源图片的高 config.hasAlpha = NO; // 源图片是否带alpha config.quality = 66; // 设置编码质量参数,无默认值,取值范围为[1, 100],值越大编码后图片体积越大、画质越好 config.format = BDImageRGBA; // 编码数据的格式(详见 BDEncodeFmt) config.encodedImageData = [NSData data]; // 设置源图片解码前的原始 data //config.imageData = [NSData data]; // 或者设置源图片解码后的rgba data或yuv data config.exifData = [NSData data]; // 传入 NSData 格式的 exif 信息,默认为 nil,可以不设置 BDImageHeicEncoder *encoder = [[BDImageHeicEncoder alloc] initWithEncoderConfig:config]; BDImageHeicEncoderResult *result = [encoder encode]; // 编码后的结果,其中result.heifData即为编码后的heif图片data数据,该默认接口编码档位为“fast” BDImageHeicEncoderResult *result = [encoder encode:BDImageEncoderPresetSlow]; // 自定义编码档位,默认值为“fast”。“slow”表示编码压缩率高速度慢,“fast”表示编码压缩率低速度快
1.44.2.8-imagex 及之后版本的编码库 SDK 支持在 HEIF 编码监控查询上报指标,埋点上报功能为默认开启。
修改采样率:在控制台的 SDK 配置下发,对allow_log_type
下的imagex_heif_encoder_monitor
更改采样率参数,默认采样率为 100%。
关闭埋点上报:通过[BDImageHeicEncoderMonitor setEnableSentEncoderMonitor:NO];
关闭埋点上报功能。
以下为开启埋点上报后, SDK 收集的埋点信息:
参数 | 类型 | 说明 |
---|---|---|
imageWidth | Int | 编码图片宽度 |
imageHeight | Int | 编码图片高度 |
dataType | Int | 编码图片数据类型 |
preset | NSString | 编码档位 |
encodeError | NSError | 编码错误码 |
quality | Int | 编码质量参数 |
hasAlpha | Int | 是否编码为带 alpha 通道的 heic 图片 |
hasExif | Int | 编码时是否传入了 exif 数据 |
exifSize | Int | exif 数据大小 |
heicSize | Int | 编码后 heic 数据大小 |
systemDecodeDuration | Int | 系统生成像素数据的耗时 |
encodeDuration | Int | 编码耗时 |
encoderVersion | NSString | 编码库版本 |
useGrid | Int | 是否使用了 grid 编码 |
sourceImageType | NSString | 编码前原图格式 |
sourceSize | Int | 编码前原图体积 |
说明
使用前请确保已添加 ImageExifEditor
依赖。
支持新增、删除和修改指定 Tag 的内容,详见 BDImageExifMacro.h,各 Tag 的详细说明请参考 Standard Exif Tags。
@interface BDImageExifEditor : NSObject /** * @brief 获取 Exif 信息的源数据 */ @property (nonatomic, strong) NSData *exifData; /** * @brief 获取 Exif 源数据解析之后的 kv 形式数据。 */ @property (nonatomic, strong) NSDictionary *exifDic; /** * @brief 解析 heic 格式图片,获得其中的 Exif 源数据并解析成 kv 形式。 * @param data 需要解析的 heic 格式图片源数据。 * @return BDImageExifEditor 实例,包含此张图片的 Exif 源数据和 kv 形式的 Exif 信息。 */ - (instancetype)initWithHeicData:(NSData *)data; /** * @brief 解析 png 格式图片,获得其中的 Exif 源数据并解析成 kv 形式。 * @param data 需要解析的 png 格式图片源数据。 * @return BDImageExifEditor 实例,包含此张图片的 Exif 源数据和 kv 形式的 Exif 信息。 */ - (instancetype)initWithPngData:(NSData *)data; /** * @brief 解析 webp 格式图片,获得其中的 Exif 源数据并解析成 kv 形式。 * @param data 需要解析的 webp 格式图片源数据。 * @return BDImageExifEditor 实例,包含此张图片的 Exif 源数据和 kv 形式的 Exif 信息。 */ - (instancetype)initWithWebpData:(NSData *)data; /** * @brief 解析 jpeg 格式图片,获得其中的 Exif 源数据并解析成 kv 形式。 * @param data 需要解析的 jpeg 格式图片源数据。 * @return BDImageExifEditor 实例,包含此张图片的 Exif 源数据和 kv 形式的 Exif 信息。 */ - (instancetype)initWithJpegData:(NSData *)data; /** * @brief 将 Exif 源数据解析成 kv 形式 * @param data 需要解析的 Exif 源数据。 * @return BDImageExifEditor 实例,包含此张图片的 Exif 源数据和 kv 形式的 Exif 信息。 */ - (instancetype)initWithExifData:(NSData *)data; /** * @brief 新增/修改 Tag 内容并重新解析成 kv 形式 * 若原 Tag 中内容为空,表示新增;若原 Tag 中内容不为空,表示更新 * @param tag 指定要更新或新增的 Tag 值,详见 BDImageExifMacro 头文件中宏定义。 * @param ifd 指定 Tag 所对应的 IFD。 * @param format 指定 Tag 对应的值的形式,比如 int、short、ASCII 字符,详见 BDExifFormat。 * @param data 指定 Tag 对应的值的指针。 * @param count 指定 Tag 对应的值的个数。 */ - (int)updateExifTag:(int)tag ifd:(int)ifd format:(BDExifFormat)format data:(void *)data count:(int)count; /** * @brief 删除指定 Tag 内容并重新解析数据。 * @param tagArray 需要删除的 Exif tag 数组,可一次性删除多个 tag。 */ - (void)deleteExifTag:(NSArray<NSString *> *)tagArray; /** * @brief 若 Exif 源数据中包含旋转信息,则解析为具体形式,详见 BDImageExifOriInfo。 * @return BDImageExifOriInfo 旋转详细信息,详见 BDImageExifOriInfo 类接口介绍。 */ - (BDImageExifOriInfo *)obtainOriInfo; @end
旋转相关参数说明如下所示。
@interface BDImageExifOriInfo : NSObject /** * @brief 代表旋转的具体值。 */ @property (nonatomic, assign) int val; /** * @brief 旋转的角度(逆时针)。 */ @property (nonatomic, assign) int rotation; /** * @brief 是否水平翻转。 */ @property (nonatomic, assign) BOOL flipInHorizontal; /** * @brief 是否垂直翻转。 */ @property (nonatomic, assign) BOOL flipInVertical; @end
使用 BDExifEditor 进行 Exif 源数据的提取并解析,代码示例如下所示:
// 提取并解析:exifEditor.exifData 为 Exif 的 NSData 源数据;exifEditor.exifDic 为解析之后 NSDictionary 形式的 Exif 数据。 BDImageExifEditor *exifEditor = [[BDImageExifEditor alloc] initWithJpegData:imageData]; // 若 Exif 数据中包含旋转信息,可通过该接口进一步解析,获取旋转翻转信息,详见 BDImageExifOriInfo 类接口介绍。 BDImageExifOriInfo *info = [exifEditor obtainOriInfo];
使用 BDExifEditor 删除 Exif 源数据中指定条目,代码示例如下所示:
// tagArray 中填入上述 exifEditor.exifDic 中的键值 NSArray *tagArray = [@"UserComment", @"Orientation", @"DateTimeOriginal"]; [exifEditor deleteExifTag:tagArray];
使用 BDExifEditor 编辑 Exif 源数据中指定条目,代码示例如下所示:
// 具体条目和格式详见 BDImageExifMacro.h // 设置 BDEXIF_TAG_USER_COMMENT 条目为 exif test char* str = "exif test"; int res = [exifEditor updateExifTag:BDEXIF_TAG_USER_COMMENT ifd:2 format:BDEXIF_FORMAT_ASCII data:(void *)str count:(int)strlen(str)]; // 设置 BDEXIF_TAG_ORIENTATION 条目为 1 uint16_t ori = 1; int res = [exifEditor updateExifTag:BDEXIF_TAG_ORIENTATION ifd:0 format:BDEXIF_FORMAT_SHORT data:(void *)&ori count:1];