How to create pixel by pixel pixels

I want to create a UIImage pixel by pixels with fast 3

I have a search, but I could not find the code that really works

So let me explain, I have an array with characters

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 

if it is w, the pixel color is blue

if x, the color of the pixel is red

if y, pixel color is green

if v, the pixel color is black

I want to create an image from these characters and save it in photos

Any thoughts ??

thank you for your responses

+5
source share
1 answer

You can create a CGContext , then get the data buffer for this image, and then fill this buffer with the values ​​corresponding to your string values:

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

If there are 26 million pixels, you probably want to make it asynchronous to avoid blocking the main queue.

By the way, the above example uses 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) } 

To save the image, you can do:

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

Where

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

Source: https://habr.com/ru/post/1258669/


All Articles