BOOL TIPCGImageHasAlpha()

in TwitterImagePipeline/TIPImageUtils.m [225:295]


BOOL TIPCGImageHasAlpha(CGImageRef imageRef, BOOL inspectPixels)
{
    BOOL isLeadingByteAlpha = YES;
    const CGBitmapInfo bmpInfo = CGImageGetBitmapInfo(imageRef);
    const CGImageAlphaInfo alphaInfo = bmpInfo & kCGBitmapAlphaInfoMask;
    switch (alphaInfo) {
        case kCGImageAlphaNone:
            if (CGImageIsMask(imageRef)) {
                if (inspectPixels) {
                    break;
                }
                return YES; // alpha mask
            }
        case kCGImageAlphaNoneSkipLast:
        case kCGImageAlphaNoneSkipFirst:
            return NO;
        case kCGImageAlphaPremultipliedLast:
        case kCGImageAlphaLast:
            isLeadingByteAlpha = NO;
        case kCGImageAlphaPremultipliedFirst:
        case kCGImageAlphaFirst:
            if (inspectPixels) {
                break;
            }
        case kCGImageAlphaOnly:
            return YES;
    }

    if (TIP_BITMASK_HAS_SUBSET_FLAGS(bmpInfo, kCGBitmapFloatComponents)) {
        return YES; // bail, only tested with 8-bit components
    }

    const size_t bitsPerComponent = CGImageGetBitsPerComponent(imageRef);
    if (bitsPerComponent != 8) {
        return YES; // bail
    }

    CGColorSpaceRef const colorSpace = CGImageGetColorSpace(imageRef);
    const size_t numberOfComponents = colorSpace ? CGColorSpaceGetNumberOfComponents(colorSpace) : 0;
    const CGSize size = CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef));
    const size_t expectedBytesPerRow = (numberOfComponents + 1) * (size_t)size.width * (bitsPerComponent / 8);
    const size_t byteSluffPerRow = CGImageGetBytesPerRow(imageRef) - expectedBytesPerRow;
    if (byteSluffPerRow > CGImageGetBytesPerRow(imageRef)) {
        return YES; // bail - underflow
    }

    const int alphaByteIndex = _TIPImageByteIndexOfAlphaComponent(bmpInfo, numberOfComponents, isLeadingByteAlpha);
    if (alphaByteIndex < 0) {
        return YES; // bail
    }

    CGDataProviderRef const dataProvider = CGImageGetDataProvider(imageRef);
    CFRetain(dataProvider);
    TIPDeferRelease(dataProvider);
    CFDataRef const data = CGDataProviderCopyData(dataProvider);
    TIPDeferRelease(data);

    const UInt8 *byteComponent = CFDataGetBytePtr(data);
    for (size_t iRow = 0; iRow < (size_t)size.height; iRow++) {
        const UInt8 * const endRowByte = byteComponent + expectedBytesPerRow;
        while (byteComponent < endRowByte) {
            if (0xFF != byteComponent[alphaByteIndex]) {
                return YES;
            }
            byteComponent += numberOfComponents + 1;
        }
        byteComponent += byteSluffPerRow;
    }

    return NO;
}