当CGContextShowGlyphsAtPoint()确实有效时,为什么CGContextShowGlyphsAtPositions()不起作用?

时间:2013-06-13 19:51:10

标签: macos cocoa scrollview glyph

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

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

这里是从程序中剪下来的完整代码,用于sub-View&s -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字形绘制程序的情况下会有一些非常不同的变化,但到目前为止我所有的实验都没有证明这可能是什么

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

我有什么想法会出错?

2 个答案:

答案 0 :(得分:1)

经过多次实验,经过彼得·霍西的回应而被重击(尽管其中一些不太正确,非常感谢!),这是我的困惑和解释的来源我很确定是正确的(好吧,代码正在做我期望的事情,无论如何)。

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

因此,初始设置调用CGContextSetTextMatrix()以翻转文本矩阵的垂直感仍然是必要的(如果用户空间被类似地翻转),否则两个字形集合绘制例程都将绘制字形上部 - 无论文本绘图在何处开始或使用哪种绘图程序,都可以使用r / t路径绘图。

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

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

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

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

最后,请注意提供给{{1}}的位置数据位于用户空间坐标中。 Apple的头文件中对这些例程的评论明确表示如此。

答案 1 :(得分:0)

这种可能性来自CGContextShowGlyphsAtPositions文件:

  

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

The text matrix是上下文的一个独立属性,与图形状态的当前转换矩阵不同。

  

此功能在用户空间的指定位置显示一组字形

(重点加在两个引号上。)

因此,当您从单个点显示字形时,实际上不会使用您的文本矩阵。

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

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

我的建议是取出CGContextShowGlyphsAtPoint来电。