[英]Manipulate pixels in NSImage (Swift)
在尋找一種在 NSImage 中操作像素的方法時,我在https://gist.github.com/larsaugustin/af414f3637885f56c837b88c3fea1e6b找到了一種很有前途的方法
但是,當將圖像放入像素數組並將該數組轉換回 NSImage 時,結果會失真。
這是重現問題的代碼:
import Foundation
import AppKit
struct Pixel {
var a: UInt8
var r: UInt8
var g: UInt8
var b: UInt8
}
let fileManager : FileManager = FileManager.default
let fileURL : URL = fileManager.homeDirectoryForCurrentUser.appendingPathComponent("IMG_RGB_ORIG.png")
let imageData = try Data(contentsOf: fileURL)
let imageOrig = NSImage(data: imageData)
let pixels = imageToPixels(image: imageOrig!)
let imageConv = pixelsToImage(pixels: pixels,
width: Int(imageOrig!.size.width),
height: Int(imageOrig!.size.height))
func imageToPixels(image: NSImage) -> [Pixel] {
var returnPixels = [Pixel]()
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
}
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))
}
我使用的是 M1 mac,無論是否使用 Rosetta,結果都是一樣的。 問題似乎已經出現在轉換為像素陣列的過程中。 關於如何更正代碼的任何想法?
同時,我設法根據Objective-C: NSBitmapImageRep SetColor中描述的方法更改了 NSImage 中的像素,該方法在 NSBitmapImageRep 上使用了 setPixel() 方法。
下面的代碼說明了它是如何工作的(請不要在你的代碼中強制解包選項)。
import Foundation
import AppKit
let fileManager : FileManager = FileManager.default
let fileURL : URL = fileManager.homeDirectoryForCurrentUser.appendingPathComponent("IMG_RGB_ORIG.png")
let imgData = try Data(contentsOf: fileURL)
let imgOrig = NSImage(data: imgData)
let rep = NSBitmapImageRep(bitmapDataPlanes: nil,
pixelsWide: Int(imgOrig!.size.width),
pixelsHigh: Int(imgOrig!.size.height),
bitsPerSample: 8,
samplesPerPixel: 4,
hasAlpha: true,
isPlanar: false,
colorSpaceName: .deviceRGB,
bytesPerRow: Int(imgOrig!.size.width) * 4,
bitsPerPixel: 32)
let ctx = NSGraphicsContext.init(bitmapImageRep: rep!)
NSGraphicsContext.saveGraphicsState()
NSGraphicsContext.current = NSGraphicsContext(bitmapImageRep: rep!)
imgOrig!.draw(at: NSZeroPoint, from: NSZeroRect, operation: NSCompositingOperation.copy, fraction: 1.0)
ctx?.flushGraphics()
NSGraphicsContext.restoreGraphicsState()
for y in 0..<Int(imgOrig!.size.height) {
for x in 0..<Int(imgOrig!.size.width) {
// you can read the color of pixels like this:
let color = rep!.colorAt(x: x, y: y)
var colorR = color!.redComponent
var colorG = color!.greenComponent
var colorB = color!.blueComponent
var colorA = color!.alphaComponent
}
}
var yellowPixel : [Int] = [255, 255, 0 , 255]
var redPixel : [Int] = [255, 0 , 0 , 255]
var greenPixel : [Int] = [0 , 255, 0 , 255]
var bluePixel : [Int] = [0 , 0 , 255, 255]
for y in 10..<Int(imgOrig!.size.height) {
for x in 10..<Int(imgOrig!.size.width) {
// you can change the color of pixels like this:
rep!.setPixel(&yellowPixel, atX: x, y: y)
}
}
let imgConv = NSImage(cgImage: rep!.cgImage!, size: NSSize(width: Int(imgOrig!.size.width), height: Int(imgOrig!.size.height)))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.