3

我使用 Xcode 4.2 为 Mac OS X (10.7) 编写了一个简单的 Cocoa 应用程序。该应用程序所做的只是创建一个窗口,其中包含一个可滚动的子视图数组,每个子视图代表一个页面,可以在非常低的级别上绘制内容。子View的isFlipped方法传递YES,所以每个子View的原点都是左上角。使用各种 Core Graphics 例程,我能够成功地绘制线条和填充路径以及所有有趣的 PostScripty 东西。

它从给定的字体中绘制字形让我感到困惑。

这是从程序中剪切并粘贴的完整代码,用于子视图的 -drawRect: 方法 --

- (void)drawRect:(NSRect)dirtyRect
{
  // Start with background color for any part of this view
  [[NSColor whiteColor] set];
  NSRectFill( dirtyRect );

  // Drop down to Core Graphics world, ensuring there's no side-effects
  context = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
  CGContextSaveGState(context);
  {
    //CGFontRef theFont = CGFontCreateWithFontName(CFSTR("American Typewriter"));
    //CGContextSetFont(context, theFont);
    CGContextSelectFont(context, "American Typewriter", 200, kCGEncodingMacRoman);
    CGContextSetFontSize(context, 200);

    // Adjust the text transform so the text doesn't draw upside down
    CGContextSetTextMatrix(context, CGAffineTransformScale(CGAffineTransformIdentity, 1, -1));

    CGContextSetTextDrawingMode(context, kCGTextFillStroke);
    CGContextSetRGBFillColor(context, 0.0, .3, 0.8, 1.0);

    // Find the center of view's (not dirtyRect's) bounds
    // View is 612 x 792 (nominally 8.5" by 11")

    CGPoint centerPoint;
    CGRect bds = [self bounds];
    centerPoint.x = bds.origin.x + bds.size.width  / 2;
    centerPoint.y = bds.origin.y + bds.size.height / 2;

    // Create arrays to hold glyph IDs and the positions at which to draw them.
    #define glyphCount 1                        // For now, just one glyph
    CGGlyph glyphs[glyphCount];
    CGPoint positions[glyphCount];

    glyphs[0] = 40;                             // Glyph ID for '@' character in above font
    positions[0] = centerPoint;

    // Draw above center.  This works.
    CGContextShowGlyphsAtPoint(context, centerPoint.x, centerPoint.y - 200.0, glyphs, glyphCount);

    // Draw at center.  This works.
    CGContextShowGlyphsAtPoint(context, positions[0].x, positions[0].y, glyphs, glyphCount);

    // Draw below center.  This fails (draws nothing).  Why?
    positions[0].y += 200.0;
    CGContextShowGlyphsAtPositions(context, glyphs, positions, glyphCount);
  }
  CGContextRestoreGState(context);
}

让我大吃一惊的是,使用 CGContextShowGlyphsAtPoint() 的前两个字形绘图调用按预期工作,但使用 CGContextShowGlyphsAtPositions() 的第三次尝试从未绘制任何东西。所以页面上只有两个@符号,而不是三个。这种行为差异并不取决于我之前是否使用过 CGContextSetFont() 或 CGContextSelectFont()。

这两个几乎相同的 Core Graphics 字形绘制例程肯定有一些隐藏的状态变化,或者在引擎盖下有一些非常不同的东西,但到目前为止我所有的实验都没有证明这可能是什么。

叹。我只想在视图中相应的位置数组有效地绘制一组字形。

有什么想法我错了吗?

4

2 回答 2

1

经过彼得·霍西(Peter Hosey)的回应(尽管其中一些不太正确,非常感谢!)而进行的大量实验之后,这是我困惑的根源和我很确定是正确的解释(嗯,无论如何,代码正在做我期望的事情)。

在通常的高级 PostScript 路径/绘图模型中,绘制一个字符会将当前点(路径末端)更新到下一个字符可能出现的位置,而当前用户空间变换保持不变。但在底层,文本矩阵变换是字形的宽度(或更准确地说是由一个高级向量)转换的,以便下一个要绘制的字符可以从一个新的文本 origin 开始,或者相对于一个新的文本origin开始。文本矩阵的比例因子在翻译后保持不变。

因此,翻转文本矩阵的垂直方向的初始设置调用CGContextSetTextMatrix()仍然是必要的(如果用户空间类似地翻转),因为否则两个字形集合绘图例程都会将字形颠倒绘制 w/r/t 路径绘图,无论文本绘制从何处开始或使用哪个绘制例程。

这两个字形集合绘制例程都不影响当前路径。他们比这低。我发现我可以在路径构造调用中穿插任一例程,而不会影响路径的位置或形状。

在上面发布的代码中,CGContextShowGlyphsAtPositions()用于绘制字形集合的位置数据都是对于与当前文本矩阵的原点相对应的用户空间点,该原点被翻译到先前绘制的“@”字形的右侧。因为我使用了如此大的字体大小,position[0]导致下一个“@”字形被绘制在视图边界之外,所以它不可见,但它正在被绘制。

但这两个例程之间仍然存在一些细微差别。 CGContextShowGlyphsAtPositions()永远不能用于将字形放置在任何绝对用户空间位置。那么你如何告诉它从哪里开始呢?答案(或至少一个答案)是CGContextShowGlyphsAtPoint()将文本矩阵的原点更新为给定的用户空间点,即使没有要绘制的字形也是如此。并且CGContextShowGlyphsAtPoint()必须在它绘制的每个字形之后翻译文本矩阵,因为将整个字形集合绘制在另一个之上的意义(可以这么说)是什么。

因此,可以使用字形计数为 0 的“移动”到用户空间中的非路径点CGContextShowGlyphsAtPoint(),然后可以CGContextShowGlyphsAtPositions()使用位置向量调用(任意次数),其中每个位置都将相对于文本进行处理矩阵的原点(或者实际上是与之对应的用户空间点),而文本矩阵原点在CGContextShowGlyphsAtPositions()返回时根本不会更新。

最后,请注意提供给的位置数据CGContextShowGlyphsAtPositions()是在用户空间坐标中。Apple 的头文件中对这些例程的注释明确说明了这一点。

于 2013-06-16T14:23:33.993 回答
0

一种可能性是,来自CGContextShowGlyphsAtPositions文档:

每个字形的位置在文本空间中指定,因此,通过文本矩阵转换到用户空间

文本矩阵是上下文的一个单独属性,与图形状态的当前变换矩阵不同。

没有说关于CGContextShowGlyphsAtPoint

这个函数在用户空间的指定位置显示一个字形数组。

(强调添加到两个引号。)

因此,当您从一个点显示字形时,实际上并没有使用您的文本矩阵。

但是,当您在一组位置显示字形时,它会被使用,并且您会看到错误矩阵的症状。具体来说,您尝试以另一种方式将文本翻转回来的矩阵是错误的:它将坐标系颠倒过来。您正在视图之外绘图。

(尝试将其设置为 0.5 而不是 -1,你会明白我的意思。)

我的建议是挂断你的CGContextSetTextMatrix电话。

于 2013-06-14T23:54:40.900 回答