How to create an image pixel by pixel

匿名 (未验证) 提交于 2019-12-03 08:46:08

问题:

I want to create an UIImage pixel by pixel in swift 3

I have searched but couldn't find the code that actually 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 like 26 millions of those 

if it's w, the color of the pixel will be blue

if it's x, the color of the pixel will be red

if it's y, the color of the pixel will be green

if it's v, the color of the pixel will be black

I want to create an image from those characters and store it in the photos

Any thoughts??

Thanks for your answers

回答1:

You can create a CGContext and then retrieve the data buffer for that image, and then fill that buffer with 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 this asynchronous to avoid blocking the main queue.

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


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!