2017-12-02 141 views
2

:我代替我的原代码存根与自足版本CTFontDrawGlyphs绘制编辑时间不正确的位置

我使用Quartz2D画音乐符号的CGContext上。我正在使用Swift 4在Playground中做这件事。

音符由用于音符的单个CGGlyph和用于茎的线原语组成。字形取自音乐字体“bravura”。 书写笔字形的x位置正好位于其左边缘。茎必须完全对齐这个原点,因此它的X位置必须是纸头的X位置+茎的厚度/ 2.

我有一个函数,它将CGFloat作为x位置并绘制字形和干到CGContext。当x的值是像30.0这样的四舍五入值时,这可以很好地工作。然而,当值就像是30.9的分数,茎被错位:

picture of 1 good and 1 bad note

很明显,该线正确绘制,但字形忽略CGFloat的小数部分。当我将x值进一步提高到31.0时,两个部分再次同步。

这里是简化代码,这会在你的XCode9游乐场工作:

import PlaygroundSupport 
import Cocoa 

let fontSize = CGFloat(64) 

// uncomment the next paragraph if you have added the "Bravura" Font to the ressources folder 
/* 
let fontURL = Bundle.main.url(forResource: "Bravura", withExtension: "otf") 
CTFontManagerRegisterFontsForURL(fontURL! as CFURL, CTFontManagerScope.process, nil) 
var font = CTFontCreateWithName("Bravura" as CFString, fontSize, nil) 
*/ 

// comment out the next line if you use Bravura 
var font = CTFontCreateWithName("Helvetica" as CFString, fontSize, nil) 

func drawAtXPosition(_ posX: CGFloat, inContext context: CGContext) { 
    // draw font glyph (notehead) 
    var glyph = CTFontGetGlyphWithName(font, "uniE0A3" as CFString) 
    var notePosition = CGPoint(x: posX, y: 100) 
    CTFontDrawGlyphs(font, &glyph, &notePosition, 1, context) 

    // draw line (note stem) 
    let stemThickness = CGFloat(fontSize/4*0.12) 
    let x: CGFloat = posX + stemThickness/2 
    let y: CGFloat = 100 - (0.168 * fontSize/4) 
    let stemBegin = CGPoint(x:x, y:y) 
    let stemEnd = CGPoint(x:x, y: y - (3.5 * fontSize/4)) 

    context.setLineWidth(stemThickness) 
    context.strokeLineSegments(between: [stemBegin, stemEnd]) 
} 

class MyView: NSView { 
    override func draw(_ rect: CGRect) { 
     let context = NSGraphicsContext.current!.cgContext 
     context.setStrokeColor(CGColor.black) 
     context.setFillColor(CGColor.black) 

     drawAtXPosition(100, inContext: context) // this draws as expected 

     drawAtXPosition(200.99, inContext: context) // here the glyph is drawn at x=200, while the line is correctly drawn at 200.99 
    } 
} 

var myView = MyView(frame: CGRect(x: 0, y: 0, width: 500, height: 200)) 
let myViewController = NSViewController() 
myViewController.view = myView 
PlaygroundPage.current.liveView = myViewController 

您可以从下载音乐字体 “炫耀的表现” ......

https://www.smufl.org/fonts/

...但我重写了代码,因此它默认使用Helvetica,这也适用于演示。

作为我原始代码中的解决方法,我在将x值传递给绘图函数之前实现了Foundation的.rounded()方法。这是有效的,但恐怕在小字号(整个代码的写入使得所有的字体都是围绕字体大小)时,这种不准确将会引起人们的注意。

我遇到了CGContext的setShouldSubpixelPositionFonts和setAllowsFontSubpixelPositioning方法,但将它们设置为true并没有做任何改变。

那么,有没有一种方法可以像原始图一样精确绘制字体对象(必须有一个)?或者,我担心将CGFloats四舍五入到Ints是不合理的?

+0

添加完整的自包含代码可能会有帮助,其他人可以将其复制到Playground中以重现问题并尝试可能的解决方案。 –

+0

谢谢指出。随着我的第一个版本,我希望能够找到遇到同样问题的人,所以我很快包装了一些线来证明问题。正如你所看到的,一个工作版本实际上需要更多的代码,但现在我终于有时间重写我的第一个版本了。 – MassMover

回答

0

无尽的挖掘后,我找到了解决办法:

这是不够的设定

context.setShouldSubpixelPositionFonts(true) 

您还可以设置

context.setShouldSubpixelQuantizeFonts(false) 

,因为后者似乎超越了前者。