Skip to content

Instantly share code, notes, and snippets.

@Bokugene
Created February 23, 2012 13:21
Show Gist options
  • Save Bokugene/1892760 to your computer and use it in GitHub Desktop.
Save Bokugene/1892760 to your computer and use it in GitHub Desktop.
Read Table Data from a CGFont, then wrap them into a OTF/TTF font.
typedef struct FontHeader {
int32_t fVersion;
uint16_t fNumTables;
uint16_t fSearchRange;
uint16_t fEntrySelector;
uint16_t fRangeShift;
}FontHeader;
typedef struct TableEntry {
uint32_t fTag;
uint32_t fCheckSum;
uint32_t fOffset;
uint32_t fLength;
}TableEntry;
static uint32_t CalcTableCheckSum(const uint32_t *table, uint32_t numberOfBytesInTable) {
uint32_t sum = 0;
uint32_t nLongs = (numberOfBytesInTable + 3) / 4;
while (nLongs-- > 0) {
sum += CFSwapInt32HostToBig(*table++);
}
return sum;
}
static uint32_t CalcTableDataRefCheckSum(CFDataRef dataRef) {
const uint32_t *dataBuff = (const uint32_t *)CFDataGetBytePtr(dataRef);
uint32_t dataLength = (uint32_t)CFDataGetLength(dataRef);
return CalcTableCheckSum(dataBuff, dataLength);
}
//Reference:
//http://skia.googlecode.com/svn-history/r1473/trunk/src/ports/SkFontHost_mac_coretext.cpp
- (NSData *)fontDataForCGFont:(CGFontRef)cgFont{
if (!cgFont) {
return nil;
}
CFRetain(cgFont);
CFArrayRef tags = CGFontCopyTableTags(cgFont);
int tableCount = CFArrayGetCount(tags);
size_t *tableSizes = malloc(sizeof(size_t) * tableCount);
memset(tableSizes, 0, sizeof(size_t) * tableCount);
BOOL containsCFFTable = NO;
size_t totalSize = sizeof(FontHeader) + sizeof(TableEntry) * tableCount;
for (int index = 0; index < tableCount; ++index) {
//get size
size_t tableSize = 0;
uint32_t aTag = (uint32_t)CFArrayGetValueAtIndex(tags, index);
if (aTag == 'CFF ' && !containsCFFTable) {
containsCFFTable = YES;
}
CFDataRef tableDataRef = CGFontCopyTableForTag(cgFont, aTag);
if (tableDataRef != NULL) {
tableSize = CFDataGetLength(tableDataRef);
CFRelease(tableDataRef);
}
totalSize += (tableSize + 3) & ~3;
tableSizes[index] = tableSize;
}
unsigned char *stream = malloc(totalSize);
memset(stream, 0, totalSize);
char* dataStart = (char*)stream;
char* dataPtr = dataStart;
// compute font header entries
uint16_t entrySelector = 0;
uint16_t searchRange = 1;
while (searchRange < tableCount >> 1) {
entrySelector++;
searchRange <<= 1;
}
searchRange <<= 4;
uint16_t rangeShift = (tableCount << 4) - searchRange;
// write font header (also called sfnt header, offset subtable)
FontHeader* offsetTable = (FontHeader*)dataPtr;
//OpenType Font contains CFF Table use 'OTTO' as version, and with .otf extension
//otherwise 0001 0000
offsetTable->fVersion = containsCFFTable ? 'OTTO' : CFSwapInt16HostToBig(1);
offsetTable->fNumTables = CFSwapInt16HostToBig((uint16_t)tableCount);
offsetTable->fSearchRange = CFSwapInt16HostToBig((uint16_t)searchRange);
offsetTable->fEntrySelector = CFSwapInt16HostToBig((uint16_t)entrySelector);
offsetTable->fRangeShift = CFSwapInt16HostToBig((uint16_t)rangeShift);
dataPtr += sizeof(FontHeader);
// write tables
TableEntry* entry = (TableEntry*)dataPtr;
dataPtr += sizeof(TableEntry) * tableCount;
for (int index = 0; index < tableCount; ++index) {
uint32_t aTag = (uint32_t)CFArrayGetValueAtIndex(tags, index);
CFDataRef tableDataRef = CGFontCopyTableForTag(cgFont, aTag);
size_t tableSize = CFDataGetLength(tableDataRef);
memcpy(dataPtr, CFDataGetBytePtr(tableDataRef), tableSize);
entry->fTag = CFSwapInt32HostToBig((uint32_t)aTag);
entry->fCheckSum = CFSwapInt32HostToBig(CalcTableCheckSum((uint32_t *)dataPtr, tableSize));
uint32_t offset = dataPtr - dataStart;
entry->fOffset = CFSwapInt32HostToBig((uint32_t)offset);
entry->fLength = CFSwapInt32HostToBig((uint32_t)tableSize);
dataPtr += (tableSize + 3) & ~3;
++entry;
CFRelease(tableDataRef);
}
CFRelease(cgFont);
free(tableSizes);
NSData *fontData = [NSData dataWithBytesNoCopy:stream
length:totalSize
freeWhenDone:YES];
return fontData;
}
@anotherrav
Copy link

Would it be possible for you to specify a license for this code? According to the GitHub guidelines, when a license isn't specified (like here), essentially nobody is legally allowed to use the code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment