如上图二十多MB的图渲染
- 设置UIImageView
let imageView = UIImageView(frame: CGRect(x: 10.0, y: 74.0, width: (ScreenWith - 20.0), height: (ScreenWith - 20.0)))
imageView.backgroundColor = .orange
self.view.addSubview(imageView)
- 等比例处理ImageView的size
// size 的计量单位不是用 pixel,而是用 point。想要计算出你调整大小后图像的等效尺寸,用主 UIScreen 的 scale,等比例放大你 UIImageView 的 size 大小
let screenScale = UIScreen.main.scale
let transform = CGAffineTransform(scaleX: screenScale, y: screenScale)
let size = imageView.bounds.size.applying(transform)
- 渲染展示图片
DispatchQueue.global(qos: .default).async {
let start = CACurrentMediaTime()
guard let path = Bundle.main.path(forResource: "VIIRS_3Feb2012_lrg.jpg", ofType: nil) else {
fatalError("没找到资源")
}
guard let url = Bundle.main.url(forResource: "VIIRS_3Feb2012_lrg.jpg", withExtension: nil) else {
fatalError("Bundle.main.url 没找到资源")
}
// let image = UIImage(contentsOfFile: path)
// let image = CoreGraphicsManager.imageRenderOfCoreGraphics(url: url, size: size) // CoreGraphics
// let image = CoreImageManager.renderImageOfCoreImage(url: url, size: size)
// let image = ImageIO.renderImage(url: url, size: size)
// let image = ImageIO.renderImageWithHintingAndSubsampling(url: url, size: size)
// let image = VImage.renderVImage(url: url, size: size)
let image = self.renderImageWithUIKit(url: url, size: size)
DispatchQueue.main.async {
let duration = 1.0
UIView.transition(with: imageView, duration: duration, options: [.curveEaseInOut,.transitionCrossDissolve]) {
imageView.image = image
} completion: { (result) in
let end = CACurrentMediaTime()
print("耗时: \(end - start - duration)")
}
}
}
- 根据上面的代码有七种方式,这七种渲染方式效果对比如下
UIImage - 耗时: 2.272907687998668 内存 561MB
CoreGraphics - 耗时: 1.3122502480000549 内存 16.2MB
CoreImage - 耗时: 5.254483673999857 内存 20MB
ImageIO 第一种方式 - 耗时: 1.0823896530000638 内存 15MB
第二种方式 - 耗时: 1.0853783849997853 内存 15MB
vImage - 耗时: 2.418650589999743 内存 18MB
UIGraphicsImageRenderer - 耗时: 0.9039393570001266 内存 15MB
- CoreGraphics
class CoreGraphicsManager: NSObject {
static func imageRenderOfCoreGraphics(url:URL,size:CGSize) -> UIImage? {
guard size != .zero else {
debugPrint("图片大小不能为零")
return nil
}
guard let imageSource = CGImageSourceCreateWithURL(url as CFURL, nil),
let image = CGImageSourceCreateImageAtIndex(imageSource, 0, nil) else {
debugPrint("CGImageSourceCreate Error")
return nil
}
let context = CGContext(data: nil,
width: Int(size.width),
height: Int(size.height),
bitsPerComponent: image.bitsPerComponent,
bytesPerRow: image.bytesPerRow,
space: image.colorSpace ?? CGColorSpace(name: CGColorSpace.sRGB)!,
bitmapInfo: image.bitmapInfo.rawValue)
context?.interpolationQuality = .high
context?.draw(image, in: CGRect(origin: .zero, size: size))
guard let cgImage = context?.makeImage() else {
debugPrint("cgImage nil")
return nil
}
return UIImage(cgImage: cgImage)
}
}
- CoreImage
class CoreImageManager: NSObject {
static let sharedContext = CIContext(options: [.useSoftwareRenderer : false])
static func renderImageOfCoreImage(url:URL,size:CGSize) -> UIImage? {
precondition(size != .zero)
guard let imageSource = CGImageSourceCreateWithURL(url as NSURL, nil),
let properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? [CFString: Any],
let imageWidth = properties[kCGImagePropertyPixelWidth] as? CGFloat,
let imageHeight = properties[kCGImagePropertyPixelHeight] as? CGFloat
else {
return nil
}
let scale = max(size.width, size.height) / max(imageWidth, imageHeight)
guard scale >= 0, !scale.isInfinite, !scale.isNaN else { return nil }
let aspectRatio = imageWidth / imageHeight
guard aspectRatio >= 0, !aspectRatio.isInfinite, !aspectRatio.isNaN else { return nil }
guard let image = CIImage(contentsOf: url) else {
return nil
}
let filter = CIFilter(name: "CILanczosScaleTransform")
filter?.setValue(image, forKey: kCIInputImageKey)
filter?.setValue(scale, forKey: kCIInputScaleKey)
filter?.setValue(aspectRatio, forKey: kCIInputAspectRatioKey)
guard let outputCIImage = filter?.outputImage,
let outputCGImage = sharedContext.createCGImage(outputCIImage, from: outputCIImage.extent)
else {
return nil
}
return UIImage(cgImage: outputCGImage)
}
}
- ImageIO
import MobileCoreServices
class ImageIO: NSObject {
static func renderImage(url:URL,size:CGSize) -> UIImage? {
precondition(size != .zero)
let options: [CFString: Any] = [
kCGImageSourceThumbnailMaxPixelSize: max(size.width, size.height),
kCGImageSourceCreateThumbnailFromImageAlways: true,
kCGImageSourceCreateThumbnailWithTransform: true
]
guard let imageSource = CGImageSourceCreateWithURL(url as NSURL, nil),
let image = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary)
else {
return nil
}
return UIImage(cgImage: image)
}
static func renderImageWithHintingAndSubsampling(url:URL,size:CGSize) -> UIImage? {
precondition(size != .zero)
guard let imageSource = CGImageSourceCreateWithURL(url as NSURL, nil),
let properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? [CFString: Any],
let imageWidth = properties[kCGImagePropertyPixelWidth] as? CGFloat,
let imageHeight = properties[kCGImagePropertyPixelHeight] as? CGFloat
else {
return nil
}
var options: [CFString: Any] = [
kCGImageSourceThumbnailMaxPixelSize: max(size.width, size.height),
kCGImageSourceCreateThumbnailFromImageAlways: true,
kCGImageSourceCreateThumbnailWithTransform: true
]
if let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, url.pathExtension as CFString, kUTTypeImage)?.takeRetainedValue() {
options[kCGImageSourceTypeIdentifierHint] = uti
if uti == kUTTypeJPEG || uti == kUTTypeTIFF || uti == kUTTypePNG ||
String(uti).hasPrefix("public.heif")
{
switch min(imageWidth / size.width, imageHeight / size.height) {
case ...2.0:
options[kCGImageSourceSubsampleFactor] = 2.0
case 2.0...4.0:
options[kCGImageSourceSubsampleFactor] = 4.0
case 4.0...:
options[kCGImageSourceSubsampleFactor] = 8.0
default:
break
}
}
}
guard let image = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary) else {
return nil
}
return UIImage(cgImage: image)
}
}
- VImage
import Accelerate.vImage
class VImage: NSObject {
static func renderVImage(url:URL,size:CGSize) -> UIImage? {
precondition(size != .zero)
// Decode the source image
guard let imageSource = CGImageSourceCreateWithURL(url as NSURL, nil),
let image = CGImageSourceCreateImageAtIndex(imageSource, 0, nil),
let properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? [CFString: Any],
let imageWidth = properties[kCGImagePropertyPixelWidth] as? vImagePixelCount,
let imageHeight = properties[kCGImagePropertyPixelHeight] as? vImagePixelCount
else {
return nil
}
// Define the image format
var format = vImage_CGImageFormat(bitsPerComponent: 8,
bitsPerPixel: 32,
colorSpace: nil,
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.first.rawValue),
version: 0,
decode: nil,
renderingIntent: .defaultIntent)
var error: vImage_Error
// Create and initialize the source buffer
var sourceBuffer = vImage_Buffer()
defer { sourceBuffer.data.deallocate() }
error = vImageBuffer_InitWithCGImage(&sourceBuffer,
&format,
nil,
image,
vImage_Flags(kvImageNoFlags))
guard error == kvImageNoError else { return nil }
// Create and initialize the destination buffer
var destinationBuffer = vImage_Buffer()
error = vImageBuffer_Init(&destinationBuffer,
vImagePixelCount(size.height),
vImagePixelCount(size.width),
format.bitsPerPixel,
vImage_Flags(kvImageNoFlags))
guard error == kvImageNoError else { return nil }
// Scale the image
error = vImageScale_ARGB8888(&sourceBuffer,
&destinationBuffer,
nil,
vImage_Flags(kvImageNoFlags))
guard error == kvImageNoError else { return nil }
// Create a CGImage from the destination buffer
guard let resizedImage =
vImageCreateCGImageFromBuffer(&destinationBuffer,
&format,
nil,
nil,
vImage_Flags(kvImageNoAllocate),
&error)?.takeRetainedValue(),
error == kvImageNoError
else {
return nil
}
return UIImage(cgImage: resizedImage)
}
}
- UIGraphicsImageRenderer
func renderImageWithUIKit(url:URL,size:CGSize) -> UIImage? {
guard let image = UIImage(contentsOfFile: url.path) else {
return nil
}
let renderer = UIGraphicsImageRenderer(size: size)
return renderer.image { (context) in
image.draw(in: CGRect(origin: .zero, size: size))
}
}