Last active
August 29, 2015 13:57
-
-
Save Norod/9392911 to your computer and use it in GitHub Desktop.
Demonstrate how to load an OTF file, change some if its internal values in-memory (Ascender, Descender, LineGap), register it and then create a UIFont object
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <CoreText/CoreText.h> | |
#define kOTFhorizontalHeaderTableRecord_tag htonl((int32_t)('hhea')) | |
typedef struct otfTableRecordStruct | |
{ | |
int32_t tag; | |
int32_t checksum; | |
int32_t offset; | |
int32_t length; | |
}otfTableRecord, *otfTableRecordPTR; | |
typedef struct otfHorizontalHeaderTableStruct | |
{ | |
int32_t version; | |
int16_t ascender; | |
int16_t descender; | |
int16_t lineGap; | |
int16_t advancedWidthMax; | |
}otfHorizontalHeaderTable, *otfHorizontalHeaderTablePTR; | |
@interface OTFModifier () | |
@property(nonatomic, strong) NSString* fontPostScriptName; | |
@property(nonatomic, strong) UIFont* uiFont; | |
@end | |
@implementation OTFModifier | |
CGFontRef cgFont; | |
- (void)dealloc | |
{ | |
[self unregisterOTF]; | |
} | |
#pragma mark - OTFun | |
- (BOOL)loadOTF:(NSURL*)otfFileURL withModifyAscender:(int)modifiedAscender modifiedDescender:(int)modifiedDescender modifiedLineGap:(int)modifiedLineGap | |
{ | |
[self unregisterOTF]; | |
NSData* otfData = [NSData dataWithContentsOfURL:otfFileURL]; | |
const char* pRawDataBuffer = (const char*)[otfData bytes]; | |
char* pCurOffset = ((char*)pRawDataBuffer) + 0x04; //Offset where the value that specifies the number of "Table Records" reside | |
int16_t numTables = htons(*((int16_t*)(pCurOffset))); | |
NSLog(@"numTables = %d", (int)numTables); | |
otfHorizontalHeaderTablePTR pHorizontalHeaderTable = NULL; | |
pCurOffset = ((char*)pRawDataBuffer) + 0x0C; //Offset where the list of "Table Records" begin | |
for (int16_t curTableIndex = 0; curTableIndex < numTables; ++curTableIndex) | |
{ | |
otfTableRecordPTR pTableRecord = (otfTableRecordPTR)pCurOffset; | |
if (pTableRecord->tag == kOTFhorizontalHeaderTableRecord_tag) | |
{ | |
NSLog(@"\nFound the Horizontal Header Table Record (tag=0x%x -> 'hhea')", (pTableRecord->tag)); | |
NSLog(@"Loading Horizontal Header Table (offset=0x%x)\n", htonl(pTableRecord->offset)); | |
pHorizontalHeaderTable = ((otfHorizontalHeaderTablePTR)(((char*)pRawDataBuffer) + htonl(pTableRecord->offset))); | |
} | |
else | |
{ | |
NSLog(@"Skipping Header Table Record (tag=0x%x -> '%c%c%c%c')", | |
(pTableRecord->tag), | |
((char*)(&(pTableRecord->tag)))[0], | |
((char*)(&(pTableRecord->tag)))[1], | |
((char*)(&(pTableRecord->tag)))[2], | |
((char*)(&(pTableRecord->tag)))[3] | |
); | |
} | |
pCurOffset+= sizeof(otfTableRecord); //+=16 | |
} | |
if (pHorizontalHeaderTable == NULL) | |
{ | |
NSLog(@"Sorry, I looked and I looked but I could not find the Horizontal Header Table Record :("); | |
return NO; | |
} | |
NSLog(@"\nHorizontal Header Table Record:"); | |
NSLog(@"version\t=\t0x%x",(int32_t)htonl(pHorizontalHeaderTable->version & 0xFFFFFFFF)); | |
NSLog(@"ascender\t=\t%hi",(int16_t)htons(pHorizontalHeaderTable->ascender & 0x0000FFFF)); | |
NSLog(@"descender\t=\t%hi",(int16_t)htons(pHorizontalHeaderTable->descender & 0x0000FFFF)); | |
NSLog(@"lineGap\t=\t%hi",(int16_t)htons(pHorizontalHeaderTable->lineGap & 0x0000FFFF)); | |
NSLog(@"advancedWidthMax\t=\t%hi",(int16_t)htons(pHorizontalHeaderTable->advancedWidthMax & 0x0000FFFF)); | |
NSLog(@"\n"); | |
NSLog(@"Patching \"ascender\" value to \"%d\"", (int)modifiedAscender); | |
pHorizontalHeaderTable->ascender = (int16_t)htons(modifiedAscender); | |
NSLog(@"Patching \"descender\" value to \"%d\"", (int)modifiedDescender); | |
pHorizontalHeaderTable->descender = (int16_t)htons(modifiedDescender); | |
NSLog(@"Patching \"lineGap\" value to \"%d\"", (int)modifiedLineGap); | |
pHorizontalHeaderTable->lineGap = (int16_t)htons(modifiedLineGap); | |
NSLog(@"Done patching\n"); | |
NSLog(@"Creating Core-Graphics Font object"); | |
CFErrorRef error; | |
CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)otfData); | |
cgFont = CGFontCreateWithDataProvider(provider); | |
if (cgFont == NULL) | |
{ | |
NSLog(@"Failed :("); | |
CFRelease(provider); | |
return NO; | |
} | |
NSLog(@"Done\n"); | |
CFStringRef cfFontPostScriptName = CGFontCopyPostScriptName(cgFont); | |
self.fontPostScriptName = CFBridgingRelease(cfFontPostScriptName); | |
if ([self.fontPostScriptName length] > 0) | |
{ | |
self.title = self.fontPostScriptName; | |
} | |
NSLog(@"Registering the font \"%@\"", self.fontPostScriptName); | |
if (! CTFontManagerRegisterGraphicsFont(cgFont, &error)) { | |
CFStringRef errorDescription = CFErrorCopyDescription(error); | |
NSLog(@"Failed to register font: %@", errorDescription); | |
CFRelease(errorDescription); | |
} | |
CFRelease(provider); | |
NSLog(@"Done\n"); | |
NSLog(@"Creating a UIFont object"); | |
self.uiFont = [UIFont fontWithName:self.fontPostScriptName size:14.0f]; | |
if (self.uiFont == nil) | |
{ | |
NSLog(@"Failed :("); | |
return NO; | |
} | |
NSLog(@"Done\n"); | |
//Test :) | |
self.uiLabel.font = self.uiFont; | |
self.uiTextField.font = self.uiFont; | |
self.uiButton.titleLabel.font = self.uiFont; | |
self.uiButton.titleLabel.text = [NSString stringWithFormat:@"%@", self.uiButton.titleLabel.text]; | |
self.uiTextView.font = self.uiFont; | |
return YES; | |
} | |
- (BOOL)unregisterOTF | |
{ | |
if (cgFont) | |
{ | |
NSLog(@"Unregistering the font"); | |
CFErrorRef error; | |
if (!CTFontManagerUnregisterGraphicsFont(cgFont, &error)) { | |
CFStringRef errorDescription = CFErrorCopyDescription(error); | |
NSLog(@"Failed to unregister font: %@", errorDescription); | |
CFRelease(errorDescription); | |
return NO; | |
} | |
else | |
{ | |
NSLog(@"Done\n"); | |
} | |
CGFontRelease(cgFont); | |
cgFont = NULL; | |
} | |
return YES; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment