in iOS/WAStickersThirdParty/YYImageCoder.m [754:866]
static BOOL YYCGImageDecodeToBitmapBufferWith32BitFormat(CGImageRef srcImage, vImage_Buffer *dest, CGBitmapInfo bitmapInfo) {
if (!srcImage || !dest) return NO;
size_t width = CGImageGetWidth(srcImage);
size_t height = CGImageGetHeight(srcImage);
if (width == 0 || height == 0) return NO;
BOOL hasAlpha = NO;
BOOL alphaFirst = NO;
BOOL alphaPremultiplied = NO;
BOOL byteOrderNormal = NO;
switch (bitmapInfo & kCGBitmapAlphaInfoMask) {
case kCGImageAlphaPremultipliedLast: {
hasAlpha = YES;
alphaPremultiplied = YES;
} break;
case kCGImageAlphaPremultipliedFirst: {
hasAlpha = YES;
alphaPremultiplied = YES;
alphaFirst = YES;
} break;
case kCGImageAlphaLast: {
hasAlpha = YES;
} break;
case kCGImageAlphaFirst: {
hasAlpha = YES;
alphaFirst = YES;
} break;
case kCGImageAlphaNoneSkipLast: {
} break;
case kCGImageAlphaNoneSkipFirst: {
alphaFirst = YES;
} break;
default: {
return NO;
} break;
}
switch (bitmapInfo & kCGBitmapByteOrderMask) {
case kCGBitmapByteOrderDefault: {
byteOrderNormal = YES;
} break;
case kCGBitmapByteOrder32Little: {
} break;
case kCGBitmapByteOrder32Big: {
byteOrderNormal = YES;
} break;
default: {
return NO;
} break;
}
/*
Try convert with vImageConvert_AnyToAny() (avaliable since iOS 7.0).
If fail, try decode with CGContextDrawImage().
CGBitmapContext use a premultiplied alpha format, unpremultiply may lose precision.
*/
vImage_CGImageFormat destFormat = {0};
destFormat.bitsPerComponent = 8;
destFormat.bitsPerPixel = 32;
destFormat.colorSpace = YYCGColorSpaceGetDeviceRGB();
destFormat.bitmapInfo = bitmapInfo;
dest->data = NULL;
if (YYCGImageDecodeToBitmapBufferWithAnyFormat(srcImage, dest, &destFormat)) return YES;
CGBitmapInfo contextBitmapInfo = bitmapInfo & kCGBitmapByteOrderMask;
if (!hasAlpha || alphaPremultiplied) {
contextBitmapInfo |= (bitmapInfo & kCGBitmapAlphaInfoMask);
} else {
contextBitmapInfo |= alphaFirst ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaPremultipliedLast;
}
CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 0, YYCGColorSpaceGetDeviceRGB(), contextBitmapInfo);
if (!context) goto fail;
CGContextDrawImage(context, CGRectMake(0, 0, width, height), srcImage); // decode and convert
size_t bytesPerRow = CGBitmapContextGetBytesPerRow(context);
size_t length = height * bytesPerRow;
void *data = CGBitmapContextGetData(context);
if (length == 0 || !data) goto fail;
dest->data = malloc(length);
dest->width = width;
dest->height = height;
dest->rowBytes = bytesPerRow;
if (!dest->data) goto fail;
if (hasAlpha && !alphaPremultiplied) {
vImage_Buffer tmpSrc = {0};
tmpSrc.data = data;
tmpSrc.width = width;
tmpSrc.height = height;
tmpSrc.rowBytes = bytesPerRow;
vImage_Error error;
if (alphaFirst && byteOrderNormal) {
error = vImageUnpremultiplyData_ARGB8888(&tmpSrc, dest, kvImageNoFlags);
} else {
error = vImageUnpremultiplyData_RGBA8888(&tmpSrc, dest, kvImageNoFlags);
}
if (error != kvImageNoError) goto fail;
} else {
memcpy(dest->data, data, length);
}
CFRelease(context);
return YES;
fail:
if (context) CFRelease(context);
if (dest->data) free(dest->data);
dest->data = NULL;
return NO;
return NO;
}