ch_studend ch_studend - 3 months ago 47
Swift Question

Obtain NSImage from Pixel Array Problems (Swift)

L.E : I've found the issue, now it does'n crashing anymore, but now ( new issue ) it doesn't draw the image as it should.. It is damaged...

I have a pixel array I need to turn into a CGImage and then into a NSImage. I've tried this version of a code used on ios for obtaining aUIImage and I get an error I can not handle: CGImageCreate: invalid image bits/pixel or bytes/row.
fatal error: unexpectedly found nil while unwrapping an Optional value


Any idea, any help will be honestly appreciated! Thank you! I'll let the code here :

func imageFromPixels(image : CGImage, size:NSSize,pixels: UnsafeMutablePointer<UInt8>, width: Int, height: Int)-> NSImage {
let rgbColorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo:CGBitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedFirst.rawValue)
let bitsPerComponent = CGImageGetBitsPerComponent(image)
let bitsPerPixel = CGImageGetBitsPerPixel(image)
let bytesPerRow = CGImageGetBytesPerRow(image)
var data = pixels
let providerRef = CGDataProviderCreateWithCFData(
NSData(bytes: &data, length: height * width * sizeof(UInt8))
)

let cgim = CGImageCreate(
width,
height,
bitsPerComponent,
bitsPerPixel,
bitsPerRow,
rgbColorSpace,
bitmapInfo,
providerRef,
nil,
true,
.RenderingIntentDefault
)
return NSImage(CGImage: cgim!, size: size)
}

Answer

Your new code has more faults than the older one, so some fixes:

func imageFromPixels(size: NSSize, pixels: UnsafePointer<UInt8>, width: Int, height: Int)-> NSImage { //No need to pass another CGImage
    let rgbColorSpace = CGColorSpaceCreateDeviceRGB()
    let bitmapInfo:CGBitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedFirst.rawValue)
    let bitsPerComponent = 8 //number of bits in UInt8
    let bitsPerPixel = 4 * bitsPerComponent //ARGB uses 4 components
    let bytesPerRow = bitsPerPixel * width / 8 // bitsPerRow / 8 (in some cases, you need some paddings)
    let providerRef = CGDataProviderCreateWithCFData(
        NSData(bytes: pixels, length: height * bytesPerRow) //Do not put `&` as pixels is already an `UnsafePointer`
    )

    let cgim = CGImageCreate(
        width,
        height,
        bitsPerComponent,
        bitsPerPixel,
        bytesPerRow, //->not bits
        rgbColorSpace,
        bitmapInfo,
        providerRef,
        nil,
        true,
        .RenderingIntentDefault
    )
    return NSImage(CGImage: cgim!, size: size)
}

See comments in the code.