Swift 使用NSBezierPath绘制点
我想创建一个单像素大小的点。我假设这样做的方法是使用NSBezierPath绘制一条线,起点等于终点(请参见下面的代码),但这样做会使窗口完全变空Swift 使用NSBezierPath绘制点,swift,cocoa,nsbezierpath,Swift,Cocoa,Nsbezierpath,我想创建一个单像素大小的点。我假设这样做的方法是使用NSBezierPath绘制一条线,起点等于终点(请参见下面的代码),但这样做会使窗口完全变空 func drawPoint() { let path = NSBezierPath() NSColor.blue.set() let fromPoint = NSMakePoint(CGFloat(100) , CGFloat(100)) let toPoint = NSMakePoint(CGFloat(100)
func drawPoint() {
let path = NSBezierPath()
NSColor.blue.set()
let fromPoint = NSMakePoint(CGFloat(100) , CGFloat(100))
let toPoint = NSMakePoint(CGFloat(100) , CGFloat(100))
path.move(to: fromPoint)
path.line(to: toPoint)
path.lineWidth = 1.0
path.stroke()
path.fill()
}
但是,如果我将toPoint坐标从100100更改为101101(或100100以外的任何一组坐标),将显示一个蓝色形状。有人知道为什么会这样吗
我发现的另一个问题是,如果将toPoint的坐标设置为(例如)101101,那么它将创建一个长度为两个像素的正方形,但也会添加另一个像素长度的模糊层(请参见下图,放大以了解详细信息)
然而,我想做的是,只放一个一像素大小的蓝色正方形,没有模糊。有人知道我怎么做吗?您有几个问题: 我想创建一个单像素大小的点 你确定吗?如果你在视网膜显示器上呢?如果您正在绘制PDF文件,并将在600 dpi激光打印机上打印,该怎么办 我假设这样做的方法是使用NSBezierPath绘制一条起点等于终点的线 如果将
lineCap
属性设置为.round
或square
,则这是绘制线宽大小的点的一种方法。默认的lineCap
为.butt
,这将导致空笔划。如果将lineCap
设置为.round
或.square
,将得到非空笔划
您需要了解坐标栅格与像素的关系:
- 在非视网膜屏幕上,整数坐标默认位于像素的边缘,而不是像素的中心。沿整数坐标的笔划跨越像素之间的边界,因此(使用
lineWidth=1.0
)可以获得多个部分填充的像素。要填充单个像素,需要使用以.5
(像素中心)结尾的坐标
- 在视网膜屏幕上,整数和半整数坐标默认位于像素的边缘,而不是像素的中心。沿整数或半整数坐标的笔划跨越像素之间的边界。当
lineWidth=1.0时,两侧的像素完全填满。如果只想填充单个像素,则需要使用以.25
或.75
结尾的坐标和线宽为0.5
的坐标
- 在未缩放PDF上下文中,
1.0的线宽
名义上对应于1/72英寸,填充像素的数量取决于输出设备
这只能在非视网膜屏幕上显示“单个像素大小的点”(或者如果缩放图形上下文)。如果你真的想在视网膜屏幕上显示一个像素点,你需要调整它。但你最好坚持点而不是像素
综上所述,以下是如何创建并笔划NSBezierPath
以填充一个像素:
import AppKit
func dotImage() -> CGImage {
let gc = CGContext(data: nil, width: 20, height: 20, bitsPerComponent: 8, bytesPerRow: 0, space: CGColorSpace(name: CGColorSpace.sRGB)!, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)!
let nsGc = NSGraphicsContext(cgContext: gc, flipped: false)
NSGraphicsContext.current = nsGc; do {
let path = NSBezierPath()
path.move(to: .init(x: 10.5, y: 10.5))
path.line(to: .init(x: 10.5, y: 10.5))
path.lineWidth = 1
path.lineCapStyle = .round
NSColor.blue.set()
path.stroke()
}; NSGraphicsContext.current = nil
return gc.makeImage()!
}
let image = dotImage()
context.setLineWidth(0.5)
context.setStrokeColor(color)
context.beginPath()
context.move(to: CGPoint(x: 100, y: 100))
context.addLine(to: CGPoint(x: 100.15, y: 100.15))
context.strokePath()
结果:
但是,您可能更喜欢直接填充矩形:
func dotImage2() -> CGImage {
let gc = CGContext(data: nil, width: 20, height: 20, bitsPerComponent: 8, bytesPerRow: 0, space: CGColorSpace(name: CGColorSpace.sRGB)!, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)!
let nsGc = NSGraphicsContext(cgContext: gc, flipped: false)
NSGraphicsContext.current = nsGc; do {
NSColor.blue.set()
CGRect(x: 10, y: 10, width: 1, height: 1).fill()
}; NSGraphicsContext.current = nil
return gc.makeImage()!
}
let image2 = dotImage2()
结果:
您有几个问题:
我想创建一个单像素大小的点
你确定吗?如果你在视网膜显示器上呢?如果您正在绘制PDF文件,并将在600 dpi激光打印机上打印,该怎么办
我假设这样做的方法是使用NSBezierPath绘制一条起点等于终点的线
如果将lineCap
属性设置为.round
或square
,则这是绘制线宽大小的点的一种方法。默认的lineCap
为.butt
,这将导致空笔划。如果将lineCap
设置为.round
或.square
,将得到非空笔划
您需要了解坐标栅格与像素的关系:
- 在非视网膜屏幕上,整数坐标默认位于像素的边缘,而不是像素的中心。沿整数坐标的笔划跨越像素之间的边界,因此(使用
lineWidth=1.0
)可以获得多个部分填充的像素。要填充单个像素,需要使用以.5
(像素中心)结尾的坐标
- 在视网膜屏幕上,整数和半整数坐标默认位于像素的边缘,而不是像素的中心。沿整数或半整数坐标的笔划跨越像素之间的边界。当
lineWidth=1.0时,两侧的像素完全填满。如果只想填充单个像素,则需要使用以.25
或.75
结尾的坐标和线宽为0.5
的坐标
- 在未缩放PDF上下文中,
1.0的线宽
名义上对应于1/72英寸,填充像素的数量取决于输出设备
这只能在非视网膜屏幕上显示“单个像素大小的点”(或者如果缩放图形上下文)。如果你真的想在视网膜屏幕上显示一个像素点,你需要调整它。但你最好坚持点而不是像素
综上所述,以下是如何创建并笔划NSBezierPath
以填充一个像素:
import AppKit
func dotImage() -> CGImage {
let gc = CGContext(data: nil, width: 20, height: 20, bitsPerComponent: 8, bytesPerRow: 0, space: CGColorSpace(name: CGColorSpace.sRGB)!, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)!
let nsGc = NSGraphicsContext(cgContext: gc, flipped: false)
NSGraphicsContext.current = nsGc; do {
let path = NSBezierPath()
path.move(to: .init(x: 10.5, y: 10.5))
path.line(to: .init(x: 10.5, y: 10.5))
path.lineWidth = 1
path.lineCapStyle = .round
NSColor.blue.set()
path.stroke()
}; NSGraphicsContext.current = nil
return gc.makeImage()!
}
let image = dotImage()
context.setLineWidth(0.5)
context.setStrokeColor(color)
context.beginPath()
context.move(to: CGPoint(x: 100, y: 100))
context.addLine(to: CGPoint(x: 100.15, y: 100.15))
context.strokePath()
结果:
但是,您可能更喜欢直接填充矩形:
func dotImage2() -> CGImage {
let gc = CGContext(data: nil, width: 20, height: 20, bitsPerComponent: 8, bytesPerRow: 0, space: CGColorSpace(name: CGColorSpace.sRGB)!, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)!
let nsGc = NSGraphicsContext(cgContext: gc, flipped: false)
NSGraphicsContext.current = nsGc; do {
NSColor.blue.set()
CGRect(x: 10, y: 10, width: 1, height: 1).fill()
}; NSGraphicsContext.current = nil
return gc.makeImage()!
}
let image2 = dotImage2()
结果:
在rob mayoff的解决方案之上,我使用NSGraphicsContext找到了一个不同的解决方案。我刚刚抓取了核心图形上下文并关闭了抗锯齿功能(见下文)
然后,我创建了一个大小为一个像素的路径:
import AppKit
func dotImage() -> CGImage {
let gc = CGContext(data: nil, width: 20, height: 20, bitsPerComponent: 8, bytesPerRow: 0, space: CGColorSpace(name: CGColorSpace.sRGB)!, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)!
let nsGc = NSGraphicsContext(cgContext: gc, flipped: false)
NSGraphicsContext.current = nsGc; do {
let path = NSBezierPath()
path.move(to: .init(x: 10.5, y: 10.5))
path.line(to: .init(x: 10.5, y: 10.5))
path.lineWidth = 1
path.lineCapStyle = .round
NSColor.blue.set()
path.stroke()
}; NSGraphicsContext.current = nil
return gc.makeImage()!
}
let image = dotImage()
context.setLineWidth(0.5)
context.setStrokeColor(color)
context.beginPath()
context.move(to: CGPoint(x: 100, y: 100))
context.addLine(to: CGPoint(x: 100.15, y: 100.15))
context.strokePath()
在向线条添加端点时,我注意到,通过给它一个大于100但小于100.5的值,可以在rob mayoff的基础上得到正好一个像素的阴影。