Accessing OpenType Features in UIKit or CoreText
Asked Answered
C

1

7

I am using a custom font in OpenType(.otf) format and would like to use some of the OpenType Features of the font.

How can I accomplish this with UIKit or CoreText? I would obviously prefer UIKit, but looking at UIFont, the options are extremely limited.

There seems to be a complete absence of documentation regarding OpenType support on iOS, except that the font format can be used.

Related reading: Microsoft's reference for OpenType features, and some info on how browsers are beginning to offer OpenType feature support. Though this question is for rendering fonts with OpenType features on iOS natively.

Cullen answered 7/2, 2013 at 6:28 Comment(0)
C
7

Since all I'm hearing are crickets in this dark and lonesome Core Text place, I thought I'd post the answer I found on my own.

The answer is UIKit does not support the setting of OpenType features within its framework(at the time of writing), you have to drop down to Core Text to do it, and luckily they do have an API that exposes additional font features.

I won't go into detail about using Core Text to draw text, but the relevant idea is you will need to get a CTFontDescriptorRef that defines all the attributes of the font that will be used to draw your text.

Sample Code:

CTFontDescriptorRef fontDescriptorNoFeatures = CTFontDescriptorCreateWithNameAndSize((__bridge CFStringRef)self.font.fontName, pointSize);

// Set up OpenType Attributes
CFAllocatorRef defaultAllocator = CFAllocatorGetDefault();

int numberSpacing = kNumberSpacingType;
int numberSpacingType = kMonospacedNumbersSelector;

CFNumberRef numberSpacingId = CFNumberCreate(defaultAllocator, kCFNumberIntType, &numberSpacing);
CFNumberRef monospacedNumbersSelector = CFNumberCreate(defaultAllocator, kCFNumberIntType, &numberSpacingType);

CTFontDescriptorRef fontDescriptor = CTFontDescriptorCreateCopyWithFeature(fontDescriptorNoFeatures, numberSpacingId, monospacedNumbersSelector);

CFRelease(fontDescriptorNoFeatures);
CFRelease(numberSpacingId);
CFRelease(monospacedNumbersSelector);

The main thing I am doing here is making a copy, using CTFontDescriptorCreateCopyWithFeature(), of the normal font descriptor with an additional feature, in OpenType it is called "Tabular Figures", but in Core Text you would access this feature by using the number spacing feature (kNumberSpacingType), and set the value for the appropriate enum defined in <CoreText/SFNTLayoutTypes.h>.

For the number spacing feature the enum values(for some reason they call them selectors!?!) are:

enum {
  kMonospacedNumbersSelector    = 0,
  kProportionalNumbersSelector  = 1,
  kThirdWidthNumbersSelector    = 2,
  kQuarterWidthNumbersSelector  = 3
};

So the trick is there isn't a direct one-to-one mapping of OpenType to CoreText features, but it appears they all are there, you'll just need to go through the pain of identifying the feature by looking through the constants defined in <CoreText/SFNTLayoutTypes.h>.

The rest of the pain is now you have to draw the text with this font in Core Text, instead of a higher level view, but there are lots of references out there for doing that.

Cullen answered 13/11, 2013 at 19:24 Comment(2)
I know this is a really old question/answer but it might be worth checking out developer.apple.com/videos/play/wwdc2016/803 from WWDC 2016 as there are examples on how to use the features using UIFont and modifying an existing descriptor. Around page 216 of the PDF slides.Crescantia
Core Text added support for loading OpenType features using kCTFontOpenTypeFeatureTag and kCTFontOpenTypeFeatureValue, which are defined as OS X 10.10+ and iOS 8.0+ in the Core Text headers.Agreed

© 2022 - 2024 — McMap. All rights reserved.