Как создать изображение пиксель за пикселем

Я хочу создать UIImage пиксель за пикселем в Swift 3

Я искал, но не смог найти код, который на самом деле работает

Итак, позвольте мне объяснить, у меня есть массив с символами

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, цвет пикселя будет синим

если это х, цвет пикселя будет красным

если это у, цвет пикселя будет зеленым

если это v, цвет пикселя будет черным

Я хочу создать изображение из этих персонажей и сохранить его на фотографиях

Какие-нибудь мысли??

Спасибо за ваши ответы

1 ответ

Решение

Вы можете создать CGContext а затем получить data буфер для этого изображения, а затем заполните этот буфер значениями, соответствующими строковым значениям:

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

}

Если имеется 26 миллионов пикселей, вы, вероятно, захотите сделать это асинхронным, чтобы избежать блокировки основной очереди.

Кстати, вышеупомянутое использует это 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)
}

Чтобы сохранить изображение, вы можете сделать:

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")
}
Другие вопросы по тегам