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

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

环境要求

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

注意事项

  • 为了保证编码成功,建议您在编码前调用 BDImageHeicEncoder 类判断编码时是否存在 OOM 风险(内存溢出)。
  • Grid 编码不支持编码带有 alpha 通道的图片。如需正常编码带有 alpha 通道的图片,请关闭 Grid 编码。

前提条件

您已完成独立 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 源图片的 bitmap rgba data
 */
@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 需要传递的编码数据的格式,支持 RGBA 和 YUV 两种数据格式
 *  typedef NS_ENUM(NSInteger, BDEncodeFmt) {
 *    BDImageRGBA,
 *    BDImageRGB,
 *    BDImageYUV,
 *    BDImageYUVA,
 *  };
 */
@property (nonatomic, assign) BDEncodeFmt format;

/**
 * @typedef exifData
 * @discussion 传入源图片数据中的 exif 数据,可为空
 */
@property (nonatomic, strong) NSData *exifData;

/**
 * @brief 使编码图片时会使用更少的内存完成编码,编码后文件体积可能会增大约 2%。
 * @typedef useGrid 是否开启 Grid 编码
 * @discussion 节省一部分编码时所用内存
 */
@property (nonatomic, assign) BOOL useGrid;

/**
 * @brief 例如在 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
 * @typedef sourceSize 图片的原始体积大小,单位为字节。
 */
@property (nonatomic, assign) NSUInteger sourceSize;

@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.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数据
BDImageHeicEncoderResult *result = [encoder encode:BDImageEncoderPresetSlow]; // 自定义编码档位,默认值为“fast”。“slow”表示编码压缩率高速度慢,“fast”表示编码压缩率低速度快

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