PDA

View Full Version : Anyway to add fonts to an iPhone program?




yayaba
Apr 6, 2008, 09:11 PM
The iPhone doesn't have very many built in fonts. Is there a way to embed fonts inside your program to display?



BNicholson
Apr 7, 2008, 07:25 PM
removed

Sbrocket
Apr 8, 2008, 12:38 AM
There's actually a thread on the Cocoa-dev mailing list going around about this. The same plist key would probably work on the OSX side, although the bundling is a bit different for iPhone.

http://www.cocoabuilder.com/archive/message/cocoa/2008/4/6/203410

http://developer.apple.com/documentation/MacOSX/Conceptual/BPRuntimeConfig/Articles/PListKeys.html/apple_ref/doc/uid/20001431-SW8

See where that'll get ya.

BNicholson
Apr 8, 2008, 06:00 PM
There's actually a thread on the Cocoa-dev mailing list going around about this. The same plist key would probably work on the OSX side, although the bundling is a bit different for iPhone.

http://www.cocoabuilder.com/archive/message/cocoa/2008/4/6/203410

http://developer.apple.com/documentation/MacOSX/Conceptual/BPRuntimeConfig/Articles/PListKeys.html/apple_ref/doc/uid/20001431-SW8

See where that'll get ya.

I greatly appreciate the help! Unfortunately the solutions provided through the threads require linking to a framework that isn't supported by the Iphone SDK. Hopefully they will release a little more support for getting custom fonts working in a later version. = )

BNicholson
Apr 9, 2008, 02:45 PM
removed

BNicholson
Apr 9, 2008, 06:41 PM
removed

lee1210
Apr 9, 2008, 07:03 PM
Just in case anyone wanted the solution to this problem, all you need to do to display the correct characters is make the CGGlyph = (the decimal value of your character - 29)

Example: Say if you want to print a capital A.
You would want to set your CGGlyph = 65(Decimal value of A) - 29;
Then call CGContextShowGlyphsAtPoint or CGContextShowGlyphs as appropriate.

I have no idea as to why 29 is the magic number but there is your solution as to how to load and display(correctly) a custom font in a .ttf format = )

Interesting work, I hope this is helpful to others working on iPhone development. i was curious about the 29, it seemed nonsensical. After some research I wanted to warn that that may be specific to the font you are working with:
http://developer.apple.com/documentation/GraphicsImaging/Reference/CGFont/Reference/reference.html#//apple_ref/doc/c_ref/CGGlyph

Per that page a GCGlyph is:
An index into the internal glyph table of a font.

I don't know that every font will have things at the some position in their internal glyph table. I'm not a truetype guru, so maybe they will be, but it doesn't seem like that's a guarantee.

-Lee

lee1210
Apr 9, 2008, 08:24 PM
I suddenly got very interested in this and started digging more. There is a cmap, or "Character to Glyph Map" in the font (perhaps a few, for different platforms). This states which glyph should be used for a character in an outside encoding such as unicode. From:
http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&item_id=IWS-Chapter08#ba57949e

The ‘cmap’ table is used to convert from an outside encoding (such as Unicode) to internal glyph ids.

I am not sure if the cmap(s) can be accessed using the CGFontRef, but I am going to keep digging. If there is, it should be easy to write a routine that takes an NSString or utf8 string and turns it into an array of Glyphs.

-Lee

lee1210
Apr 9, 2008, 09:46 PM
I'm not there yet, but this seems to be the way you might be able to get glyphs for a generic font:

NSTextStorage
setFont
You have to pass an NSFont to this. This might complicate things because you have a CGFontRef, but hopefully it's easy to get the NSFont pretty similarly.
setCharacters
Pass an NSArray of characters. I would just pass in 0-127 or 0-256

NSLayoutManager
glyphIndexForCharacterAtIndex
You should be able to pass in a character index (which would just be the ascii values or unicode code points) and get the glyph back. it will be a NSUInteger, but you should be able to cast that to a CGGlyph. The CGGlyph is an unsigned short, not an integer, but I think the cast should do it.

I'm afraid other than parsing the font yourself, this is the only way to go. I have C code that parses a ttf, but I didn't write it and it belongs to my employer, so I probably can't share it. It's painful anyway.

You may not need to do this, but it's probably the best way to go unless you want to make the glyph list for each font you will use.

That is also a valid method. For each font you will use, just figure out a map of the characters (at least the ones you want to use) to the glyphs and keep it around to use when you use that font.

Good luck.

-Lee

yayaba
Apr 10, 2008, 02:17 AM
Wow, great work guys. I've been a bit busy lately so I haven't had time to code (haven't even tried Beta 3 yet!) but I'll start digging around what you guys suggested.

Thanks!

Andy55
Jan 30, 2010, 04:18 PM
Hey guys, I was in need of a unicode-to-glyph converter, so here's what I came up with using the lead provided by lee1210 (thanks!).

Note the comments/warnings in the body and that since this proc has high overhead, you'll want to cache the results, etc. The class 'UtilStr' is our in-house string C++ wrapper and should be self-explainitory.

Finally, can someone confirm that I'm not leaking anything? I'm not a Cocoa guy, so that stuff doesn't jump out at me. Thanks in advance!


void GetGlyphsForUniChars( const UtilStr& inTypefaceName, const UniChar inChars[], int inNumChars, CGGlyph outGlyphs[] ) {

// A negative length denotes that inChars[] is NUL terminated.
if ( inNumChars < 0 ) {
inNumChars = 0;
while ( inChars && inChars[ inNumChars ] )
inNumChars++;
}

if ( inNumChars <= 0 )
return;

NSString* srcChars = [ NSString stringWithCharacters: inChars length: inNumChars ];
NSString* fontName = [ NSString stringWithUTF8String: inTypefaceName.CStr() ];
NSFont* font = [ NSFont fontWithName:fontName size:0 ];

NSTextStorage* textStorage = [[ NSTextStorage alloc ] initWithString: srcChars ];

if ( font ) {
[ textStorage setFont: font ];
} else {
ss_break();
}

NSLayoutManager* layoutMgr = [[ NSLayoutManager alloc ] init ];
[ textStorage addLayoutManager: layoutMgr ];


// Unicode strings can be arbitraily complex and all kinds of reordering and glyph combination can occur (including consolidation to fewer glyphs).
// We assume below that one unicode char maps to one glyph and that they occur in order. Since this assuption doesn't hold for asian languages,
// we must be careful. Fortunately, for typical western fonts and the text we intend to convert, this is good enough.
SInt32 numGlyphs = [ layoutMgr numberOfGlyphs ];
ss_assert( (int) numGlyphs == inNumChars );

NSGlyph* nsglyphs = (NSGlyph*) ss_malloc( sizeof( NSGlyph ) * numGlyphs );

NSRange range = { 0, numGlyphs };
[ layoutMgr getGlyphsInRange : range glyphs: nsglyphs characterIndexes:NULL glyphInscriptions:NULL elasticBits:NULL ];

{
int i;

for ( i = 0; i < numGlyphs; i++ ) {
if ( nsglyphs[ i ] < 0xFFFF ) {
outGlyphs[ i ] = (CGGlyph) nsglyphs[ i ];
} else {
outGlyphs[ i ] = 0;
}
}

for ( ; i < inNumChars; i++ ) {
outGlyphs[ i ] = 0;
}
}

ss_free( nsglyphs );
nsglyphs = NULL;

[ layoutMgr release ];
[ textStorage release ];
}