快速 - 每像素绘图UIView像素的速度提升

时间:2017-08-07 18:21:30

标签: ios performance uiview pixel

有没有办法提高每像素绘制像素到UIView的速度/性能?

500x500像素UIView的当前实现非常慢。

class CustomView: UIView {

public var context = UIGraphicsGetCurrentContext()

public var redvalues = [[CGFloat]](repeating: [CGFloat](repeating: 1.0, count: 500), count: 500)

public var start = 0
{
didSet{
    self.setNeedsDisplay()
}
}

override func draw(_ rect: CGRect
{
super.draw(rect)
context = UIGraphicsGetCurrentContext()
for yindex in 0...499{
    for xindex in 0...499 {
        context?.setStrokeColor(UIColor(red: redvalues[xindex][yindex], green: 0.0, blue: 0.0, alpha: 1.0).cgColor)

        context?.setLineWidth(2)
        context?.beginPath()
        context?.move(to: CGPoint(x: CGFloat(xindex), y: CGFloat(yindex)))
        context?.addLine(to: CGPoint(x: CGFloat(xindex)+1.0, y: CGFloat(yindex)))
        context?.strokePath()
    }
}
}
}

非常感谢

3 个答案:

答案 0 :(得分:1)

绘制单个像素时,可以使用a bitmap context.位图上下文将原始像素数据作为输入。

上下文会复制您的原始像素数据,因此您不必使用可能要慢得多的路径。然后,您可以使用CGImage获得context.makeImage()

然后可以在图像视图中使用图像,这样就无需每帧重绘整个图像。

如果您不想手动创建位图上下文,可以使用

UIGraphicsBeginImageContext(size)
let context = UIGraphicsGetCurrentContext()
// draw everything into the context
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

然后您可以使用UIImageView来显示渲染图像。

也可以绘制成CALayer,不需要每帧重绘,但只有在调整大小时才会重绘。

答案 1 :(得分:0)

现在的样子,是否有可能进行优化?

public struct rgba {
    var r:UInt8
    var g:UInt8
    var b:UInt8
    var a:UInt8
}

public let imageview = UIImageView()

override func viewDidLoad() {

    super.viewDidLoad()        

    let width_input = 500
    let height_input = 500

    let redPixel = rgba(r:255, g:0, b:0, a:255)
    let greenPixel = rgba(r:0, g:255, b:0, a:255)
    let bluePixel = rgba(r:0, g:0, b:255, a:255

    var pixelData = [rgba](repeating: redPixel, count: Int(width_input*height_input))

    pixelData[1] = greenPixel
    pixelData[3] = bluePixel

    self.view.addSubview(imageview)

    imageview.frame = CGRect(x: 100,y: 100,width: 600,height: 600)
    imageview.image = draw(pixel: pixelData,width: width_input,height: height_input)
}


func draw(pixel:[rgba],width:Int,height:Int) -> UIImage
{
    let colorSpace = CGColorSpaceCreateDeviceRGB()
    let data = UnsafeMutableRawPointer(mutating: pixel)

    let bitmapContext = CGContext(data: data,
                                  width: width,
                                  height: height,
                                  bitsPerComponent: 8,
                                  bytesPerRow: 4*width,
                                  space: colorSpace,
                                  bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)

    let image = bitmapContext?.makeImage()
    return UIImage(cgImage: image!)
}

答案 2 :(得分:0)

我从Manuel那里得到了答案,并使其在Swift 5中运行。这里的主要症结在于清除Xcode 12中悬空的指针警告。

var image:CGImage?
        
pixelData.withUnsafeMutableBytes( { (rawBufferPtr: UnsafeMutableRawBufferPointer) in
    if let rawPtr = rawBufferPtr.baseAddress {
        let bitmapContext = CGContext(data: rawPtr,
                                     width: width,
                                    height: height,
                          bitsPerComponent: 8,
                               bytesPerRow: 4*width,
                                     space: colorSpace,
                                bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)
        image = bitmapContext?.makeImage()
     }
})

我确实不得不放弃使用rgba struct方法来预先加载数据,并转移到直接从枚举中的rawValues派生的UInt32值。用于更新现有阵列的“ append”或“ replaceInRange”方法耗时数小时(我的位图很大),最终耗尽了计算机上的交换空间。

enum Color: UInt32 { // All 4 bytes long with full opacity
    case red = 4278190335 // 0xFF0000FF
    case yellow = 4294902015
    case orange = 4291559679
    case pink = 4290825215
    case violet = 4001558271
    case purple = 2147516671
    case green = 16711935
    case blue = 65535 // 0x0000FFFF
}

通过这种方法,我能够通过以下方式快速构建具有该数据量的数据缓冲区:

func prepareColorBlock(c:Color) -> Data {
    var rawData = withUnsafeBytes(of:c.rawValue) { Data($0) }
    rawData.reverse() // Byte order is reveresed when defined
    var dataBlock = Data()
    dataBlock.reserveCapacity(100)
    for _ in stride(from: 0, to: 100, by: 1) {
        dataBlock.append(rawData)
    }
    return dataBlock
}

这样,我将每个这些块附加到了可变数据实例'pixelData'中,我们就退出了。您可以调整数据的组装方式,因为我只是想在UIImageView中生成一些颜色条以验证工作。对于800x600的视图,生成并渲染整个内容大约需要2.3秒。

再次,要向曼努埃尔(Manuel)指点我正确的方向。