为什么 iPhone 7 和 iPhone 7 Plus 屏幕截图会发送与 RGB 颜色 space 图像不兼容的 alpha?

Why do iPhone 7 and iPhone 7 Plus screenshots send an incompatible alpha with RGB color space images?

我正在尝试创建位图上下文以调整从相机胶卷导入的图像的大小。这是代码:

    CGContextRef bitmap = CGBitmapContextCreate(NULL,
                                            newRect.size.width,
                                            newRect.size.height,
                                            CGImageGetBitsPerComponent(imageRef),
                                            0,
                                            CGImageGetColorSpace(imageRef),
                                            CGImageGetBitmapInfo(imageRef));

我在 iPhone 7 上截取了两张屏幕截图,当我尝试从相机胶卷加载它们时,一张失败了,另一张成功了。

第一个失败的是:

<CGImage 0x1701de3c0>
<<CGColorSpace 0x174a325c0> (kCGColorSpaceICCBased; kCGColorSpaceModelRGB; Display P3)>
    width = 750, height = 1334, bpc = 16, bpp = 64, row bytes = 6000 
    kCGImageAlphaLast | kCGImageByteOrder16Little 
    is mask? No, has mask? No, has matte? No, should interpolate? Yes

这是错误:

<Error>: CGBitmapContextCreate: unsupported parameter combination:
     16 integer bits/component;
     64 bits/pixel;
    RGB color space model; kCGImageAlphaLast;
    3840 bytes/row.
Valid parameters for RGB color space model are:
    16  bits per pixel,         5  bits per component,         kCGImageAlphaNoneSkipFirst
    32  bits per pixel,         8  bits per component,         kCGImageAlphaNoneSkipFirst
    32  bits per pixel,         8  bits per component,         kCGImageAlphaNoneSkipLast
    32  bits per pixel,         8  bits per component,         kCGImageAlphaPremultipliedFirst
    32  bits per pixel,         8  bits per component,         kCGImageAlphaPremultipliedLast
    64  bits per pixel,         16 bits per component,         kCGImageAlphaPremultipliedLast
    64  bits per pixel,         16 bits per component,         kCGImageAlphaNoneSkipLast
    64  bits per pixel,         16 bits per component,         kCGImageAlphaPremultipliedLast|kCGBitmapFloatComponents
    64  bits per pixel,         16 bits per component,         kCGImageAlphaNoneSkipLast|kCGBitmapFloatComponents
    128 bits per pixel,         32 bits per component,         kCGImageAlphaPremultipliedLast|kCGBitmapFloatComponents
    128 bits per pixel,         32 bits per component,         kCGImageAlphaNoneSkipLast|kCGBitmapFloatComponents
See Quartz 2D Programming Guide (available online) for more information.

第二个成功的是:

<CGImage 0x1705c0a50>
<<CGColorSpace 0x17402b7c0> (kCGColorSpaceICCBased; kCGColorSpaceModelRGB; sRGB IEC61966-2.1)>
    width = 750, height = 1334, bpc = 8, bpp = 32, row bytes = 3000 
    kCGImageAlphaPremultipliedLast | 0 (default byte order) 
    is mask? No, has mask? No, has matte? No, should interpolate? Yes

关于这种特殊情况,我找不到任何明确的信息。所以,我想知道是否有人对此问题有任何见解以及可能的修复建议。看到这里我完全懵了

我的崩溃日志表明此问题仅在我的 iPhone 7 和 iPhone 7 Plus 用户中发现。

提前致谢。

我希望有人找到更好的解决方案,因为这是一个 hack,但这是我的解决方法:

kCGImageAlphaLast 参数是该位图信息中不受支持的部分。对于图像完全不透明的情况,您可以使用 kCGImageAlphaPremultipliedLast 并获得相同的结果,因为在完全不透明的情况下,alpha 预乘本质上是无操作(每个像素乘以 1)。

但是警告,如果图像有任何半透明像素,它们的颜色将是错误的。在我的例子中,我希望照片完全不透明,否则用户没有正确使用我的应用程序,所以我现在可以忍受这个。

CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);

// first try
CGContextRef bitmap = CGBitmapContextCreate(NULL,
                                        newRect.size.width,
                                        newRect.size.height,
                                        CGImageGetBitsPerComponent(imageRef),
                                        0,
                                        CGImageGetColorSpace(imageRef),
                                        bitmapInfo);

if (!bitmap && (bitmapInfo & kCGBitmapAlphaInfoMask) == kCGImageAlphaLast) {

    // WARNING - only do this if you expect a fully opaque image

    // try again with pre-multiply alpha

    // clear alpha bits
    bitmapInfo &= ~kCGBitmapAlphaInfoMask;
    // set pre-multiply last
    bitmapInfo |= kCGImageAlphaPremultipliedLast & kCGBitmapAlphaInfoMask;

    CGContextRef bitmap = CGBitmapContextCreate(NULL,
                                        newRect.size.width,
                                        newRect.size.height,
                                        CGImageGetBitsPerComponent(imageRef),
                                        0,
                                        CGImageGetColorSpace(imageRef),
                                        bitmapInfo);

}

if (!bitmap) {
    // fail gracefully
}