0

I have been trying to measure glyph bounds precisely but this code prints out 916!!! The real width of this is 69.

- (void)drawRect:(NSRect)dirtyRect {
        CGContextRef main = [[NSGraphicsContext currentContext] graphicsPort];
        CGContextSetTextMatrix(main, CGAffineTransformIdentity);
        CGGlyph g;
        CGPoint p  = CGPointMake(100, 100);
        CGRect rect = CGRectMake(0, 0, 0, 0);
        CGFontRef font = CGFontCreateWithFontName((CFStringRef)@"Arial");
        g = CGFontGetGlyphWithGlyphName(font, CFSTR("L"));
        CGContextSetFont(main, font);
        CGContextSetTextPosition(main, 0, 0);
        CGContextSetFontSize(main, 200);
        CGContextSetRGBFillColor(main, 0, 0, 1, 1);
        CGContextShowGlyphsAtPositions(main, &g, &p, 1);
        CGFontGetGlyphBBoxes(font, &g, 1, &rect);
        printf("%f", rect.size.width);
    }
olaf
  • 51
  • 9
  • What are you _really_ trying to do? TextKit might do it a lot more easily. – matt May 16 '18 at 16:32
  • Becouse I want do render single glyphs and change them rapidly – olaf May 16 '18 at 16:34
  • 1
    That's not much of an explanation. What's happening here that couldn't be done with TextKit, or even NSString? – matt May 16 '18 at 16:41
  • If your performance needs are so tight that basic `NSString` drawing is failing you, it seems strange that you could accept a drawing method that calls `CGFontCreateWithFontName` with the same font every time. Is the above code really substantially faster than `[NSString drawAtPoint:withAttributes:]` (with a statically defined set of attributes so you don't have to recompute font objects every time?) Or do you really need *glyphs* like ligatures? (Maybe your current example is misleading because it uses "L?") (Not to detract from LGP's answer, which I'm sure is what you need here.) – Rob Napier May 16 '18 at 17:43
  • It's only simple example for my own test – olaf May 16 '18 at 17:51

1 Answers1

4

You are using CGFontGetGlyphBBoxes, which returns the size in glyph space units. To use this, you need to scale it with the units per em and the font size.

CGRect rect;
CGFontRef font = CGFontCreateWithFontName((CFStringRef)@"Arial");
CGFloat fontSize = 200.0;
CGGlyph g = CGFontGetGlyphWithGlyphName(font, CFSTR("L"));
CGFontGetGlyphBBoxes(font, &g, 1, &rect);
CGFloat width = rect.size.Width / CGFontGetUnitsPerEm(font) * fontSize;

An alternate way to do it to use [NSFont boundingRectForCGGlyph:].

NSFont *font = [NSFont fontWithName:@"Arial" size:200];
NSRect rect = [font boundingRectForCGGlyph:g];

boundingRectForCGGlyph
Returns the bounding rectangle for the specified glyph, scaled to the receiver’s size.

LGP
  • 4,135
  • 1
  • 22
  • 34