OpenGL ES 2.0/3.0 GLKTextureLoader加载图片/纹理错误 errorCode=12

image.png

这个 Bug 是在将工程的 Deployment Target 从 8.0 升级到 9.0 后出现的, 错误代码如下:

NSDictionary *optionDict = @{GLKTextureLoaderOriginBottomLeft:@(YES)};
GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithCGImage:procImgRef options:optionDict error:&error];

错误信息:

ErrorDomain=GLKTextureLoaderErrorDomain errorCode=12 

同样的代码在 Deployment Target = 8.0 时没有问题...

过程:

升级OpenGL ES 2.0 -> 3.0 遇到同样错误.
查看OpenGL ES 3.0 新功能和改动, 并无纹理加载的相关的改动.
尝试更换加载API:

// 失败
+ (nullable GLKTextureInfo *)textureWithContentsOfFile:(NSString *)path                                       /* File path of image. */
                                               options:(nullable NSDictionary *)options /* Options that control how the image is loaded. */
                                                 error:(NSError * __nullable * __nullable)outError;           /* Error description. */

// 通过 UIImagePNGRepresentation 转换成 Data 后加载成功, 但是 Alpha 通道数据异常
+ (nullable GLKTextureInfo *)textureWithContentsOfData:(NSData *)data                                         /* NSData containing image contents. */
                                               options:(nullable NSDictionary *)options /* Options that control how the image is loaded. */
                                                 error:(NSError * __nullable * __nullable)outError;           /* Error description. */

尝试转成JPEG后加载, 丢失透明通道, 但是加载成功.
以为是格式问题, 代码创建Bitmap上下文并重新渲染, 生成了各种格式的图片, 发现只有 CGImageAlphaInfo = kCGImageAlphaNone 的图片能加载成功.
大致判断错误应该是在Alpha通道上, 仔细查看 Texture Loading Options 参数, 发现一个选项:

/*
 Dictionary keys for texture loader properties
 */
/*
 GLKTextureLoaderApplyPremultiplication - A boolean NSNumber.
 Non-alpha channels are premultiplied by corresponding alpha channel values.
 For compressed formats, this option must be omitted, or false.
 False by default.
 */
GLK_EXTERN NSString *const GLKTextureLoaderApplyPremultiplication NS_AVAILABLE(10_8, 5_0);

即应用自左乘.
添加参数 GLKTextureLoaderApplyPremultiplication 并设置成 YES, 加载成功!

CGImageAlphaInfo 有如下几种:

typedef CF_ENUM(uint32_t, CGImageAlphaInfo) {
    kCGImageAlphaNone,               /* For example, RGB. */
    kCGImageAlphaPremultipliedLast,  /* For example, premultiplied RGBA */
    kCGImageAlphaPremultipliedFirst, /* For example, premultiplied ARGB */
    kCGImageAlphaLast,               /* For example, non-premultiplied RGBA */
    kCGImageAlphaFirst,              /* For example, non-premultiplied ARGB */
    kCGImageAlphaNoneSkipLast,       /* For example, RBGX. */
    kCGImageAlphaNoneSkipFirst,      /* For example, XRGB. */
    kCGImageAlphaOnly                /* No color data, alpha data only */
};

后来查了一下我的 CGImageAlphaInfo 是 kCGImageAlphaPremultipliedLast.
按理说这个参数一直都要设置成YES才行.
很奇怪的是 这个问题在 8.0 的时候没有问题, 怎么到 9.0 就崩溃了....

解决办法:

optionDict 添加配置参数 GLKTextureLoaderApplyPremultiplication 并设置为 YES 并更换 API

NSDictionary *optionDict = @{GLKTextureLoaderOriginBottomLeft:@(YES), GLKTextureLoaderApplyPremultiplication:@(YES)};
GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithContentsOfData:UIImagePNGRepresentation(procImg) options:optionDict error:&error];

你可能感兴趣的:(OpenGL ES 2.0/3.0 GLKTextureLoader加载图片/纹理错误 errorCode=12)