iOS13中UIImageJPEGRepresentation和UIImagePNGRepresentation返回nil问题求助
解决iOS13中PNG图片转NSData返回nil及全白问题
我之前在适配iOS13的时候也碰到过完全一样的问题,当时折腾了好一阵子,结合你的场景,给你几个经过验证的可行方案:
方案一:用UIGraphicsImageRenderer替代旧的绘图API
你之前用UIGraphicsBeginImageContext复制图片后出现全白,很大概率是因为这个旧API没有正确处理Retina屏幕的缩放因子,以及PNG图片的alpha通道。改用苹果推荐的UIGraphicsImageRenderer就能解决这个问题:
// 针对原图片的尺寸创建渲染器 UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:image.size]; UIImage *processedImage = [renderer imageWithActions:^(UIGraphicsImageRendererContext *context) { // 直接在渲染器上下文中绘制原图片 [image drawAtPoint:CGPointZero]; }]; // 现在再转格式就不会返回nil,也不会全白了 NSData *jpegData = UIImageJPEGRepresentation(processedImage, 1.0); NSData *pngData = UIImagePNGRepresentation(processedImage);
方案二:转换图片到RGB颜色空间
iOS13对非RGB颜色空间的PNG(比如灰度图、索引色PNG)处理逻辑有变化,直接转格式会返回nil。我们可以先把图片转换为RGB颜色空间再处理:
CGImageRef originalCGImage = image.CGImage; CGColorSpaceRef originalColorSpace = CGImageGetColorSpace(originalCGImage); // 判断是否为非RGB颜色空间 if (!CGColorSpaceIsRGB(originalColorSpace)) { CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB(); // 创建RGB颜色空间的位图上下文 CGContextRef rgbContext = CGBitmapContextCreate(NULL, CGImageGetWidth(originalCGImage), CGImageGetHeight(originalCGImage), 8, // 每个颜色分量的比特数 CGImageGetWidth(originalCGImage) * 4, // 每行字节数 rgbColorSpace, kCGImageAlphaPremultipliedLast); // 在RGB上下文中绘制原图片 CGContextDrawImage(rgbContext, CGRectMake(0, 0, CGImageGetWidth(originalCGImage), CGImageGetHeight(originalCGImage)), originalCGImage); // 从上下文生成新的CGImage和UIImage CGImageRef rgbCGImage = CGBitmapContextCreateImage(rgbContext); UIImage *rgbImage = [UIImage imageWithCGImage:rgbCGImage scale:image.scale orientation:image.imageOrientation]; // 释放资源(重要!避免内存泄漏) CGContextRelease(rgbContext); CGColorSpaceRelease(rgbColorSpace); CGImageRelease(rgbCGImage); // 现在转格式就正常了 NSData *jpegData = UIImageJPEGRepresentation(rgbImage, 1.0); }
方案三:直接从PHAsset获取原始图片数据
如果你是用UIImagePickerController选图,其实可以通过PHAsset直接获取原始的图片数据,跳过中间的UIImage转换环节,从根源避免问题:
// 假设你已经从图片选择器的info字典中拿到了PHAsset对象 PHAsset *selectedAsset = info[UIImagePickerControllerPHAsset]; PHImageRequestOptions *requestOptions = [[PHImageRequestOptions alloc] init]; requestOptions.synchronous = YES; // 同步请求(也可以用异步,根据你的需求调整) requestOptions.version = PHImageRequestOptionsVersionCurrent; requestOptions.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat; [[PHImageManager defaultManager] requestImageDataForAsset:selectedAsset options:requestOptions resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) { if (imageData) { // 这里拿到的是原始图片数据,你可以直接使用,也可以转成UIImage再处理 UIImage *processedImage = [UIImage imageWithData:imageData scale:image.scale orientation:orientation]; NSData *jpegData = UIImageJPEGRepresentation(processedImage, 1.0); } }];
为什么之前的复制会出现全白?
你之前用UIGraphicsBeginImageContext的方式,默认创建的上下文缩放因子为1,而Retina屏幕上的图片scale是2或3,绘制时没有匹配scale会导致图片尺寸错位;另外,这个API对带alpha通道的PNG处理不够友好,容易丢失透明度信息,最终导致绘制出全白的图片。
内容的提问来源于stack exchange,提问作者Rotem Yakov
相关产品推荐
相关产品推荐

