2015-06-20 7 views
7

Я пытался выяснить, как преобразовать массив данных пикселов rgb в UIImage в Swift.Пиксельный массив для UIImage в Swift

Я сохраняю данные 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?

ответ

4

Ваша единственная проблема заключается в том, что типы данных в вашей структуре PixelData должны быть UInt8. Я создал тестовое изображение в Playground со следующим:

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) 

Обновление для Swift 2.2:

Я обновил imageFromARGB32Bitmap работать с 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

Update для 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

Это действительно хорошо, но это немного затянуто. Я бы предложил изменить утверждения на простые инструкции 'guard' и использовать' guard let' вместо 'if'ing для nils. В моей реализации я также использовал 'UInt' для предотвращения отрицательной ширины и высоты. – huwr

 Смежные вопросы

  • Нет связанных вопросов^_^