Skip to content

Instantly share code, notes, and snippets.

@larsaugustin
Created January 26, 2020 13:02
Show Gist options
  • Save larsaugustin/af414f3637885f56c837b88c3fea1e6b to your computer and use it in GitHub Desktop.
Save larsaugustin/af414f3637885f56c837b88c3fea1e6b to your computer and use it in GitHub Desktop.
Get an array of pixels from an NSImage and use this array to render the image. Handy for performing per-pixel operations on an image
import Cocoa
// Representation of a pixel
struct Pixel {
var a: UInt8
var r: UInt8
var g: UInt8
var b: UInt8
}
// Get pixels from an NSImage
func imageToPixels(image: NSImage) -> [Pixel] {
var returnPixels = [Pixel]()
let image = NSImage(named: "uv")!
let pixelData = (image.cgImage(forProposedRect: nil, context: nil, hints: nil)!).dataProvider!.data
let data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData)
for y in 0..<Int(image.size.height) {
for x in 0..<Int(image.size.width) {
let pos = CGPoint(x: x, y: y)
let pixelInfo: Int = ((Int(image.size.width) * Int(pos.y) * 4) + Int(pos.x) * 4)
let r = data[pixelInfo]
let g = data[pixelInfo + 1]
let b = data[pixelInfo + 2]
let a = data[pixelInfo + 3]
returnPixels.append(Pixel(a: a, r: r, g: g, b: b))
}
}
return returnPixels
}
// Render pixels
func pixelsToImage(pixels: [Pixel], width: Int, height: Int) -> NSImage? {
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
guard let providerRef = CGDataProvider(data: NSData(bytes: &data,
length: data.count * MemoryLayout<Pixel>.size)
)
else { return nil }
guard let cgim = CGImage(
width: width,
height: height,
bitsPerComponent: bitsPerComponent,
bitsPerPixel: bitsPerPixel,
bytesPerRow: width * MemoryLayout<Pixel>.size,
space: rgbColorSpace,
bitmapInfo: bitmapInfo,
provider: providerRef,
decode: nil,
shouldInterpolate: true,
intent: .defaultIntent
)
else { return nil }
return NSImage(cgImage: cgim, size: CGSize(width: width, height: height))
}
// Code to get pixels and render them again
let input = NSImage(named: "image_name")!
let pixels = imageToPixels(image: input)
let output = pixelsToImage(pixels: pixels, width: Int, height: Int)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment