admin管理员组文章数量:1398999
Apple provides several methods to take a UIView snapshot as a UIImage, such as UIGraphicsImageRenderer
and drawHierarchy(in:)
. However, none of them are fast enough for my needs.
So, I decided to use a private API for this purpose.
I tried using the approach from , but I always end up with a white image. How can I fix the white image issue?
import UIKit
import IOSurface
typealias CARenderServerRenderDisplayType = @convention(c) (UInt32, CFString, IOSurfaceRef, Int, Int) -> Void
// Function to load the private API
func getCARenderServerRenderDisplay() -> CARenderServerRenderDisplayType? {
let handle = dlopen("/System/Library/Frameworks/QuartzCore.framework/QuartzCore", RTLD_LAZY)
guard let symbol = dlsym(handle, "CARenderServerRenderDisplay") else {
print("CARenderServerRenderDisplay not found")
return nil
}
return unsafeBitCast(symbol, to: CARenderServerRenderDisplayType.self)
}
extension UIView {
func fastScreenshot() -> UIImage? {
let screenSize = UIScreen.main.bounds.size
let scale = UIScreen.main.scale
let width = Int(screenSize.width * scale)
let height = Int(screenSize.height * scale)
let bytesPerElement = 4
let bytesPerRow = bytesPerElement * width
let totalBytes = bytesPerRow * height
let properties: [CFString: Any] = [
kIOSurfaceIsGlobal: true,
kIOSurfaceBytesPerElement: bytesPerElement,
kIOSurfaceBytesPerRow: bytesPerRow,
kIOSurfaceWidth: width,
kIOSurfaceHeight: height,
kIOSurfacePixelFormat: 0x42475241, // ARGB format
kIOSurfaceAllocSize: totalBytes
]
guard let surface = IOSurfaceCreate(properties as CFDictionary) else { return nil }
// Lock the surface
IOSurfaceLock(surface, [], nil)
// Fast screenshot capture using a private API (similarly to the method from the code you shared)
if let renderFunction = getCARenderServerRenderDisplay() {
renderFunction(0, "LCD" as CFString, surface, 0, 0)
} else {
print("Failed to find CARenderServerRenderDisplay")
}
// Get the raw pixel data
let baseAddress = IOSurfaceGetBaseAddress(surface)
let data = Data(bytes: baseAddress, count: totalBytes)
// Unlock the surface
IOSurfaceUnlock(surface, [], nil)
// Convert raw data into CGImage
guard let provider = CGDataProvider(data: data as CFData) else { return nil }
guard let imageRef = CGImage(
width: width,
height: height,
bitsPerComponent: 8,
bitsPerPixel: 8 * bytesPerElement,
bytesPerRow: bytesPerRow,
space: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.first.rawValue),
provider: provider,
decode: nil,
shouldInterpolate: false,
intent: .defaultIntent
) else { return nil }
return UIImage(cgImage: imageRef)
}
}
本文标签: uikitFastest way to capture a UIView snapshot as a UIImage using a private APIStack Overflow
版权声明:本文标题:uikit - Fastest way to capture a UIView snapshot as a UIImage using a private API - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744198972a2594875.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论