CoreText and coretext
I. Introduction to basic knowledge
1. Character and Glyphs)
An important process of text display in the typographical system is the conversion from a character to a font. A character is an element of the information, and a font is a graphical representation of a character. It also has other characteristics such as pronunciation. A character is actually an encoding in a computer. The encoding in a character set, such as the Unicode Character Set, contains a large number of characters. A font is a graph, which is generally stored in a font file. The font also has its encoding, that is, its index in the font. A single character can correspond to multiple fonts (different fonts, or different styles of the same font: bold italic, etc.); multiple characters may also correspond to one font, for example, Ligatures ).
Roman Ligatures
Next, let's take a look at the parameters of the Glyph, that is, the so-called Glyph metric Glyph Metrics.
- Bounding box (boundary box bbox) is an imaginary box, which is loaded as closely as possible.
- Baseline (baseline), a hypothetical line. All the glyphs on a line use this line as a reference for the upper and lower positions. There is a point on the left of this line called the baseline origin,
- The distance from the origin to the top of the font (the depth here is based on the baseline as the reference line), and the ascent is a positive value.
- The distance from the descent (downstream height) to the bottom of the largest font symbol from the origin to the bottom of the font. descent is a negative value (for example, the distance from the source to the bottom of the deepest font is 2, then descent is-2)
- Linegap (line spacing), linegap can also be referred to as leading (in fact, the accurate point should be called External leading), and the line height can be calculated through ascent + | descent | + linegap.
For some Metrics expertise, refer to the Free Type document Glyph metrics. In fact, iOS uses the Free Type Library for font rendering.
2. Coordinate System
First of all, I have to say that the coordinate system in Apple programming is full of tricks, and developers are often caught off guard. The origin of the traditional Mac coordinate system is in the lower left corner. For example, the default Coordinate System of NSView is in the lower left corner. However, in Mac, some views change the origin point to the upper left corner for its convenience. For example, the coordinates of NSTableView are in the upper left corner. The origin of iOS UIKit's UIView coordinate system is in the upper left corner.
At the bottom layer, the origin of the coordinate system used by the context of Core Graphics is in the lower left corner. In iOS, the underlying interface is drawn through Core Graphics. How is the coordinate series transformed? In the drawRect method of UIView, we can use UIGraphicsGetCurrentContext () to obtain the current Graphics Context. Before the drawRect method is called, the Graphics Context is created and configured. If you are careful, you can see through CGContextGetCTM (CGContextRef c) that the returned value is not CGAffineTransformIdentity.
Printing description of contextCTM: (CGAffineTransform) contextCTM = { a = 1 b = 0 c = 0 d = -1 tx = 0 ty = 460 }
This is a non-retina resolution result. If it is a, d, and ty value on retina, it will take 2. If it is iPhone 5, the value of ty will be larger. However, all functions are the same, that is, the coordinate system of the context space is flip, so that the original origin in the lower left corner is changed to the upper left corner, and the positive direction of the Y axis is also changed to downward.
As mentioned above, the Core Text is first positioned in the desktop Layout System and uses the coordinate system with the traditional origin in the lower left corner, therefore, it draws the text by referring to the origin in the lower left corner. However, the context of the drawRect method of iOS's UIView is flip. If you do not do anything, you can directly draw the Core Text on this context, you will find that the text is an image and the text is upside down.
So first we need to flip the coordinate system and insert the code.
CGContextSetTextMatrix(context, CGAffineTransformIdentity);CGContextTranslateCTM(context, 0, self.bounds.size.height);CGContextScaleCTM(context, 1.0, -1.0);
Next, we will implement a basic and simple drawing. The Code is as follows:
-(Void) drawRect :( CGRect) rect {[super drawRect: rect]; // obtain the current context CGContextRef context = UIGraphicsGetCurrentContext (); // flip the coordinate system CGContextSetTextMatrix (context, callback ); CGContextTranslateCTM (context, 0, self. bounds. size. height); CGContextScaleCTM (context, 1.0,-1.0); // draw the path CGMutablePathRef path = CGPathCreateMutable (); CGPathAddRect (path, NULL, self. bounds); // create the drawn string and CTFrame NSAttributedString * attString = [[NSAttributedString alloc] initWithString: @ "Hello core text world! "]; CTFramesetterRef framesetter = extract (CFAttributedStringRef) attString); CTFrameRef frame = extract (framesetter, CFRangeMake (0, [attString length]), path, NULL ); // draw CTFrameDraw (frame, context); // release the memory CFRelease (frame); CFRelease (path); CFRelease (framesetter );}
Effect:
Here we will explain the CTFramesetter and CTFrame. First, let's look at the two graphs to help us better understand the CoreText object model.
CTFrame can be understood as a canvas consisting of many rows (CTLine), and each row is composed of one or more small squares (CTRun). We do not need to create CTRun by ourselves, core Text automatically creates CTRun Based on the attributes of NSAttributedString. Each CTRun object corresponds to different attributes. Therefore, you can freely control the font, color, font spacing, and other information.
CTFramesetter is actually the CTFrame factory method. It generates CTRrame through the given NSAttributedString, and the system automatically creates CTTypesetter. CTTypesetter is the class for managing your fonts.
So how to use NSAttributedString? How can I set the Row Height, font style, and size?
The following lists the configurable attributes.
Const CFStringRef kCTCharacterShapeAttributeName; // The default value of the font shape attribute must be 0 for the CFNumberRef object. If the value is not 0, the corresponding character shape is defined. For example, 1 indicates the traditional character shape const CFStringRef; // The font attribute must be the CTFont object const CFStringRef kCTKernAttributeName; // The character interval attribute must be the CFNumberRef object const CFStringRef kCTLigatureAttributeName; // set whether to use the hyphen attribute to 0, indicates that the hyphen attribute is not used. The standard English hyphen (FI) and FL. The default value is 1. Both use the standard hyphen. That is, when f is searched, fl is considered as a text. It must be CFNumberRef. The default value is 1. You can set 0, 1, and 2 const CFStringRef kCTForegroundColorAttributeName. // The font color attribute must be a CGColor object. The default value is blackconst CFStringRef kctforeground; // The context font color attribute must be CFBooleanRef; default value: False; const CFStringRef kCTParagraphStyleAttributeName; // The stroke line width must be a CFNumberRef object. The default value is 0.0f and the standard value is 3.0 fconst CFStringRef k. CTStrokeColorAttributeName; // The color attribute of a stroke must be a CGColorRef object. The default value is const CFStringRef kCTSuperscriptAttributeName. // set the font's upper/lower mark attribute to the CFNumberRef object. The default value is 0, it can be-1 as subscript, 1 as superscript, and font support is required. For example, the composite style Cn1const CFStringRef kCTUnderlineColorAttributeName; // The font underline color attribute must be a CGColorRef object. The default value is the foreground color const CFStringRef kCTUnderlineStyleAttributeName. // The font underline style, if it is kCTUnderlineStyleNone, you can use CTUnderlineStypleModifiers to modify the underline style const CFStringRef kCTVerticalFormsAttributeName; // The font direction attribute of the text must be CFBooleanRef. The default value is false, true indicates that the vertical direction const CFStringRef kCTGlyphInfoAttributeName; // The font information attribute must be the CTGlyphInfo object const CFStringRef kCTRunDelegateAttributeName // CTRun the delegate attribute must be the CTRunDelegate object
Let's give an example.
-(Void) drawRect :( CGRect) rect {[super drawRect: rect]; // 1. CGContextRef context = UIGraphicsGetCurrentContext (); // 2. coordinate CGContextSetTextMatrix (context, CGAffineTransformIdentity); CGContextTranslateCTM (context, 0, self. bounds. size. height); CGContextScaleCTM (context, 1.0,-1.0); NSMutableAttributedString * attriString = [[NSMutableAttributedString alloc] initWithString: @ "this is test! "]; // Change the font color of this to red [attriString addAttribute :( NSString *) kCTForegroundColorAttributeName value :( id) [UIColor redColor]. CGColor range: NSMakeRange (0, 4)]; // change is to green [attriString addattriename :( NSString *) kCTForegroundColorAttributeName value :( id) [UIColor greenColor]. CGColor range: NSMakeRange (5, 2)]; // change the font of this. The value must be a CTFontRef [attriString addAttribute :( NSString *) kCTUnderlineStyleAttributeName value :( id) [NSNumber numberWithInt: kCTUnderlineStyleDouble] range: NSMakeRange (0, 4)]; // underline this. You can select [attriString addAttribute :( NSString *) kCTUnderlineStyleAttributeName value (id) in the specified enumeration) [NSNumber numberWithInt: kCTUnderlineStyleDouble] range: NSMakeRange (0, 4)]; // draw the path CGMutablePathRef path = CGPathCreateMutable (); CGPathAddRect (path, NULL, self. bounds); // create the drawn string and CTFrame into framesetter = inline (CFAttributedStringRef) attriString); CTFrameRef frame = inline (framesetter, CFRangeMake (0, [attriString length]), path, NULL); // draw CTFrameDraw (frame, context); // release the memory CFRelease (frame); CFRelease (path); CFRelease (framesetter );}
The effect is as follows:
Now the simple custom rendering is complete ~