zoukankan      html  css  js  c++  java
  • 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,理解的并不算深入,但是写个博客来做个笔记吧。


    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这些概念之间的分别。

    按照个人的理解(语文不好,说错了请指出):

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

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

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

    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还有很多内容,随着我学习的深入会继续更新博客的。







  • 相关阅读:
    自然语言交流系统 phxnet团队 创新实训 项目博客 (十一)
    install ubuntu on Android mobile phone
    Mac OS, Mac OSX 与Darwin
    About darwin OS
    自然语言交流系统 phxnet团队 创新实训 项目博客 (十)
    Linux下编译安装qemu和libvirt
    libvirt(virsh命令总结)
    深入浅出 kvm qemu libvirt
    自然语言交流系统 phxnet团队 创新实训 项目博客 (九)
    自然语言交流系统 phxnet团队 创新实训 项目博客 (八)
  • 原文地址:https://www.cnblogs.com/riskyer/p/3347883.html
Copyright © 2011-2022 走看看