app上传前的原图与上传后CDN上压缩图对比颜色有失真
具体描述可见:拒绝黯淡!教你还原iPhone 7照片本色
问题的原因与文中一致, 我们CDN压缩图片是用的sRGB色域, iPhone 7以后用的是Display P3色域
解决方案: 上传前对图片色域进行转换
具体步骤:
- 先获取图片源的色域(colorspace)与目标色域(iOS9以上为kCGColorSpaceSRGB, iOS9以下为CGColorSpaceCreateDeviceRGB(), 两者色域相同不处理)
- 初始化源图buffer和目标图buffer
- 初始化输入色域格式与输出色域格式并构造转换器
- 利用转换器和转换函数vImageConvert_AnyToAny生成目标图buffer
- 最后通过目标图buffer生成目标图片
代码如下:
#import <Accelerate/Accelerate.h>
@implementation UIImage (sRGB)
- (UIImage *)mz_convertToSRGBColorSpace
{
UIImage *newImage = self;
do {
CGImageRef CGImage = self.CGImage;
CGColorSpaceRef srcSpace = CGImageGetColorSpace(CGImage);
CGColorSpaceRef dstSpace = [UIDevice currentDevice].systemVersion.floatValue >= 9.0 ? CGColorSpaceCreateWithName(kCGColorSpaceSRGB) : CGColorSpaceCreateDeviceRGB();
// 颜色空间一样直接返回 self
if (CFEqual(srcSpace, CFAutorelease(CGColorSpaceCreateDeviceRGB())) ||
CFEqual(srcSpace, dstSpace)) {
CGColorSpaceRelease(dstSpace);
break;
}
vImage_Buffer srcBuffer;
vImage_Buffer dstBuffer;
vImage_CGImageFormat srcFormat = {
.bitsPerComponent = (uint32_t)CGImageGetBitsPerComponent(CGImage),
.bitsPerPixel = (uint32_t)CGImageGetBitsPerPixel(CGImage),
.colorSpace = srcSpace,
.bitmapInfo = CGImageGetBitmapInfo(CGImage)
};
vImage_CGImageFormat dstFormat = {
.bitsPerComponent = (uint32_t)CGImageGetBitsPerComponent(CGImage),
.bitsPerPixel = (uint32_t)CGImageGetBitsPerPixel(CGImage),
.colorSpace = dstSpace,
.bitmapInfo = CGImageGetBitmapInfo(CGImage)
};
vImage_Error error = kvImageNoError;
error = vImageBuffer_InitWithCGImage(&srcBuffer, &srcFormat, NULL, CGImage, kvImageNoFlags);
if (error != kvImageNoError) {
CGColorSpaceRelease(dstSpace);
break;
}
vImageConverterRef convertRef = vImageConverter_CreateWithCGImageFormat(&srcFormat, &dstFormat, NULL, kvImageNoFlags, &error);
if (error != kvImageNoError) {
free(srcBuffer.data);
CGColorSpaceRelease(dstSpace);
break;
}
error = vImageBuffer_Init(&dstBuffer, srcBuffer.height, srcBuffer.width, dstFormat.bitsPerPixel, kvImageNoFlags);
if (error != kvImageNoError) {
free(srcBuffer.data);
CGColorSpaceRelease(dstSpace);
vImageConverter_Release(convertRef);
break;
}
error = vImageConvert_AnyToAny(convertRef, &srcBuffer, &dstBuffer, NULL, kvImageNoFlags);
if (error != kvImageNoError) {
free(srcBuffer.data);
free(dstBuffer.data);
CGColorSpaceRelease(dstSpace);
vImageConverter_Release(convertRef);
break;
}
CGImageRef newCGImage = vImageCreateCGImageFromBuffer(&dstBuffer, &dstFormat, NULL, NULL, kvImageNoFlags, &error);
if (error != kvImageNoError) {
if (newCGImage) {
CGImageRelease(newCGImage);
}
free(srcBuffer.data);
free(dstBuffer.data);
CGColorSpaceRelease(dstSpace);
vImageConverter_Release(convertRef);
break;
}
newImage = [UIImage imageWithCGImage:newCGImage];
free(srcBuffer.data);
free(dstBuffer.data);
CGImageRelease(newCGImage);
CGColorSpaceRelease(dstSpace);
vImageConverter_Release(convertRef);
} while(0);
return newImage;
}
@end
依赖苹果原生图片bitmap处理库Accelerate库, 经测试单张1080px图的处理需要大概10ms左右
源码来源