2015-06-20 24 views
7

Próbowałem dowiedzieć się, jak przekonwertować tablicę danych pikseli rgb do UIImage w Swift.Pixel Array do UIImage w Swift

Jestem przechowywania danych rgb na piksel w prosty struct:

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

zrobiłem moją drogę do następującej funkcji, ale powstały obraz jest nieprawidłowy:

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

Wszelkie wskazówki lub wskazówki, jak poprawnie przekonwertować tablicę rgb do UIImage?

Odpowiedz

4

Jedynym problemem jest to, że typy danych w twojej strukturze PixelData muszą być UInt8. I stworzył obraz testowy na placu zabaw z poniższym:

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) 

Aktualizacja dla Swift 2.2:

zaktualizowałem imageFromARGB32Bitmap pracować 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

Aktualizacji dla 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

To jest naprawdę dobre, ale jest trochę rozwlekłe. Sugerowałbym zmianę asercji na proste instrukcje 'guard' i użycie' guard let' zamiast 'if'ing dla nils. W mojej implementacji użyłem również 'UInt', aby zapobiec ujemnej szerokości i wysokości. – huwr