2017-02-20 16 views
12

W mojej aplikacji tworzę mapowanie obrazu, które przenosi się do wartości pikseli i używa go jako nakładki w Mapach Google, ale trwa to wieczność, to samo w Androidzie jest niemal natychmiastowe. Mój kod wygląda tak:Rysowanie obrazu w Swift trwa wiecznie

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!) 
} 

Jakieś sugestie, jak to może zająć tyle czasu? Widzę, że wykorzystuje około 96% mocy procesora.

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) 
} 

Próbowałem go profilować czasowo, a to jest wynik, gdy wymaga czasu.

enter image description here

+0

Zasadniczo jestem po prostu pokazując obraz albo zielony, czerwony lub żółty pikseli miesza się – Recusiwe

+0

Czy jesteś pewien problem jest tutaj, a nie w tworzeniu '[]' PixelData tablicy? W kompilacjach debugowania obsługa dużych tablic jest bardzo powolna. W przypadku kompilacji wydania z włączonymi optymalizacjami użycie dużych tablic jest znacznie szybsze. Upewnij się, że problem jest tutaj, a nie w tworzeniu tej tablicy. A następnie, oczywiście, upewnij się, że po wyświetleniu obrazu, który robisz to w głównej kolejce. – Rob

+1

@Recusiwe, czy próbowałeś używać Instrumentów do wskazania miejsca, w którym zużywasz cały procesor? Możesz spróbować zacząć od tego samouczka: https://www.raywenderlich.com/97886/instruments-tutorial-with-swift-getting-started –

Odpowiedz

8

Próbowałem swój kod i okazało się, że problem nie jest ze swojej funkcji.

Myślę, że należy użyć struktury pikseli opartej na UInt8, a nie struktury opartej na CGFloat.

przetłumaczyłem kodu dla aplikacji kakao, a ta jest wynikiem:

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) 

Kod ten jest szybki i lekki, oto wartości oddziaływania systemu debugować:

enter image description here

I pomyśl, że problem pojawia się w części, która ładuje dane pikseli, sprawdź to i upewnij się, że działa poprawnie.

+0

Nie wezmę NSImage i NSSize? Jak by wyglądał, gdyby używał UIKit zamiast AppKit? – Recusiwe

+0

@Recusiwe można użyć 'UIImage (cgImage: cgimage!)' I zwrócić 'UIImage' zamiast' NSImage', a następnie zmienić 'NSData' na' Dane', jeśli używasz UIKit. Oto [dokumentacja] (https://developer.apple.com/reference/uikit/uiimage/1624090-init). Pozostałe instrukcje są prawie takie same ... – Cristian

1

Jeśli chcesz uzyskać dostęp i zmienić rzeczywiste dane bitmap, możesz użyć CGImage. W innych przypadkach użyj obiektów reprezentowanych przez CII. Pracuj z UIImage, konwertuj UIImage na CIImage, wykonuj na nim dowolne manipulacje, a następnie przekonwertuj je z powrotem do UIImage (tak jak robiłeś to z CGImage w twoim kodzie).

Oto po wyjaśniając, co jest co: UIImage vs. CIImage vs. CGImage

Rdzeń Obraz rzeczywistości nie renderowanie obrazu, dopóki nie dowiaduje się, aby to zrobić. Ta metoda "leniwej oceny" pozwala Core Image działać tak wydajnie, jak to tylko możliwe.

CIImage page in Apple Developer Documentation

Powiązane problemy