You need to enable JavaScript to run this app.
导航
集成 HEIF 编码库
最近更新时间:2024.11.18 20:48:41首次发布时间:2024.05.07 15:24:06

本文为您介绍 veImageX 自研 iOS 端 HEIF 编码库的接入流程。

环境要求

类别说明
开发环境Xcode 11 及以上版本(推荐使用最新版本)
系统版本iOS 10.0 及以上版本

注意事项

  • 为了保证编码成功,建议您在编码前调用 BDImageHeicEncoder 类判断编码时是否存在 OOM 风险(内存溢出)。
  • Grid 编码不支持编码带有 alpha 通道的图片。如需正常编码带有 alpha 通道的图片,请关闭 Grid 编码。
  • 编码前原图支持以下格式:
    • 像素数据:UIImage、YUV、YUVA、RGB、RGBA

      说明

      UIImage 格式原图支持的编码功能有限,如您有相关编码需求,使用前请联系商务人员。

    • 本地图片:建议为 jpeg、png、webp 等系统原生解码支持良好的图片格式

前提条件

您已完成独立 HEIF 编解码库的集成准备

获取 SDK 最新版本号

参考发布历史获取 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 类

BDImageHeicEncoderConfig类为编码 heic 静图的配置类,代码示例如下所示:

警告

若原图是 RGB 图片并设置hasAlphaYES,将导致偶现 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 类

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 类

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 收集的埋点信息:

参数类型说明
imageWidthInt编码图片宽度
imageHeightInt编码图片高度
dataTypeInt编码图片数据类型
presetNSString编码档位
encodeErrorNSError编码错误码
qualityInt编码质量参数
hasAlphaInt是否编码为带 alpha 通道的 heic 图片
hasExifInt编码时是否传入了 exif 数据
exifSizeIntexif 数据大小
heicSizeInt编码后 heic 数据大小
systemDecodeDurationInt系统生成像素数据的耗时
encodeDurationInt编码耗时
encoderVersionNSString编码库版本
useGridInt是否使用了 grid 编码
sourceImageTypeNSString编码前原图格式
sourceSizeInt编码前原图体积

Exif 接口介绍

说明

使用前请确保已添加 ImageExifEditor 依赖

BDImageExifEditor 类

支持新增、删除和修改指定 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

BDImageExifOriInfo 类

旋转相关参数说明如下所示。

@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];