CoreText编程指南(常用字体操作)

Common Font Operations(常用字体操作)

这一章描述了一个常用的字体处理操作,并展示了怎么用CoreText代码来实现它们。这些操作在iOS和OS X中是一样的。本章包含下面的操作列表:

  • 创建一个字体描述符
  • 从字体描述符创建一个字体
  • 创建相关的字体
  • 解析字体
  • 用字体解析数据创建一个字体
  • 调整字距
  • 从字符中获得符号

Creating Font Descriptors(创建字体描述符)

清单3-1中示例函数用PostScrpt font name和字号作为参数创建一个字体描述符。

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中的示例函数从font family namefont traits创建一个字体描述符。

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(从字体描述符创建字体)

清单3-3展示了怎么创建一个字体描述符并用它创建一个字体。当你调用CTFontCreateWithFontDescriptor时,你通常传NULLmatrix参数来制定一个默认(identity)的矩阵。CTFontCreateWithFontDescriptorsizematrix(第二个和第三个)参数会覆盖制定的字体描述符中指定的值,除非(字体描述符中)他们没有被指定(size为0,matrixNULL)。

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(创建相关字体)

把一个已经存在的字体转化成一个相关或类似的字体经常是有用的。清单3-4中的示例函数展示了怎么根据函数调用时传的Boolean参数的值,来生成一个粗体或者非粗体的字体。如果当前字体family没有需要的样式,这个函数返回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中的示例函数把所给的字体转换成另一个字体family中相似的字体,尽可能的保留特征。它可能返回NULLsize参数传0,matrix参数传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中的示例函数展示了怎么解析字体并创建一个可以嵌入到文档的XML数据。还有一种选择,而且是比较好的,可以用NSArchiver。这只是完成任务的一种方法,但是它保留了以后重新创建字体所需的所有数据。

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(从解析数据创建字体)

清单3-7中的示例函数展示了怎么从XML数据创建一个字体引用。它展示了怎么解压出字体属性并用那些属性创建字体。

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(调整字间距)

联结和字间距是默认开启的。通过设置kCTKernAttributeName属性为0来关闭它。清单3-8在前几个字符绘制的时候把字间距设置成一个大的数字。

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(从字符中获取符号)

清单3-9展示了怎么用一个字体从stringcharacters中获取glyphs。大部分时间有应该只从CTLine对象中获取这些信息,因为整个string可能不止用了一个字体。而且,对于复杂的文本简单的character-to-glyph mapping不会得到正确的外观。这个简单的glyph mapping可能在你尝试用一个字体显示特定Unicode字符时是合适的。

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);
}

你可能感兴趣的:(CoreText编程指南(常用字体操作))