Loading 4-channel texture data in iOS

不羁岁月 提交于 2019-12-03 16:10:43

As you considered PVRTC then using GLKit could be an option. This includes GLKTextureLoader which allows you to load textures without pre-multiplying alpha. Using for example:

+ (GLKTextureInfo *)textureWithContentsOfFile:(NSString *)fileName options:(NSDictionary *)textureOperations error:(NSError **)outError

and passing an options dictionary containing:

GLKTextureLoaderApplyPremultiplication = NO

You can simply request that Xcode not 'compress' your PNG files. Click your project in the top left, select the 'Build Settings', find 'Compress PNG Files' and set the option to 'No'.

As to your other options, postdividing isn't a bad solution but obviously you'll lose overall precision and I believe both TIFF and BMP are also supported. PVRTC is PowerVR specific so it's not Apple-specific but it's also not entirely platform independent and is specifically designed to be a lossy compression that's trivial to uncompress with little input on the GPU. You'd generally increase your texture resolution to ameliorate for the low bit per pixel count.

You should use libpng to load PNG without premultiplied colors.

It is written in C and should compile for iOS.

I've had similar problems with Android and also had to use third-party library to load PNG files with non-premultiplied colors.

This is an attempt to answer my own question.

It is not possible to load non-premultiplied .png files.

The option kCGImageAlphaLast is a valid option, but does not give a valid combination for CGBitmapContextCreate (reference). It is however a valid option for CGImageRef's.

What the build setting COMPRESS_PNG_FILES in XCode mentioned above does, is to convert .png files into some other file format and also multiply the channels rgb with a (reference). I was hoping that disabling this option would make it possible to reach the channel data in my actual .png files. But I am not sure if this is possible. The following example is an attempt to access the .png data at low level, as a CGImageRef:

void test_cgimage(const char* path)
{
    CGDataProviderRef dataProvider = CGDataProviderCreateWithFilename(path);
    CGImageRef cg_image = CGImageCreateWithPNGDataProvider(dataProvider, NULL, NO,
                                                           kCGRenderingIntentDefault);
    CGImageAlphaInfo info = CGImageGetAlphaInfo(cg_image);
    switch (info)
    {
        case kCGImageAlphaNone:               printf("kCGImageAlphaNone\n");                break;
        case kCGImageAlphaPremultipliedLast:  printf("kCGImageAlphaPremultipliedLast\n");   break;
        case kCGImageAlphaPremultipliedFirst: printf("kCGImageAlphaPremultipliedFirst\n");  break;
        case kCGImageAlphaLast:               printf("kCGImageAlphaLast\n");                break;
        case kCGImageAlphaFirst:              printf("kCGImageAlphaFirst\n");               break;
        case kCGImageAlphaNoneSkipLast:       printf("kCGImageAlphaNoneSkipLast\n");        break;
        case kCGImageAlphaNoneSkipFirst:      printf("kCGImageAlphaNoneSkipFirst\n");       break;
        default: break;
    }

}

which gives "kCGImageAlphaPremultipliedLast" with COMPRESS_PNG_FILES disabled. So I think iOS always convert .png files, even at run-time.

Not 100% what you want, but I got around the problem using this approach: Put the alpha channel into a separate black & white png and save the original png without alpha. So space taken is about the same. Then in my texture loader load both images and combine into one texture.

I know this is a only a workaround, but at least it gives the correct result. And yes, it is very annoying, that iOS does not allow you to load textures from PNG without premultiplied alpha.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!