我试图弄清楚如何在mac OS上使用Swift和Cocoa创建位图 我在网上找到了这个例子。
// LibPNG example
// A.Greensted
// http://www.labbookpages.co.uk
使用libpng和桥接头我将此示例转换为Swift。我不想通常使用libpng,因为它似乎不是Apple提供的标准框架之一。我正在尝试学习如何使用Core Graphics和Cocoa。 (我试图避免使用目标C并使用Swift)
我使用上面在操场上运行的示例编写了以下代码。在边缘我得到一个很好的mandelbrot图像。我无法弄清楚如何将其转换为pdf和/或png以及如何将其保存到文件中。看起来这应该很容易。关于如何做到这一点的指针将不胜感激;或指向先前答案的指针。 Apple经常更改他们的API,许多答案都是陈旧的。
如果您运行我的示例,如果您在操场上运行此函数,则将函数(createMandelbrot,setRGB,makeRGBImage)放在sources目录中的单独文件中。如果mandelbrot函数位于主操场窗口中,则迭代将永远持续。
import Cocoa
let h = 500
let w = 500
let mandelbrot = createMandelbrot(width: w, height: h, xS: -0.802, yS: -0.177, rad: 0.011, maxIteration: 110)
let context = makeRGBImage(width: w, height: h, buffer: mandelbrot)
let image = NSImage(cgImage: context.makeImage()!, size: NSSize(width: w, height: h))
下面是“源目录”中的文件。
import Foundation
public func createMandelbrot(width: Int, height: Int, xS: Double, yS: Double, rad: Double, maxIteration: Int) -> [Double] {
var buffer = Array<Double>(repeating: 0.0, count: width * height)
var minMu = Double(maxIteration)
var maxMu = 0.0
for yPos in 0..<height {
let yP: Double = (yS-rad) + (2.0 * rad/Double(height)) * Double(yPos);
for xPos in 0..<width {
let xP: Double = (xS - rad) + (2.0 * rad/Double(width)) * Double(xPos)
var iteration:Int = 0
var x = 0.0
var y = 0.0
while x * x + y * y <= 4 && iteration < maxIteration {
let tmp = x * x - y * y + xP
y = 2 * x * y + yP
x = tmp;
iteration += 1
}
if iteration < maxIteration {
let modZ = sqrt(x * x + y * y)
let mu = Double(iteration) - (log(log(modZ))) / log(2.0)
if mu > maxMu {
maxMu = mu
}
if mu < minMu {
minMu = mu
}
buffer[yPos * width + xPos] = mu
}
else {
buffer[yPos * width + xPos] = 0
}
}
}
// Scale buffer values between 0 and 1
var count = width * height;
while count > 0 {
count -= 1
buffer[count] = (buffer[count] - minMu) / (maxMu - minMu)
}
return buffer
}
import Cocoa
func setRGB(ptr: inout [UInt8], val: Double)
{
var v = Int(val * 767)
if (v < 0) {
v = 0
} else if (v > 767){
v = 767
}
let offset: Int = v % 256
if (v<256) {
ptr[0] = 0; ptr[1] = 0; ptr[2] = UInt8(offset)
}
else if (v<512) {
ptr[0] = 0; ptr[1] = UInt8(offset); ptr[2] = 255 - UInt8(offset)
}
else {
ptr[0] = UInt8(offset); ptr[1] = 255 - UInt8(offset); ptr[2] = 0
}
ptr[3] = 255
}
public func makeRGBImage(width: Int, height: Int, buffer: [Double]) -> CGContext
{
let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue
let colorSpace = CGColorSpaceCreateDeviceRGB()
let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: 8, bytesPerRow: 4 * width, space: colorSpace, bitmapInfo: bitmapInfo)
var pix: [UInt8] = [0,0,0,0]
let dta = UnsafeMutablePointer<UInt8>(mutating: context?.data?.assumingMemoryBound(to: UInt8.self))!
// Write image data
for y in 0..<height {
let jmp = 4 * width * y
for x in 0..<width {
let indxBuf = y * width + x
setRGB(ptr: &pix, val: buffer[indxBuf])
let indxPix = 4 * x + jmp
dta[indxPix] = pix[0] // red
dta[indxPix+1] = pix[1] // green
dta[indxPix+2] = pix[2] // blue
dta[indxPix+3] = pix[3] // alpha
}
}
return context!
}
答案 0 :(得分:1)
您的代码开始绘制图形上下文。下一步可能是从上下文(CGBitmapContextCreateImage
)获取CGImage。从那里,您可以创建一个数据使用者,将信息放入文件(CGDataConsumer(url: ___)
),然后创建类型为CGImageDestinationCreateWithDataConsumer
的图像目标(kUTTypePNG
)并将图像添加到目标(CGImageDestinationAddImage
)
请务必致电CGImageDestinationFinalize
答案 1 :(得分:0)
根据Scott Thompson的建议,我在主操场页面写了以下内容。它会产生一个打开的png文件,但只是一个没有mandelbrot的灰色框。 PDF无法生成可以打开的文件。
import Cocoa
let h = 500
let w = 500
let mandelbrot = createMandelbrot(width: w, height: h, xS: -0.802, yS: -0.177, rad: 0.011, maxIteration: 110)
let context = makeRGBImage(width: w, height: h, buffer: mandelbrot)
let url = URL(fileURLWithPath: "/Users/judd/local/mandelbrot.png")
let dc = CGDataConsumer(url: url as CFURL)
let dest = CGImageDestinationCreateWithDataConsumer(dc!, kUTTypePNG, 1, nil)
CGImageDestinationAddImage(dest!, context.makeImage()!, nil)
CGImageDestinationFinalize(dest!)
然后我使用完全相同的代码,除了操场,我开始了一个新项目并将操场代码放在main中。一切都很好。然后我回到了游乐场环境并在Sources中创建了一个新文件,我在其中放置了一个包含以下函数的文件。
import Cocoa
public func writeToPNG(context: CGContext) {
let url = URL(fileURLWithPath: "/Users/judd/local/mandelbrot.png")
let dc = CGDataConsumer(url: url as CFURL)
let dest = CGImageDestinationCreateWithDataConsumer(dc!, kUTTypePNG, 1, nil)
CGImageDestinationAddImage(dest!, context.makeImage()!, nil)
CGImageDestinationFinalize(dest!)
}
public func writeToPDF(context: CGContext) {
let url = URL(fileURLWithPath: "/Users/judd/local/mandelbrot.pdf")
let dc = CGDataConsumer(url: url as CFURL)
let dest = CGImageDestinationCreateWithDataConsumer(dc!, kUTTypePDF, 1, nil)
CGImageDestinationAddImage(dest!, context.makeImage()!, nil)
CGImageDestinationFinalize(dest!)
}
我的主要游乐场页面现在看起来像
import Cocoa
let h = 500
let w = 500
let mandelbrot = createMandelbrot(width: w, height: h, xS: -0.802, yS: -0.177, rad: 0.011, maxIteration: 110)
let context = makeRGBImage(width: w, height: h, buffer: mandelbrot)
writeToPNG(context: context)
writeToPDF(context: context)
这很好用,我在我的文件中得到了一个合适的png和pdf图像。从主操场页面做事情似乎存在问题,导致一些混乱。