Core Text Calculate Letter Frame in iOS

Core Text calculate letter frame in iOS

You did an impressive amount of work in your question and were so close on your own. The problem you were having comes from this line of code where you position the bounding boxes for each frame:

_characterFrames[ic].origin = CGPointMake(startOffset, lineOrigin.y);

The problem with it is that you are overriding whatever offset the frame already had.

If you were to comment out that line you would see that all the frames were positioned more or less in the same place but you would also see that they are not positioned at the exact same place. Some are positioned more to the left or right and some more up or down. This means that the frames for the glyphs have a position of their own.

enter image description here

The solution to your problem is to take the current position of the frames into account when you move them into their correct place on the lines. You can either do it by adding to x and y separately:

_characterFrames[ic].origin.x += startOffset;
_characterFrames[ic].origin.y += lineOrigin.y;

or by offsetting the rectangle:

_characterFrames[ic] = CGRectOffset(_characterFrames[ic],
startOffset, lineOrigin.y);

Now the bounding boxes will have their correct positions:

enter image description here

and you should see that it works for some of the more extreme fonts out there

enter image description here

Calculate Font Size to Fit Frame - Core Text - NSAttributedString - iOS

The only way I can see this being possible is to have a system that runs the size calculation then adjusts the size and repeats until it finds the right size.

I.e. set up a bisecting algorithm that goes between certain sizes.

i.e. run it for size 10.
Too small.
Size 20.
Too small.
Size 30.
Too big.
Size 25.
Too small.
Size 27.
Just right, use size 27.

You could even start in hundreds.

Size 100.
Too big.
Size 50.
etc...

Core Text - Height of glyph

Got there in the end, you can do it like this:

// Create an attributed string
CTLineRef line = CTLineCreateWithAttributedString(_string);

// Get an array of glyph runs from the line
CFArrayRef runArray = CTLineGetGlyphRuns(line);

// loop through each run in the array
CTRunRef run = ....

// Get the range of the run
CFRange range = CFRangeMake...

// Use CTRunGetImageBounds
CGRect glyphRect = CTRunGetImageBounds(run, context, range);

// glyphRect now contains the bounds of the glyph run, if the string is just 1 character you have the correct dimensions of that character.

How to calculate Frame size to draw CoreText by line

For some reasons seems that (ascent + descent) isn't the correct height for a line. In fact ascender + 1 + descender is equal to the Point Size.

Simply changing this:

CGContextSetTextPosition(context, 0.0, idx*-(ascent + descent)-ascent);

into this:

CGContextSetTextPosition(context, 0.0, idx*-(ascent - 1 + descent)-ascent);

did the trick.
Reference: Cocoanetics article about UIFont.
Thanks to jverrijt for the hint!

How to calculate the width of a text string of a specific font and font-size?

You can do exactly that via the various sizeWithFont: methods in NSString UIKit Additions. In your case the simplest variant should suffice (since you don't have multi-line labels):

NSString *someString = @"Hello World";
UIFont *yourFont = // [UIFont ...]
CGSize stringBoundingBox = [someString sizeWithFont:yourFont];

There are several variations of this method, eg. some consider line break modes or maximum sizes.



Related Topics



Leave a reply



Submit