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);
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,783评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,360评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,942评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,507评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,324评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,299评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,685评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,358评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,652评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,704评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,465评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,318评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,711评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,991评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,265评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,661评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,864评论 2 335

推荐阅读更多精彩内容