我使用Xcode 4.2为Mac OS X(10.7)编写了一个简单的Cocoa应用程序。该应用程序所做的全部工作就是创建一个带有可滚动子视图数组的窗口,每个子视图代表一个页面,用于在很低的级别上绘制内容。子视图的isFlipped方法提供“是”,因此每个子视图的原点在左上角。使用各种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字形绘制例程的后台进行一些非常不同的更改,但是到目前为止,我的所有实验都没有证明这可能是什么。
叹。我只想在视图的相应位置数组处有效地绘制字形数组。
有什么想法我弄错了吗?
最佳答案
经过彼得·霍西(Peter Hosey)的回应而被颠倒了脑子的大量实验(尽管其中一些并不完全正确,非常感谢!),这是我感到困惑的原因,并且我确信这是正确的解释(嗯,无论如何,代码正在执行我期望的操作。
在通常的更高级别的PostScript路径/绘制模型中,绘制字符会将当前点(路径末端)更新为下一个字符可能出现的位置,而当前用户空间的变换不变。但是在幕后,通过字形的宽度(或更准确地说,通过提前矢量)来转换文本矩阵变换,以便要绘制的下一个字符可以从新文本起点开始或相对于新文本起点开始。翻译后,文本矩阵的比例因子保持不变。
因此,仍然需要对CGContextSetTextMatrix()
进行初始设置调用以翻转文本矩阵的垂直方向(如果类似地翻转了用户空间),因为否则,这两个字形集合绘制例程都将上下颠倒地绘制字形w / r /无论文本绘图从何处开始或使用哪种绘图例程,路径绘图都可以。
这两个字形集合绘制例程均不影响当前路径。他们比那更低。我发现我可以在路径构造调用中散布任何一个例程,而不会影响路径的位置或形状。
在上面发布的代码中,CGContextShowGlyphsAtPositions()
用于绘制字形集合的位置数据都相对于与当前文本矩阵的原点相对应的用户空间点,该位置已转换到先前绘制的“ @”字形的右侧。因为我使用的字体太大,所以position[0]
导致下一个'@'字形绘制在视图范围之外,因此它不可见,但正在绘制。
但是,这两个例程之间仍然存在一些细微差别。 CGContextShowGlyphsAtPositions()
绝对不能用于将字形放置在用户空间的任何绝对位置。那么如何告诉它从哪里开始呢?答案(或至少一个答案)是,即使没有要绘制的字形,CGContextShowGlyphsAtPoint()
也会将文本矩阵的原点更新到给定的用户空间点。并且CGContextShowGlyphsAtPoint()
必须在绘制的每个字形后转换文本矩阵,因为(可以说)将整个字形集合相互叠加是什么意思(可以这么说)。
因此,人们可以使用字形计数为0的CGContextShowGlyphsAtPoint()
在用户空间中“移动”到非路径点,然后可以调用带有位置向量的CGContextShowGlyphsAtPositions()
(任意次),每个位置相对于文本矩阵的原点(或实际上是与之对应的用户空间点)进行处理,而当CGContextShowGlyphsAtPositions()
返回时,根本不更新文本矩阵的原点。
最后,请注意,提供给CGContextShowGlyphsAtPositions()
的位置数据位于用户空间坐标中。在Apple头文件中针对这些例程的注释明确表示是这样。