Common Font Operations(常用字體操作)
這一章描述了一個(gè)常用的字體處理操作,并展示了怎么用CoreText代碼來實(shí)現(xiàn)它們良风。這些操作在iOS和OS X中是一樣的升酣。本章包含下面的操作列表:
- 創(chuàng)建一個(gè)字體描述符
- 從字體描述符創(chuàng)建一個(gè)字體
- 創(chuàng)建相關(guān)的字體
- 解析字體
- 用字體解析數(shù)據(jù)創(chuàng)建一個(gè)字體
- 調(diào)整字距
- 從字符中獲得符號(hào)
Creating Font Descriptors(創(chuàng)建字體描述符)
清單3-1中示例函數(shù)用PostScrpt font name
和字號(hào)作為參數(shù)創(chuàng)建一個(gè)字體描述符。
Listing 3-1 Creating a font descriptor from a name and point size
CTFontDescriptorRef CreateFontDescriptorFromName(CFStringRef postScriptName,
CGFloat size)
{
return CTFontDescriptorCreateWithNameAndSize(postScriptName, size);
}
清單3-2中的示例函數(shù)從font family name
和font traits
創(chuàng)建一個(gè)字體描述符。
Listing 3-2 Creating a font descriptor from a family and traits
NSString* familyName = @"Papyrus";
CTFontSymbolicTraits symbolicTraits = kCTFontTraitCondensed;
CGFloat size = 24.0;
NSMutableDictionary* attributes = [NSMutableDictionary dictionary];
[attributes setObject:familyName forKey:(id)kCTFontFamilyNameAttribute];
// The attributes dictionary contains another dictionary, the traits dictionary,
// which in this example specifies only the symbolic traits.
NSMutableDictionary* traits = [NSMutableDictionary dictionary];
[traits setObject:[NSNumber numberWithUnsignedInt:symbolicTraits]
forKey:(id)kCTFontSymbolicTrait];
[attributes setObject:traits forKey:(id)kCTFontTraitsAttribute];
[attributes setObject:[NSNumber numberWithFloat:size]
forKey:(id)kCTFontSizeAttribute];
CTFontDescriptorRef descriptor = CTFontDescriptorCreateWithAttributes((CFDictionaryRef)attributes);
CFRelease(descriptor);
Creating a Font from a Font Descriptor(從字體描述符創(chuàng)建字體)
清單3-3展示了怎么創(chuàng)建一個(gè)字體描述符并用它創(chuàng)建一個(gè)字體雨效。當(dāng)你調(diào)用CTFontCreateWithFontDescriptor
時(shí),你通常傳NULL
給matrix
參數(shù)來制定一個(gè)默認(rèn)(identity)的矩陣废赞。CTFontCreateWithFontDescriptor
的size
和matrix
(第二個(gè)和第三個(gè))參數(shù)會(huì)覆蓋制定的字體描述符中指定的值徽龟,除非(字體描述符中)他們沒有被指定(size
為0,matrix
為NULL
)唉地。
Listing 3-3 Creating a font from a font descriptor
NSDictionary *fontAttributes =
[NSDictionary dictionaryWithObjectsAndKeys:
@"Courier", (NSString *)kCTFontFamilyNameAttribute,
@"Bold", (NSString *)kCTFontStyleNameAttribute,
[NSNumber numberWithFloat:16.0],
(NSString *)kCTFontSizeAttribute,
nil];
// Create a descriptor.
CTFontDescriptorRef descriptor = CTFontDescriptorCreateWithAttributes((CFDictionaryRef)fontAttributes);
// Create a font using the descriptor.
CTFontRef font = CTFontCreateWithFontDescriptor(descriptor, 0.0, NULL);
CFRelease(descriptor);
Creating Related Fonts(創(chuàng)建相關(guān)字體)
把一個(gè)已經(jīng)存在的字體轉(zhuǎn)化成一個(gè)相關(guān)或類似的字體經(jīng)常是有用的据悔。清單3-4中的示例函數(shù)展示了怎么根據(jù)函數(shù)調(diào)用時(shí)傳的Boolean
參數(shù)的值,來生成一個(gè)粗體或者非粗體的字體耘沼。如果當(dāng)前字體family沒有需要的樣式极颓,這個(gè)函數(shù)返回NULL
。
Listing 3-4 Changing traits of a font
CTFontRef CreateBoldFont(CTFontRef font, Boolean makeBold)
{
CTFontSymbolicTraits desiredTrait = 0;
CTFontSymbolicTraits traitMask;
// If requesting that the font be bold, set the desired trait
// to be bold.
if (makeBold) desiredTrait = kCTFontBoldTrait;
// Mask off the bold trait to indicate that it is the only trait
// to be modified. As CTFontSymbolicTraits is a bit field,
// could change multiple traits if desired.
traitMask = kCTFontBoldTrait;
// Create a copy of the original font with the masked trait set to the
// desired value. If the font family does not have the appropriate style,
// returns NULL.
return CTFontCreateCopyWithSymbolicTraits(font, 0.0, NULL, desiredTrait, traitMask);
}
清單3-8中的示例函數(shù)把所給的字體轉(zhuǎn)換成另一個(gè)字體family中相似的字體耕拷,盡可能的保留特征讼昆。它可能返回NULL
。size
參數(shù)傳0骚烧,matrix
參數(shù)傳NULL
來保留原始字體的尺寸浸赫。
Listing 3-5 Converting a font to another family
CTFontRef CreateFontConvertedToFamily(CTFontRef font, CFStringRef family)
{
// Create a copy of the original font with the new family. This call
// attempts to preserve traits, and may return NULL if that is not possible.
// Pass in 0.0 and NULL for size and matrix to preserve the values from
// the original font.
return CTFontCreateCopyWithFamily(font, 0.0, NULL, family);
}
Serializing a Font(解析字體)
清單3-6中的示例函數(shù)展示了怎么解析字體并創(chuàng)建一個(gè)可以嵌入到文檔的XML數(shù)據(jù)。還有一種選擇赃绊,而且是比較好的既峡,可以用NSArchiver
。這只是完成任務(wù)的一種方法碧查,但是它保留了以后重新創(chuàng)建字體所需的所有數(shù)據(jù)运敢。
Listing 3-6 Serializing a font
CFDataRef CreateFlattenedFontData(CTFontRef font)
{
CFDataRef result = NULL;
CTFontDescriptorRef descriptor;
CFDictionaryRef attributes;
// Get the font descriptor for the font.
descriptor = CTFontCopyFontDescriptor(font);
if (descriptor != NULL) {
// Get the font attributes from the descriptor. This should be enough
// information to recreate the descriptor and the font later.
attributes = CTFontDescriptorCopyAttributes(descriptor);
if (attributes != NULL) {
// If attributes are a valid property list, directly flatten
// the property list. Otherwise we may need to analyze the attributes
// and remove or manually convert them to serializable forms.
// This is left as an exercise for the reader.
if (CFPropertyListIsValid(attributes, kCFPropertyListXMLFormat_v1_0)) {
result = CFPropertyListCreateXMLData(kCFAllocatorDefault, attributes);
}
}
}
return result;
}
Creating a Font from Serialized Data(從解析數(shù)據(jù)創(chuàng)建字體)
清單3-7中的示例函數(shù)展示了怎么從XML數(shù)據(jù)創(chuàng)建一個(gè)字體引用。它展示了怎么解壓出字體屬性并用那些屬性創(chuàng)建字體忠售。
Listing 3-7 Creating a font from serialized data
CTFontRef CreateFontFromFlattenedFontData(CFDataRef iData)
{
CTFontRef font = NULL;
CFDictionaryRef attributes;
CTFontDescriptorRef descriptor;
// Create our font attributes from the property list.
// For simplicity, this example creates an immutable object.
// If you needed to massage or convert certain attributes
// from their serializable form to the Core Text usable form,
// do it here.
attributes =
(CFDictionaryRef)CFPropertyListCreateFromXMLData(
kCFAllocatorDefault,
iData, kCFPropertyListImmutable, NULL);
if (attributes != NULL) {
// Create the font descriptor from the attributes.
descriptor = CTFontDescriptorCreateWithAttributes(attributes);
if (descriptor != NULL) {
// Create the font from the font descriptor. This sample uses
// 0.0 and NULL for the size and matrix parameters. This
// causes the font to be created with the size and/or matrix
// that exist in the descriptor, if present. Otherwise default
// values are used.
font = CTFontCreateWithFontDescriptor(descriptor, 0.0, NULL);
}
}
return font;
}
Changing Kerning(調(diào)整字間距)
聯(lián)結(jié)和字間距是默認(rèn)開啟的传惠。通過設(shè)置kCTKernAttributeName
屬性為0來關(guān)閉它。清單3-8在前幾個(gè)字符繪制的時(shí)候把字間距設(shè)置成一個(gè)大的數(shù)字稻扬。
Listing 3-8 Setting kerning
// Set the color of the first 13 characters to red
// using a previously defined red CGColor object.
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, 13),
kCTForegroundColorAttributeName, red);
// Set kerning between the first 18 chars to be 20
CGFloat otherNum = 20;
CFNumberRef otherCFNum = CFNumberCreate(NULL, kCFNumberCGFloatType, &otherNum);
CFAttributedStringSetAttribute(attrString, CFRangeMake(0,18),
kCTKernAttributeName, otherCFNum);
Getting Glyphs for Characters(從字符中獲取符號(hào))
清單3-9展示了怎么用一個(gè)字體從string
的characters
中獲取glyphs
卦方。大部分時(shí)間有應(yīng)該只從CTLine
對(duì)象中獲取這些信息,因?yàn)檎麄€(gè)string
可能不止用了一個(gè)字體泰佳。而且盼砍,對(duì)于復(fù)雜的文本簡(jiǎn)單的character-to-glyph mapping不會(huì)得到正確的外觀尘吗。這個(gè)簡(jiǎn)單的glyph mapping可能在你嘗試用一個(gè)字體顯示特定Unicode字符時(shí)是合適的。
Listing 3-9 Getting glyphs for characters
void GetGlyphsForCharacters(CTFontRef font, CFStringRef string)
{
// Get the string length.
CFIndex count = CFStringGetLength(string);
// Allocate our buffers for characters and glyphs.
UniChar *characters = (UniChar *)malloc(sizeof(UniChar) * count);
CGGlyph *glyphs = (CGGlyph *)malloc(sizeof(CGGlyph) * count);
// Get the characters from the string.
CFStringGetCharacters(string, CFRangeMake(0, count), characters);
// Get the glyphs for the characters.
CTFontGetGlyphsForCharacters(font, characters, glyphs, count);
// Do something with the glyphs here. Characters not mapped by this font will be zero.
// ...
// Free the buffers
free(characters);
free(glyphs);
}