CoreText学习(一)Base Objects of Core Text

最近要作一个读入Word,PDF格式等的文件而且加以编辑的程序,原本觉得使用Text Kit结合Text View来打开doc文件是彻底没问题的,结果用了各类方法打开要么是数据是nil,要么打开的文字中不少乱码。对于Word,PDF这种格式或许必需要用底层的Core Text来作了(若是用WebView来作的话,很难对内容进行操做)。框架

因此接下来又要从Core Text从头学起了。首先看了Core Text Programming Guide,理解的并不算深刻,可是写个博客来作个笔记吧。ide


Core Text是一个iOS中一个比较底层的框架,借用iOS7 Text Kit介绍视频中的一个图:布局


其中Core Text在Core Graphics之上,Text Kit在Core Text之上构建(UIWebView不在Text Kit之上,不少Text Kit中很棒的特性UIWebView没法使用)。学习

在文档中,Core Text被描述为一个高级的、底层的框架,主要用来对文本进行排版布局和字体处理。字体

Core Text有一个很强大的功能就是进行Character-to-glyph转换,其实以前看Text Kit的时候glyph这个词就是一个高频出现的词,我的以为必需要分清楚character,glyph,font这些概念之间的分别。ui

按照我的的理解(语文很差,说错了请指出):spa

(1)character:字符,指一个符号,数字或者文字等。.net

(2)glyph:字形,对于同一套字符有不一样的写法,形态或者说是样式。字形是字符的一族形态,例如Helvetica, New Romancode

(3)font:字体,在字形的基础上进行的加工修饰便构成了字体,如加粗,倾斜,加颜色,改变磅数等。例如orm

9pt Helvetica Bold是一个字体。

回到文档来看看Character-to-glyph conversion:


对应同一个字符A,有着各类不一样的形态,对应不一样的字形glyph,固然同一种风格的写法便构成了一种字形。


一样地,对于f加l两个字符连起来写便又变成了一种新的写法,对应另一种字形。

经过Core Text能够快速高效地进行字符到字形之间的转换。

使用Core Text能够直接使用Core Foundation的对象,这些对象是toll-free bridging的(一种容许某些OC类与其对应的CoreFoundation类之间能够互换使用的机制),因此无需进行特殊的对象类型转换。另外Core Text构建于Core Graphics框架之上,因此能够经过Core Graphics的方法进行高效高质量的文字描画。


接下来是Core Text的一些Base Objects。

1.Layout Objects:Framesetters, Frames, Typesetters, Lines and Glyph runs

仍是先上个图吧:


其中framesetter经过attributed string对象持有文本的内容,并调用typesetter来建立line对象从而填满由CGPath所描述的区域。输出的结果是包含了一系列行对象的一个frame。

其中每个line中对于相同属性内的一段文字使用同一个的CTRun对象去描画该段文字:


下面这张图(来自raywenderlich)更加容易理解:


其中CTRun对象会由Core Text自动生成,不须要也不该该由开发者本身去建立,因此整个程序跑起来有不少细节是开发者不用考虑的。


2.Font Objects:Fonts, Font Descriptors, Font Collections

Font Descriptor用来描述字体的特性,是Font的核心部分,Font Collections是许多个Font Descriptors的集合。


说完一大堆Core Text的基本对象后,仍是写个Demo看看(主要参考了http://blog.csdn.net/andypan1314/article/details/7614469)

首先要使用Core Text框架的话,第一步是要导入CoreText.framework,而后在要使用的头文件中导入:

 

#import <CoreText/CoreText.h>

 

 

在使用Core Text来draw文字的时候,关键是要使用UIView中的drawRect:方法,因此先新建一个ViewController,而后新建一个UIView的子类,并将两者在视图上关联起来。

而后重写View中的drawRect:方法:

 

- (void)drawRect:(CGRect)rect
{
    [super drawRect:rect];
    
    // 1.建立一个字符串用来保存文本内容  CFAttributedString
    NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:@"First Core Text Demo"];
    
    
    // 2.建立一个framesetter用来管理描画文字的frame  CTFramesetter
    CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attrString);
    
    
    // 3.建立一个用来描画文字的路径,其区域为当前视图的bounds  CGPath
    CGMutablePathRef path = CGPathCreateMutable();
    CGRect rectForPath = CGRectMake(0.0, 0.0, self.bounds.size.width, self.bounds.size.height - 20.0);
    CGPathAddRect(path, NULL, rectForPath);
    
    
    // 4.建立由framesetter管理的frame,是描画文字的一个视图范围  CTFrame
    CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, attrString.length), path, NULL);
    
    
    // 5.获取当前视图的上下文环境
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    
    // 6.经过context在frame中描画文字内容
    CTFrameDraw(frame, context);
    
    
    // 7.全部建立的对象必须被release
    CFRelease(frame);
    CFRelease(path);
    CFRelease(frameSetter);
}


 

以上代码中各个对象的建立顺序基本与Figure 1.3相同。

其中首先对NSAttributedString强制类型转换获得CFAtttributedString对象用来保存文本内容,而后建立一个CTFramesetter对象用来保存文本内容、在所管理的Frame中对文字进行布局、输出文字等,接着建立CGPath对象和CTFrame对象,两者定义了一个输出文字内容的区域。注意CTTypesetter在CTFramesetter建立时随之而生成了,不须要再手动去建立。

在基本对象建立好后,获取当前视图上下文并设置好一些仿射变换后,直接在Frame中draw就完成了文字的输出:


注意最后全部建立的Core Foundation对象都必须被释放。


还有一个大问题,draw出来的文字是倒过来的,必需要将它们倒回来。

这就涉及到仿射变换的内容了,有篇文章挺好理解的:http://hi.baidu.com/cqhg1981/item/1a527bf4bda2fb0fc6dc45aa

主要的仿射变换有下面几种:



其中translation是平移,flip是翻转,rotation是旋转,scaling是缩放,shear是错切,identity是保持不变。


再看看基本的仿射变换代码:

 

// 平移仿射变换:tx为x正方向上的位移量,ty为y正方向上的位移量
CGContextTranslateCTM(CGContextRef c, CGFloat tx, CGFloat ty)

// 缩放仿射变换:在原点的基础上进行缩放,sx为x正方向上的缩放倍数,sy为y正方向上的缩放倍数。若是缩放倍数为负数则为反向缩放
CGContextScaleCTM(CGContextRef c, CGFloat sx, CGFloat sy);

// 旋转仿射变换:angle为旋转角度,逆时针为正,顺时针为负
CGContextRotateCTM(CGContextRef c, CGFloat angle);


 

CGContextRef context =UIGraphicsGetCurrentContext();下面加上如下代码。

首先设置好初始的仿射变换矩阵(原封不动):

 

CGContextSetTextMatrix(context, CGAffineTransformIdentity);

 


而后将整个视图向右移动10.0,向下方移动整个视图的高度:

 

CGContextTranslateCTM(context, 10.0, self.bounds.size.height);


最后倒过来(方向放大):

 

 

CGContextScaleCTM(context, 1.0, -1.0);


Run一下:

 


完成了。


Core Text还有不少内容,随着我学习的深刻会继续更新博客的。

相关文章
相关标签/搜索