Created
January 26, 2020 13:02
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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