2015-06-20 22 views
7

Ho cercato di capire come convertire un array di dati di pixel RGB in un UIImage in Swift.Pixel Array to UIImage in Swift

sto mantenendo i dati RGB per pixel in una semplice struct:

public struct PixelData { 
    var a: Int 
    var r: Int 
    var g: Int 
    var b: Int 
} 

Ho fatto la mia strada verso la seguente funzione, ma l'immagine risultante non è corretto:

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

Qualche consiglio o suggerimento su come convertire correttamente un array rgb in un UIImage?

risposta

4

L'unico problema è che i tipi di dati nella struttura PixelData devono essere UInt8. Ho creato un'immagine di prova in un parco giochi con il seguente:

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, width: 30, height: 30) 

Aggiornamento per Swift 2.2:

ho aggiornato imageFromARGB32Bitmap di lavorare con Swift 2.2:

func imageFromARGB32Bitmap(pixels:[PixelData], width: Int, height: Int)-> UIImage { 
    let rgbColorSpace = CGColorSpaceCreateDeviceRGB() 
    let bitmapInfo:CGBitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedFirst.rawValue) 
    let bitsPerComponent = 8 
    let bitsPerPixel = 32 

    assert(pixels.count == 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, 
     .RenderingIntentDefault 
    ) 
    return UIImage(CGImage: cgim!) 
} 
6

Aggiornamento per Swift 3

struct PixelData { 
    var a: UInt8 = 0 
    var r: UInt8 = 0 
    var g: UInt8 = 0 
    var b: UInt8 = 0 
} 

func imageFromBitmap(pixels: [PixelData], width: Int, height: Int) -> UIImage? { 
    assert(width > 0) 

    assert(height > 0) 

    let pixelDataSize = MemoryLayout<PixelData>.size 
    assert(pixelDataSize == 4) 

    assert(pixels.count == Int(width * height)) 

    let data: Data = pixels.withUnsafeBufferPointer { 
     return Data(buffer: $0) 
    } 

    let cfdata = NSData(data: data) as CFData 
    let provider: CGDataProvider! = CGDataProvider(data: cfdata) 
    if provider == nil { 
     print("CGDataProvider is not supposed to be nil") 
     return nil 
    } 
    let cgimage: CGImage! = CGImage(
     width: width, 
     height: height, 
     bitsPerComponent: 8, 
     bitsPerPixel: 32, 
     bytesPerRow: width * pixelDataSize, 
     space: CGColorSpaceCreateDeviceRGB(), 
     bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue), 
     provider: provider, 
     decode: nil, 
     shouldInterpolate: true, 
     intent: .defaultIntent 
    ) 
    if cgimage == nil { 
     print("CGImage is not supposed to be nil") 
     return nil 
    } 
    return UIImage(cgImage: cgimage) 
} 
+0

Questo è veramente buono ma è un po 'prolisso. Suggerirei di cambiare le asserzioni con semplici istruzioni 'guard' e usando' guard let' invece di 'if'ing for nils. Nella mia implementazione ho anche usato 'UInt' per evitare larghezza e altezze negative. – huwr