使用 NSBezierPath 绘制点

Par*_*waj 1 cocoa nsbezierpath swift

我想创建一个像素大小的点。我假设这样做的方法是使用 NSBezierPath 画一条线,起点等于终点(参见下面的代码),但这样做会产生一个完全空的窗口。

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()
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我将 toPoint 坐标从 100,100 更改为 101,101(或 100,100 以外的任何坐标集),则会显示蓝色形状。有谁知道为什么会这样?

我发现的另一个问题是,如果您将 toPoint 的坐标设置为等于(例如)101,101,那么它将创建一个长度为两个像素的正方形,但还会添加另一个像素长度的模糊层(请参见下图,放大为细节)。

正方形图片

然而,我想做的只是放置一个像素大小的单个蓝色小方块,没有模糊。有谁知道我该怎么做?

rob*_*off 5

你有几个问题:

\n\n
\n

我想创建一个像素大小的点。

\n
\n\n

你确定吗?如果您使用的是 Retina 显示屏怎么办?如果您正在绘制要在 600 dpi 激光打印机上打印的 PDF,该怎么办?

\n\n
\n

我假设这样做的方法是使用 NSBezierPath 画一条线,起点等于终点

\n
\n\n

如果将属性设置为或lineWidth,则这是一种绘制 - 大小的点的方法。默认值为,这会导致空笔画。如果您设置为或,您将得到一个非空笔画。lineCap.round.squarelineCap.buttlineCap.round.square

\n\n
\n
let fromPoint = NSMakePoint(CGFloat(100) , CGFloat(100))\nlet toPoint = NSMakePoint(CGFloat(100) , CGFloat(100))\npath.move(to: fromPoint)\npath.line(to: toPoint)\n
Run Code Online (Sandbox Code Playgroud)\n
\n\n

您需要了解坐标网格与像素的关系:

\n\n
    \n
  • 在非视网膜屏幕上,整数坐标默认位于像素边缘,而不是像素中心。沿着整数坐标的笔划跨越像素之间的边界,因此(使用lineWidth = 1.0)您会得到多个部分填充的像素。要填充单个像素,您需要使用以.5(像素中心)结束的坐标。

  • \n
  • 在视网膜屏幕上,整数和半整数坐标默认位于像素的边缘,而不是像素的中心。沿着整数或半整数坐标的笔划跨越像素之间的边界。使用 时lineWidth = 1.0,两侧的像素都被完全填充。如果只想填充单个像素,则需要使用.25以 or.75和 a lineWidthof结尾的坐标0.5

  • \n
  • 在未缩放的 PDF 环境中,alineWidth名义上1.0对应于 1/72 英寸,填充像素的数量取决于输出设备。

  • \n
\n\n
\n
path.lineWidth = 1.0\n
Run Code Online (Sandbox Code Playgroud)\n
\n\n

这只能在非 Retina 屏幕上为您提供 \xe2\x80\x9ca 单个像素大小的点\xe2\x80\x9d(或者如果您缩放了图形上下文)。如果您确实想要在视网膜屏幕上显示单个像素点,则需要调整它。但你最好坚持使用点而不是像素。

\n\n

综上所述,以下是创建和描边NSBezierPath以填充一个像素的方法:

\n\n
import AppKit\n\nfunc dotImage() -> CGImage {\n    let gc = CGContext(data: nil, width: 20, height: 20, bitsPerComponent: 8, bytesPerRow: 0, space: CGColorSpace(name: CGColorSpace.sRGB)!, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)!\n    let nsGc = NSGraphicsContext(cgContext: gc, flipped: false)\n    NSGraphicsContext.current = nsGc; do {\n\n        let path = NSBezierPath()\n        path.move(to: .init(x: 10.5, y: 10.5))\n        path.line(to: .init(x: 10.5, y: 10.5))\n        path.lineWidth = 1\n        path.lineCapStyle = .round\n        NSColor.blue.set()\n        path.stroke()\n\n    }; NSGraphicsContext.current = nil\n    return gc.makeImage()!\n}\n\nlet image = dotImage()\n
Run Code Online (Sandbox Code Playgroud)\n\n

结果:

\n\n

点图像

\n\n

但是,您可能更喜欢直接填充矩形:

\n\n
func dotImage2() -> CGImage {\n    let gc = CGContext(data: nil, width: 20, height: 20, bitsPerComponent: 8, bytesPerRow: 0, space: CGColorSpace(name: CGColorSpace.sRGB)!, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)!\n    let nsGc = NSGraphicsContext(cgContext: gc, flipped: false)\n    NSGraphicsContext.current = nsGc; do {\n\n        NSColor.blue.set()\n        CGRect(x: 10, y: 10, width: 1, height: 1).fill()\n\n    }; NSGraphicsContext.current = nil\n    return gc.makeImage()!\n}\n\nlet image2 = dotImage2()\n
Run Code Online (Sandbox Code Playgroud)\n\n

结果:

\n\n

点图像 2

\n