因此,基于KenThomases的精彩回答和一天的测试,以下是如何在物理像素级别绘制的确切方法。我想。
class PixelwiseLayer: CALayer {
override init() {
super.init()
contentsScale = UIScreen.main.scale
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override open func draw(in ctx: CGContext) {
let rectDEVICESPACE = ctx.convertToDeviceSpace(bounds).size
let img = pixelByPixelImage(sizeInDeviceSpace: rectDEVICESPACE)
ctx.draw(img, in: bounds)
}
private func pixelByPixelImage(sizeInDeviceSpace: CGSize) -> CGImage {
let wPIXELS = Int(sizeInDeviceSpace.width)
let hPIXELS = Int(sizeInDeviceSpace.height)
let bitsPerComponent: Int = MemoryLayout<UInt8>.size * 8
let bytesPerPixel: Int = bitsPerComponent * 4 / 8
let colorSpace: CGColorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
var data = [RGBA]()
for y in 0..<hPIXELS {
for x in 0..<wPIXELS {
let c = yourPixelColor(atPoint: x .. y)
data.append(c)
}
}
let ctx = CGContext(data: &data,
width: wPIXELS, height: hPIXELS,
bitsPerComponent: bitsPerComponent,
bytesPerRow: wPIXELS * bytesPerPixel,
space: colorSpace,
bitmapInfo: bitmapInfo.rawValue)
let img = ctx?.makeImage()!
return img!
}
}
fileprivate struct RGBA {
var r: UInt8
var g: UInt8
var b: UInt8
var a: UInt8
}
关键要素:
首先...
super.init()
// SET THE CONTENT SCALE >>>>AT INITIALIZATION TIME<<<<
contentsScale = UIScreen.main.scale
第二个...
override open func draw(in ctx: CGContext) {
realPixelSize = ctx.convertToDeviceSpace(bounds).size
...
}
第三个...
override open func draw(in ctx: CGContext) {
...
your image = yourPixelDrawingFunction( realPixelSize )
ctx.draw(img, in: bounds)
}
例子 ...
console:
contentsScale 3.0
UIScreen.main.scale 3.0
bounds (0.0, 0.0, 84.0, 84.0)
rectDEVICESPACE (252.0, 252.0)
actual pixels being created as data: w, h 252, 252
在初始化时设置contentsScale
非常关键。
我尝试了一些操作系统版本,不管好坏,图层contentsScale
的默认值似乎是“1”,而不是屏幕密度,因此,请不要忘记设置它!(注意,操作系统中的其他系统也将使用它来有效地处理您的图层等。)