如何逐像素创建图像 [英] How to create an image pixel by pixel

查看:82
本文介绍了如何逐像素创建图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在Swift 3中逐像素创建UIImage

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

如果为w,像素的颜色将为蓝色

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

如果是x,则像素的颜色将为红色

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

如果是y,则像素的颜色将为绿色

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

如果是v,则像素的颜色将为黑色

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

有什么想法吗?

感谢您的回答

推荐答案

您可以创建一个CGContext,然后检索该图像的data缓冲区,然后用与您的字符串值相对应的值填充该缓冲区:

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

}

如果有2600万像素,则可能要使其异步以避免阻塞主队列.

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

顺便说一下,上面使用的是struct:

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

哪里

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

    print("image saved")
}

这篇关于如何逐像素创建图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