关于使用UIKit、CoreGraphics、ImageIO这3种图片缩略技术该如何针对不同的image.scale作相应处理

献上Demo链接

首先感谢这位博主的分享:iOS的5种图片缩略技术以及性能探讨
从这篇博客中了解到5种图片缩略技术以及性能,其中在性能上 UIKitCoreGraphicsImageIO 这3种方式是最常用的,所以另外两种就不作探讨了。

可是这里有一个问题:文章中没有针对不同的 image.scale 做相应的缩略处理,图片的清晰度也因此不一样,所以我尝试在博主方法的基础上添加 scale 处理(由于该博客中用的是Swift,而我的项目用得比较多的是OC,所以我这里是对博主的方法“翻译”后再进行修改):

UIKit

/** UI缩略(按比例缩略) */
- (UIImage *)jp_uiResizeImageWithScale:(CGFloat)scale {
    return [self jp_uiResizeImageWithLogicWidth:(self.size.width * scale)];
}

/** UI缩略(按逻辑宽度缩略) */
- (UIImage *)jp_uiResizeImageWithLogicWidth:(CGFloat)logicWidth {
    if (logicWidth >= self.size.width) return self;
    CGFloat w = logicWidth;
    CGFloat h = w * (self.size.height / self.size.width);
    @autoreleasepool {
        UIGraphicsBeginImageContextWithOptions(CGSizeMake(w, h), NO, self.scale);
        [self drawInRect:CGRectMake(0, 0, w, h)];
        UIImage *resizedImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return resizedImage;
    }
}

/** UI缩略(按像素宽度缩略) */
- (UIImage *)jp_uiResizeImageWithPixelWidth:(CGFloat)pixelWidth {
    return [self jp_uiResizeImageWithLogicWidth:(pixelWidth / self.scale)];
}
  • PS:这里使用的是 UIGraphicsBeginImageContextWithOptions,因为可以设置 scale,如果使用的是 UIGraphicsBeginImageContext,其实就是相当于使用了UIGraphicsBeginImageContextWithOptions(size, NO, 1.0)

CoreGraphics

/** CG缩略(按比例缩略) */
- (UIImage *)jp_cgResizeImageWithScale:(CGFloat)scale {
    return [self jp_cgResizeImageWithLogicWidth:(self.size.width * scale)];
}

/** CG缩略(按逻辑宽度缩略) */
- (UIImage *)jp_cgResizeImageWithLogicWidth:(CGFloat)logicWidth {
    return [self jp_cgResizeImageWithPixelWidth:(logicWidth * self.scale)];
}

/** CG缩略(按像素宽度缩略) */
- (UIImage *)jp_cgResizeImageWithPixelWidth:(CGFloat)pixelWidth {
    CGImageRef cgImage = self.CGImage;
    if (!cgImage) return self;
    
    if (pixelWidth >= (self.size.width * self.scale)) return self;
    CGFloat pixelHeight = pixelWidth * self.jp_hwRatio;
    
//    size_t bitsPerComponent = CGImageGetBitsPerComponent(cgImage);
//    size_t bytesPerRow = CGImageGetBytesPerRow(cgImage);
//    CGColorSpaceRef colorSpace = CGImageGetColorSpace(cgImage);
//    CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(cgImage);
//    CGContextRef context = CGBitmapContextCreate(NULL, pixelWidth, pixelHeight, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo);
    /**
     * 在某些手机快捷键屏幕截图生成的图片,通过上面方式创建的 context 为空
     * 因为生成的图片的 CGBitmapInfo 为 kCGImageAlphaLast 或 kCGImageByteOrder16Little,iOS不支持这种格式。
     * 参考:https://www.jianshu.com/p/2e45a2ea7b62
     * 解决方法:context 的创建采用了 YYKit 的方式。
     */
    
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    
    CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(cgImage) & kCGBitmapAlphaInfoMask;
    BOOL hasAlpha = NO;
    if (alphaInfo == kCGImageAlphaPremultipliedLast ||
        alphaInfo == kCGImageAlphaPremultipliedFirst ||
        alphaInfo == kCGImageAlphaLast ||
        alphaInfo == kCGImageAlphaFirst) {
        hasAlpha = YES;
    }
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host;
    bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst;
    
    CGContextRef context = CGBitmapContextCreate(NULL, pixelWidth, pixelHeight, 8, 0, colorSpace, bitmapInfo);
    
    CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
    CGContextDrawImage(context, CGRectMake(0, 0, pixelWidth, pixelHeight), cgImage);
    CGImageRef resizedCGImage = CGBitmapContextCreateImage(context);
    
    UIImage *resizedImage = [UIImage imageWithCGImage:resizedCGImage scale:self.scale orientation:self.imageOrientation];
    
    CGColorSpaceRelease(colorSpace);
    CGContextRelease(context);
    CGImageRelease(resizedCGImage);
    
    return resizedImage;
}
  • PS:使用 CoreGraphics 的方法时,记得最后要 Release。另外在某些手机快捷键屏幕截图生成的图片,创建的 context 会有为空的情况,感谢大神博主的分享,解释了其产生原因及解决方法:CGBitmapContextCreate: unsupported parameter combination问题调查及解决

