2016-10-23 6 views
5

Ich möchte erstellen ein UIImage Pixel für Pixel mit schnellen 3Wie ein Bild Pixel für Pixel

Ich suche haben zu schaffen, aber ich konnte nicht einen Code, der tatsächlich funktioniert

Also lassen Sie mich finden erklären, ich habe ein Array mit Zeichen

var array = ["w", "x", "y", "x", "y", "y", "y", "x", "x", "x", "w", "x", "y", "w", "y"] //there will be something like 26 millions of those 

wenn es w, die Farbe des Pixels

blau ist, wenn es x ist, ist die Farbe des Pixels rot

wenn es y ist, die Farbe des Pixels grün ist

wenn es v ist, ist die Farbe des Pixels schwarz

ich ein Bild von diesen Zeichen erstellen möchten, und speichern Sie es in den Fotos

Irgendwelche Gedanken ??

Vielen Dank für Ihre Antworten

Antwort

4

Sie ein CGContext erstellen und dann für das Bild den data Puffer abrufen, und füllen Sie dann diesen Puffer mit Werten zu Ihren String-Werten entsprechen:

func createImage(width: Int, height: Int, from array: [String], completionHandler: @escaping (UIImage?, String?) -> Void) { 
    DispatchQueue.global(qos: .utility).async { 
     let colorSpace  = CGColorSpaceCreateDeviceRGB() 
     let bytesPerPixel = 4 
     let bitsPerComponent = 8 
     let bytesPerRow  = bytesPerPixel * width 
     let bitmapInfo  = RGBA32.bitmapInfo 

     guard array.count == width * height else { 
      completionHandler(nil, "Array size \(array.count) is incorrect given dimensions \(width) x \(height)") 
      return 
     } 

     guard let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo) else { 
      completionHandler(nil, "unable to create context") 
      return 
     } 

     guard let buffer = context.data else { 
      completionHandler(nil, "unable to get context data") 
      return 
     } 

     let pixelBuffer = buffer.bindMemory(to: RGBA32.self, capacity: width * height) 

     for (index, string) in array.enumerated() { 
      switch string { 
      case "w": pixelBuffer[index] = .blue 
      case "x": pixelBuffer[index] = .red 
      case "y": pixelBuffer[index] = .green 
      case "v": pixelBuffer[index] = .black 
      default: completionHandler(nil, "Unexpected value: \(string)"); return 
      } 
     } 

     let cgImage = context.makeImage()! 

     let image = UIImage(cgImage: cgImage) 

     // or 
     // 
     // let image = UIImage(cgImage: cgImage, scale: UIScreen.main.scale, orientation: .up) 

     completionHandler(image, nil) 
    } 

} 

Wenn es 26 Millionen Pixel möchten Sie wahrscheinlich asynchron machen, um die Hauptwarteschlange nicht zu blockieren.

By the way, die oben verwendet diese struct:

struct RGBA32: Equatable { 
    private var color: UInt32 

    var redComponent: UInt8 { 
     return UInt8((color >> 24) & 255) 
    } 

    var greenComponent: UInt8 { 
     return UInt8((color >> 16) & 255) 
    } 

    var blueComponent: UInt8 { 
     return UInt8((color >> 8) & 255) 
    } 

    var alphaComponent: UInt8 { 
     return UInt8((color >> 0) & 255) 
    } 

    init(red: UInt8, green: UInt8, blue: UInt8, alpha: UInt8) { 
     color = (UInt32(red) << 24) | (UInt32(green) << 16) | (UInt32(blue) << 8) | (UInt32(alpha) << 0) 
    } 

    static let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Little.rawValue 

    static func ==(lhs: RGBA32, rhs: RGBA32) -> Bool { 
     return lhs.color == rhs.color 
    } 

    static let black = RGBA32(red: 0, green: 0, blue: 0, alpha: 255) 
    static let red = RGBA32(red: 255, green: 0, blue: 0, alpha: 255) 
    static let green = RGBA32(red: 0, green: 255, blue: 0, alpha: 255) 
    static let blue = RGBA32(red: 0, green: 0, blue: 255, alpha: 255) 
} 

Um das Bild zu speichern, können Sie tun:

createImage(width: width, height: height, from: array) { image, errorMessage in 
    guard let image = image, errorMessage == nil else { 
     print(errorMessage!) 
     return 
    } 

    DispatchQueue.main.async { 
     self.imageView.image = image 
     UIImageWriteToSavedPhotosAlbum(image, self, #selector(self.image(_:didFinishSavingWithError:contextInfo:)), nil) 
    } 
} 

Wo

func image(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: Any?) { 
    guard error == nil else { 
     print(error!.localizedDescription) 
     return 
    } 

    print("image saved") 
} 
+0

dank Rob, aber ich habe ein letzte Frage Ich habe das Bild erstellt, aber ich kann es nicht speichern, weil: "Diese App ist abgestürzt, weil sie versucht hat, eine Zugriff auf datenschutzrelevante Daten ohne eine Verwendungsbeschreibung. Die Info.plist der App muss einen NSPhotoLibraryUsageDescription-Schlüssel mit einem Zeichenfolgenwert enthalten, der dem Benutzer erklärt, wie die App diese Daten verwendet. " –

+0

@lbdev Ja, dieser Fehler sagt alles: Sie müssen den' NSPhotoLibraryUsageDescription'-Schlüssel zu Ihren Informationen hinzufügen. Legen Sie eine Nachricht an, die in dem Dialogfeld angezeigt wird, das nach der Berechtigung für die Fotobibliothek fragt – Rob

+0

nur um sicher zu sein Wissen Sie, ob ich das Bild aus der Fotobibliothek zurückbekomme und versuche, das Array herauszufinden Ich bekomme das gleiche Array oder wird es anders sein (bc das Bild ist vielleicht komprimiert)? –