8

Why is it so hard to figure out how to draw Unicode characters on the iPhone, deriving simple font metrics along the way, such as how wide each imaged glyph is going to be in the font of choice?

It looks like it'd be easy with NSLayoutManager, but that API apparently isn't available on the phone. It appears the way people are doing this is to use a private API, CGFontGetGlyphsForUnichars, which won't get you past the Apple gatekeepers into the App store.

Can anybody point me to documentation that shows how to do this? I'm losing hair rapidly.

Howard

hkatz
  • 951
  • 11
  • 21

3 Answers3

3

I assumed that the exclusion of CGFontGetGlyphsForUnichars
was an oversight rather than a deliberate move, however I'm not
betting the farm on it. So instead I use

[NSString drawAtPoint:withFont:]; (in UIStringDrawing.h)

and

[NSString sizeWithFont];

This also has the advantage of performing decent substitution
on characters missing from your font, something that
CGContextShowGlyphs does not do.

Rhythmic Fistman
  • 34,352
  • 5
  • 87
  • 159
  • You know: that's almost it. That takes care of my need to image the character, but not to get simple font metrics for it. Turns out tho that you can jump into and out of the current context (`UIGraphicsGetCurrentContext`) and use `CGContextGetTextPosition` before and after drawing to essentially get the width of the bounding box. That's mostly what I'm interested in deriving, so thank you! – hkatz May 25 '09 at 17:27
  • Wait, what's wrong with `[@"a" sizeWithFont:]`? Why do you need metrics for individual chars? – Andrew Pouliot May 28 '09 at 00:55
  • It gives me metrics because I do a sizeWithFont for each character. Andrew: Perhaps he wants to cache the characters to a texture, or draw them along a path. – Rhythmic Fistman May 28 '09 at 08:12
1

CoreText is the answer if you want to draw unicode rather than CGContextShowGlyphsAtPositions. Also it's better than [NSString drawAtPoint:withFont:] if you need custom drawing. Here is a complete example:

CTLineRef line = CTLineCreateWithAttributedString((CFAttributedStringRef)attributedString);
CFArrayRef runArray = CTLineGetGlyphRuns(line);

//in more complicated cases make loop on runArray
//here I assumed this array has only 1 CTRunRef within
const CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runArray, 0);

//do not use CTFontCreateWithName, otherwise you won't see e.g. chinese characters
const CTFontRef font = CFDictionaryGetValue(CTRunGetAttributes(run), kCTFontAttributeName);

CFIndex glyphCount = CTRunGetGlyphCount(run);
CGGlyph glyphs[glyphCount];
CGPoint glyphPositions[glyphCount];

CTRunGetGlyphs(run, CFRangeMake(0, 0), glyphs);
//you can modify positions further
CTRunGetPositions(run, CFRangeMake(0, 0), glyphPositions);

CTFontDrawGlyphs(font, glyphs, glyphPositions, glyphCount, context);
CFRelease(line);
icywire
  • 165
  • 1
  • 6
  • i need to export character drawn with draw(rect:) into string that can be used as string alphabets later? will it help me ? if not how should i use hand drawing alphabets as strings? – MALIKK HABIB UR REHMAN Dec 13 '21 at 12:51
0

I've made a pretty suitable replacement for the private function. Read about it here: http://thoughts.codemelody.com/2009/07/a-replacement-for-cgfontgetglyphsforunichars/

James Hu
  • 842
  • 1
  • 7
  • 17