ImageIO

/** IO缩略(按比例缩略) */
- (UIImage *)jp_ioResizeImageWithScale:(CGFloat)scale isPNGType:(BOOL)isPNGType {
    return [self jp_ioResizeImageWithLogicWidth:(self.size.width * scale) isPNGType:isPNGType];
}

/** IO缩略(按逻辑宽度缩略) */
- (UIImage *)jp_ioResizeImageWithLogicWidth:(CGFloat)logicWidth isPNGType:(BOOL)isPNGType {
    return [self jp_ioResizeImageWithPixelWidth:(logicWidth * self.scale) isPNGType:isPNGType];
}

/** IO缩略(按像素宽度缩略) */
- (UIImage *)jp_ioResizeImageWithPixelWidth:(CGFloat)pixelWidth isPNGType:(BOOL)isPNGType {
    if (pixelWidth >= (self.size.width * self.scale)) return self;
    
    NSData *data = isPNGType ? UIImagePNGRepresentation(self) : UIImageJPEGRepresentation(self, 1);
    if (!data) return nil;
    CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)data, nil);
    
    CGFloat hwRatio = self.size.height / self.size.width;
    CGFloat maxPixelValue = (hwRatio > 1.0) ? (pixelWidth * hwRatio) : pixelWidth;
    // 因为kCGImageSourceCreateThumbnailFromImageAlways会一直创建缩略图,造成内存浪费
    // 所以使用kCGImageSourceCreateThumbnailFromImageIfAbsent
    NSDictionary *options = @{(id)kCGImageSourceCreateThumbnailWithTransform : @(YES),
                              (id)kCGImageSourceCreateThumbnailFromImageIfAbsent : @(YES),
                              (id)kCGImageSourceThumbnailMaxPixelSize : @(maxPixelValue)};
    
    CGImageRef resizedCGImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, (CFDictionaryRef)options);
    UIImage *resizedImage = [UIImage imageWithCGImage:resizedCGImage scale:self.scale orientation:self.imageOrientation];
    
    CFRelease(imageSource);
    CGImageRelease(resizedCGImage);
    
    return resizedImage;
}
  • PS:这里非常感谢另一位博主的文章:iOS 修改图片尺寸的方法,以及ImageContext内存占用的问题 ,该博主帮我解答了如何针对不同 scale 作相应处理,另外也说明了不使用 kCGImageSourceCreateThumbnailFromImageAlways 是因为会一直创建缩略图,有可能会造成内存浪费,所以使用 kCGImageSourceCreateThumbnailFromImageIfAbsent
缩略后的图片对比:
关于使用UIKit、CoreGraphics、ImageIO这3种图片缩略技术该如何针对不同的image.scale作相应处理_第1张图片
缩略后的图片对比
关于使用UIKit、CoreGraphics、ImageIO这3种图片缩略技术该如何针对不同的image.scale作相应处理_第2张图片
各图片的数据对比

经修改后,在缩略比例为50%、不同的 image.scale 环境下,图片缩略后清晰度几乎一样了,并且从这几种方法中得知,UI方式缩略后的图片最小,缩略速度跟CG方式接近,不过可能是我自己的方法有错误,有待验证。

如果有小伙伴发现了错误的地方请务必告诉我哦~感激不尽!
献上Demo链接

你可能感兴趣的:(关于使用UIKit、CoreGraphics、ImageIO这3种图片缩略技术该如何针对不同的image.scale作相应处理)