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)
}
}
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744198973a4562791.html
评论列表(0条)