我的像素图图像 (NSImage) 有时看起来不像我传入的 RGB 值,Swift Core Graphics Quartz
My pixel map image (NSImage) sometimes doesn't look like the RGB values I pass in, Swift Core Graphics Quartz
我有两个 d 像素图 ([Double]),我将其(正确地)编码为 [UInt32]),它被馈送到 CGDataProvider,它是 CGImage 的来源,转换为 NSImage,最后在自定义视图中显示
class SingleStepMapView:NSView {
@IBOutlet var dataSource : SingleStepViewController!
override func drawRect(dirtyRect: NSRect) {
let mapImage = TwoDPixMap(data: dataSource.mapData,
width: dataSource.mapWidth, color: dataSource.mapColor).image
mapImage.drawInRect(self.bounds, fromRect: NSZeroRect, operation: NSCompositingOperation.CompositeSourceAtop, fraction: 1.0)
return
}
构造NSImage的部分在TwoDPixMap实例的图像属性中...
var image : NSImage {
var buffer = [UInt32]()
let bufferScale = 1.0 / (mapMax - mapMin)
for d in data {
let scaled = bufferScale * (d - mapMin)
buffer.append( color.rgba(scaled) )
}
let bufferLength = 4 * height * width
let dataProvider = CGDataProviderCreateWithData(nil, buffer, bufferLength, nil)!
let bitsPerComponent = 8
let bitsPerPixel = 32
let bytesPerRow = 4 * width
let colorSpace = CGColorSpaceCreateDeviceRGB()
var bitMapInfo = CGBitmapInfo()
bitMapInfo.insert(.ByteOrderDefault)
// let bitMapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedFirst.rawValue)
let interpolate = false
let renderingIntent = CGColorRenderingIntent.RenderingIntentDefault
let theImage = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpace, bitMapInfo, dataProvider, nil, interpolate, renderingIntent)!
let value = NSImage(CGImage: theImage, size: NSSize(width: width, height: height))
return value
}
我已经检查过当输入 CGDataProviderCreateWithData
调用时创建的缓冲区值总是正确的。特别是对于以下示例,它们是六十四个 Double
值(从 0.0 到 63.0),它们将使用我构建的颜色条映射到六十四个 UInt32
值,这样第一个像素是纯红色 (0xff0000ff),最后一个像素是纯白色 (0xffffffff)。在 none 的值中,我们看到任何转化为黑色的东西。当排列成一张 64 乘一张地图(它本质上是颜色条)时,它应该看起来像这样...
但有时,只是重新调用 drawrect 方法,使用相同的数据和创建的缓冲区,它看起来完全错误
或有时 几乎 正确(一个像素颜色错误)。我会 post 更多示例,但仅限于两个链接
问题是您创建了一个带有指向 buffer
的不安全指针的数据提供程序,填充了该像素缓冲区,使用该提供程序创建了图像,但随后允许 buffer
脱离范围并被释放,即使数据提供者仍然对该内存地址有不安全的引用。
但是一旦该内存被释放,它就可以用于其他事情,呈现奇怪的行为,从关闭的单个像素,或者在用于其他事情时对该内存范围进行大规模更改。
在 Objective-C 环境中,我会在创建提供程序时对内存执行 malloc
,然后 CGDataProviderCreateWithData
的最后一个参数将是一个 C 函数,我会写入 free
那个记忆。 (而且释放内存的函数可能要等到很久以后才会被调用,直到图像被释放。)
我使用的另一种方法是调用 CGBitmapContextCreate
来创建上下文,然后使用 CGBitmapContextGetData
来获取它为图像创建的缓冲区。然后我可以按照我认为合适的方式填充该缓冲区。但是因为那个缓冲区是为我创建的,所以 OS 负责内存管理:
func createImageWithSize(size: NSSize) -> NSImage {
let width = Int(size.width)
let height = Int(size.height)
let bitsPerComponent = 8
let bytesPerRow = 4 * width
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGImageAlphaInfo.PremultipliedLast.rawValue // this depends upon how your `rgba` method was written; use whatever `bitmapInfo` that makes sense for your app
let context = CGBitmapContextCreate(nil, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo)!
let pixelBuffer = UnsafeMutablePointer<UInt32>(CGBitmapContextGetData(context))
var currentPixel = pixelBuffer
for row in 0 ..< height {
for column in 0 ..< width {
let red = ...
let green = ...
let blue = ...
currentPixel.memory = rgba(red: red, green: green, blue: blue, alpha: 255)
currentPixel++
}
}
let cgImage = CGBitmapContextCreateImage(context)!
return NSImage(CGImage: cgImage, size: size)
}
结果:
第一种技术(创建数据提供程序,执行 malloc
内存然后提供 CGDataProviderCreateWithData
函数参数以释放它)可能更好,但是然后你就不得不编写一个 C 函数来进行清理,这是我不想在 Swift 环境中做的事情。但这取决于你。
我有两个 d 像素图 ([Double]),我将其(正确地)编码为 [UInt32]),它被馈送到 CGDataProvider,它是 CGImage 的来源,转换为 NSImage,最后在自定义视图中显示
class SingleStepMapView:NSView {
@IBOutlet var dataSource : SingleStepViewController!
override func drawRect(dirtyRect: NSRect) {
let mapImage = TwoDPixMap(data: dataSource.mapData,
width: dataSource.mapWidth, color: dataSource.mapColor).image
mapImage.drawInRect(self.bounds, fromRect: NSZeroRect, operation: NSCompositingOperation.CompositeSourceAtop, fraction: 1.0)
return
}
构造NSImage的部分在TwoDPixMap实例的图像属性中...
var image : NSImage {
var buffer = [UInt32]()
let bufferScale = 1.0 / (mapMax - mapMin)
for d in data {
let scaled = bufferScale * (d - mapMin)
buffer.append( color.rgba(scaled) )
}
let bufferLength = 4 * height * width
let dataProvider = CGDataProviderCreateWithData(nil, buffer, bufferLength, nil)!
let bitsPerComponent = 8
let bitsPerPixel = 32
let bytesPerRow = 4 * width
let colorSpace = CGColorSpaceCreateDeviceRGB()
var bitMapInfo = CGBitmapInfo()
bitMapInfo.insert(.ByteOrderDefault)
// let bitMapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedFirst.rawValue)
let interpolate = false
let renderingIntent = CGColorRenderingIntent.RenderingIntentDefault
let theImage = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpace, bitMapInfo, dataProvider, nil, interpolate, renderingIntent)!
let value = NSImage(CGImage: theImage, size: NSSize(width: width, height: height))
return value
}
我已经检查过当输入 CGDataProviderCreateWithData
调用时创建的缓冲区值总是正确的。特别是对于以下示例,它们是六十四个 Double
值(从 0.0 到 63.0),它们将使用我构建的颜色条映射到六十四个 UInt32
值,这样第一个像素是纯红色 (0xff0000ff),最后一个像素是纯白色 (0xffffffff)。在 none 的值中,我们看到任何转化为黑色的东西。当排列成一张 64 乘一张地图(它本质上是颜色条)时,它应该看起来像这样...
但有时,只是重新调用 drawrect 方法,使用相同的数据和创建的缓冲区,它看起来完全错误
或有时 几乎 正确(一个像素颜色错误)。我会 post 更多示例,但仅限于两个链接
问题是您创建了一个带有指向 buffer
的不安全指针的数据提供程序,填充了该像素缓冲区,使用该提供程序创建了图像,但随后允许 buffer
脱离范围并被释放,即使数据提供者仍然对该内存地址有不安全的引用。
但是一旦该内存被释放,它就可以用于其他事情,呈现奇怪的行为,从关闭的单个像素,或者在用于其他事情时对该内存范围进行大规模更改。
在 Objective-C 环境中,我会在创建提供程序时对内存执行 malloc
,然后 CGDataProviderCreateWithData
的最后一个参数将是一个 C 函数,我会写入 free
那个记忆。 (而且释放内存的函数可能要等到很久以后才会被调用,直到图像被释放。)
我使用的另一种方法是调用 CGBitmapContextCreate
来创建上下文,然后使用 CGBitmapContextGetData
来获取它为图像创建的缓冲区。然后我可以按照我认为合适的方式填充该缓冲区。但是因为那个缓冲区是为我创建的,所以 OS 负责内存管理:
func createImageWithSize(size: NSSize) -> NSImage {
let width = Int(size.width)
let height = Int(size.height)
let bitsPerComponent = 8
let bytesPerRow = 4 * width
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGImageAlphaInfo.PremultipliedLast.rawValue // this depends upon how your `rgba` method was written; use whatever `bitmapInfo` that makes sense for your app
let context = CGBitmapContextCreate(nil, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo)!
let pixelBuffer = UnsafeMutablePointer<UInt32>(CGBitmapContextGetData(context))
var currentPixel = pixelBuffer
for row in 0 ..< height {
for column in 0 ..< width {
let red = ...
let green = ...
let blue = ...
currentPixel.memory = rgba(red: red, green: green, blue: blue, alpha: 255)
currentPixel++
}
}
let cgImage = CGBitmapContextCreateImage(context)!
return NSImage(CGImage: cgImage, size: size)
}
结果:
第一种技术(创建数据提供程序,执行 malloc
内存然后提供 CGDataProviderCreateWithData
函数参数以释放它)可能更好,但是然后你就不得不编写一个 C 函数来进行清理,这是我不想在 Swift 环境中做的事情。但这取决于你。