Рисование изображения в Swift длится вечно

В моем приложении я создаю отображение изображений с плавающей точкой в ​​пиксельное значение и использую его как оверлей на Картах Google, но навсегда это нужно делать, то же самое в Android почти мгновенно. Мой код выглядит следующим образом:

private func imageFromPixels(pixels: [PixelData], width: Int, height: Int) -> UIImage? {

    let bitsPerComponent = 8
    let bitsPerPixel = bitsPerComponent * 4
    let bytesPerRow = bitsPerPixel * width / 8

    let providerRef = CGDataProvider(
        data: NSData(bytes: pixels, length: height * width * 4) 
    )

    let cgimage = CGImage(
        width: width,
        height: height,
        bitsPerComponent: bitsPerComponent,
        bitsPerPixel: bitsPerPixel,
        bytesPerRow: bytesPerRow,
        space: CGColorSpaceCreateDeviceRGB(),
        bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue),
        provider: providerRef!,
        decode: nil,
        shouldInterpolate: true,
        intent: .defaultIntent
    )

    if cgimage == nil {
        print("CGImage is not supposed to be nil")
        return nil
    }
    return UIImage(cgImage: cgimage!)
}

Любые предложения о том, как это может занять столько времени? Я вижу, что он использует около 96% мощности процессора.

func fromData(pair: AllocationPair) -> UIImage? {

    let table = pair.table
    let data = pair.data

    prepareColors(allocations: table.allocations)

    let height = data.count
    let width = data[0].count

    var colors = [PixelData]()

    for row in data {
        for val in row {

            if (val == 0.0) {
                colors.append(PixelData(a: 0, r: 0, g: 0, b: 0))
                continue
            }

            if let interval = findInterval(table: table, value: val) {
                if let color = intervalColorDict[interval] {
                    colors.append(PixelData(a: color.a, r: color.r, g: color.g, b: color.b))
                } 
            }
        }
    }

    return imageFromPixels(pixels: colors, width: width, height: height)
}

Я попробовал время профилировать его, и это результат, на который требуется время.

введите описание изображения здесь

Ответ 1

Я пробовал ваш код, и я узнал, что проблема не в вашей функции.

Я думаю, что вы должны использовать структуру пикселов на основе UInt8, а не структуру на основе CGFloat.

Я перевел код для приложения cocoa, и это результат:

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

func imageFromPixels(pixels: [PixelData], width: Int, height: Int) -> NSImage? {

    let bitsPerComponent = 8
    let bitsPerPixel = bitsPerComponent * 4
    let bytesPerRow = bitsPerPixel * width / 8

    let providerRef = CGDataProvider(
        data: NSData(bytes: pixels, length: height * width * 4)
    )

    let cgimage = CGImage(
        width: width,
        height: height,
        bitsPerComponent: bitsPerComponent,
        bitsPerPixel: bitsPerPixel,
        bytesPerRow: bytesPerRow,
        space: CGColorSpaceCreateDeviceRGB(),
        bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue),
        provider: providerRef!,
        decode: nil,
        shouldInterpolate: true,
        intent: .defaultIntent
    )

    if cgimage == nil {
        print("CGImage is not supposed to be nil")
        return nil
    }
    return NSImage(cgImage: cgimage!, size: NSSize(width: width, height: height))
}

var img = [PixelData]()

for i: UInt8 in 0 ..< 20 {
    for j: UInt8 in 0 ..< 20 {
        // Creating a red 20x20 image.
        img.append(PixelData(a: 255, r: 255, g: 0, b: 0))
    }
}

var ns = imageFromPixels(pixels: img, width: 20, height: 20)

Этот код является быстрым и легким, здесь значения воздействия системы отладки:

введите описание изображения здесь

Я думаю, что проблема связана с той частью, которая загружает данные пикселя, проверяет и уверена, что она работает правильно.

Ответ 2

Если вам нужно получить доступ и изменить фактические данные растровых изображений, вы можете использовать CGImage. В других случаях CIImage использует объекты. Поэтому работайте с UIImage, конвертируйте UIImage в CIImage, делайте с ним какие-либо манипуляции, а затем конвертируйте его обратно в UIImage (как это было с CGImage в вашем коде).

Вот сообщение, объясняющее, что есть: UIImage против CIImage против CGImage

Core Image фактически не отображает изображение до тех пор, пока ему не будет предложено сделать это. Этот метод "ленивой оценки" позволяет Core Image работать максимально эффективно.

Страница CIImage в документации разработчика Apple