我一直在尝试找出如何在Swift中将rgb像素数据数组转换为UIImage。
我将每个像素的rgb数据保持在一个简单的结构中:
public struct PixelData { var a: Int var r: Int var g: Int var b: Int }
我已经实现了以下功能,但是生成的图像不正确:
func imageFromARGB32Bitmap(pixels:[PixelData], width: Int, height: Int)-> UIImage { let rgbColorSpace = CGColorSpaceCreateDeviceRGB() let bitmapInfo:CGBitmapInfo = CGBitmapInfo(CGImageAlphaInfo.PremultipliedFirst.rawValue) let bitsPerComponent:Int = 8 let bitsPerPixel:Int = 32 assert(pixels.count == Int(width * height)) var data = pixels // Copy to mutable [] let providerRef = CGDataProviderCreateWithCFData( NSData(bytes: &data, length: data.count * sizeof(PixelData)) ) let cgim = CGImageCreate( width, height, bitsPerComponent, bitsPerPixel, width * Int(sizeof(PixelData)), rgbColorSpace, bitmapInfo, providerRef, nil, true, kCGRenderingIntentDefault ) return UIImage(CGImage: cgim)! }
关于如何正确地将rgb数组转换为UIImage的任何提示或指针?
注意: 这是iOS创建的解决方案UIImage。有关macOS和的解决方案NSImage,请参见此答案。
UIImage
NSImage
唯一的问题是结构中的数据类型PixelData需要为UInt8。我在Playground中使用以下内容创建了测试图像:
PixelData
UInt8
public struct PixelData { var a: UInt8 var r: UInt8 var g: UInt8 var b: UInt8 } var pixels = [PixelData]() let red = PixelData(a: 255, r: 255, g: 0, b: 0) let green = PixelData(a: 255, r: 0, g: 255, b: 0) let blue = PixelData(a: 255, r: 0, g: 0, b: 255) for _ in 1...300 { pixels.append(red) } for _ in 1...300 { pixels.append(green) } for _ in 1...300 { pixels.append(blue) } let image = imageFromARGB32Bitmap(pixels: pixels, width: 30, height: 30)
Swift 4更新:
我更新imageFromARGB32Bitmap为使用Swift4。该函数现在返回a,UIImage?并在出现任何问题时guard用于返回nil。
imageFromARGB32Bitmap
UIImage?
guard
nil
func imageFromARGB32Bitmap(pixels: [PixelData], width: Int, height: Int) -> UIImage? { guard width > 0 && height > 0 else { return nil } guard pixels.count == width * height else { return nil } let rgbColorSpace = CGColorSpaceCreateDeviceRGB() let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue) let bitsPerComponent = 8 let bitsPerPixel = 32 var data = pixels // Copy to mutable [] guard let providerRef = CGDataProvider(data: NSData(bytes: &data, length: data.count * MemoryLayout<PixelData>.size) ) else { return nil } guard let cgim = CGImage( width: width, height: height, bitsPerComponent: bitsPerComponent, bitsPerPixel: bitsPerPixel, bytesPerRow: width * MemoryLayout<PixelData>.size, space: rgbColorSpace, bitmapInfo: bitmapInfo, provider: providerRef, decode: nil, shouldInterpolate: true, intent: .defaultIntent ) else { return nil } return UIImage(cgImage: cgim) }
使它成为UIImage的便捷初始化器:
此函数可以用作的convenience初始化程序UIImage。这是实现:
convenience
extension UIImage { convenience init?(pixels: [PixelData], width: Int, height: Int) { guard width > 0 && height > 0, pixels.count == width * height else { return nil } var data = pixels guard let providerRef = CGDataProvider(data: Data(bytes: &data, count: data.count * MemoryLayout<PixelData>.size) as CFData) else { return nil } guard let cgim = CGImage( width: width, height: height, bitsPerComponent: 8, bitsPerPixel: 32, bytesPerRow: width * MemoryLayout<PixelData>.size, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue), provider: providerRef, decode: nil, shouldInterpolate: true, intent: .defaultIntent) else { return nil } self.init(cgImage: cgim) } }
这是一个用法示例:
// Generate a 500x500 image of randomly colored pixels let height = 500 let width = 500 var pixels: [PixelData] = .init(repeating: .init(a: 0, r: 0, g: 0, b: 0), count: width * height) for index in pixels.indices { pixels[index].a = 255 pixels[index].r = .random(in: 0...255) pixels[index].g = .random(in: 0...255) pixels[index].b = .random(in: 0...255) } let image = UIImage(pixels: pixels, width: width, height: height)