我的应用程序需要渲染场强,即矩形视图中函数 f(x,y) 的值。
我知道我可以渲染线性或径向渐变,请参见here,但我没有找到一种方法来根据函数 f(x,y) 设置视图像素的亮度或不透明度。
我可能可以组装很多子视图的视图,其中每个子视图的亮度或不透明度是根据这样的函数设置的,但这很丑陋,应该有更好的方法。
有什么建议吗?
这是我的解决方案,基于上面lorem ipsum的建议。
此建议需要计算
Image
并将其覆盖在 View
上。
因此,我将以下扩展写入
Image
:
extension Image {
/// Creates an Image of a given size with a given color.
/// The color, without the alpha value, is here hard coded, but could of course be given by a parameter.
/// The alpha value represents the field function, depending on the (x,y) pixel value.
/// - Parameters:
/// - size: The size of the resulting image
/// - alpha: The field function
init?(size: CGSize, alpha: (_ x: Int, _ y: Int) -> Double) {
// Set color components as 8 bits in hex. Alpha will be taken from the function parameter.
// Pixel values are 32 bits: ARGB
let r: UInt32 = 0x00 << 16
let g: UInt32 = 0x00 << 8
let b: UInt32 = 0xFF
let pixelWidth = Int(size.width)
let pixelHeight = Int(size.height)
var srgbArray: [UInt32] = [] // The pixel array
// Compute field values
for y in 0 ..< pixelHeight {
for x in 0 ..< pixelWidth {
let fieldStrength = alpha(x, y)
if fieldStrength < 0 || fieldStrength > 1.0 {
return nil // The alpha function did return an illegal value (< 0 or > 1).
}
let a = UInt32(fieldStrength * 255.0) << 24 // alpha
srgbArray.append(a | r | g | b)
}
}
// https://forums.swift.org/t/creating-a-cgimage-from-color-array/18634
let cgImg = srgbArray.withUnsafeMutableBytes { ptr -> CGImage in
let ctx = CGContext(
data: ptr.baseAddress,
width: pixelWidth,
height: pixelHeight,
bitsPerComponent: 8,
bytesPerRow: 4 * pixelWidth,
space: CGColorSpace(name: CGColorSpace.sRGB)!,
bitmapInfo: CGBitmapInfo.byteOrder32Little.rawValue + CGImageAlphaInfo.premultipliedFirst.rawValue
)!
return ctx.makeImage()!
}
self.init(
cgImg,
scale: 1.0,
orientation: .up,
label: Text("Field")
)
}
}
Image
初始化为
let image = Image(size: fieldSize, alpha: alpha(x:y:))
其中函数
alpha
可以是任何函数。在这里,出于演示目的,我使用以下函数:
func alpha(x: Int, y: Int) -> Double {
Field.borderfield(size: fieldSize, x: x, y: y)
}
与
struct Field {
static func borderfield(size: CGSize, x: Int, y: Int) -> Double {
let a = Int(size.width)
let b = Int(size.height)
assert(x >= 0 && x <= a)
assert(y >= 0 && y <= b)
// Compute distance to border
let dt = b - y // Distance to top
let db = y // Distance to bottom
let dl = x // Distance to left
let dr = a - x // Distance to right
let minDistance = min(dt, db, dl, dr)
let d = Double(minDistance)
let r = d + 1.0 // min r is now 1
let signalStrength = 1.0/sqrt(r)
print(signalStrength)
return signalStrength
}
}
函数
borderfield
是对显示矩形的带电边框产生的场的非常粗略的近似。