title: Core Text calculate letter frame in iOS
body: <p>I need to calculate exact bounding box for every each character (glyph) in NSAttributedString (Core Text).
  After putting together some code used to solve similar problems (Core Text selection, etc..), the result is quite good, but only few frames (red) are being calculated properly:</p>
  
  <p><img src="https://i.stack.imgur.com/Jxd2T.jpg" alt="enter image description here"></p>
  
  <p>Most of the frames are misplaces either horizontally or vertically (by tiny bit). What is the cause of that? How can I perfect this code?:</p>
  
  <pre><code>-(void)recalculate{
  
      // get characters from NSString
      NSUInteger len = [_attributedString.string length];
      UniChar *characters = (UniChar *)malloc(sizeof(UniChar)*len);
      CFStringGetCharacters((__bridge CFStringRef)_attributedString.string, CFRangeMake(0, [_attributedString.string length]), characters);
  
      // allocate glyphs and bounding box arrays for holding the result
      // assuming that each character is only one glyph, which is wrong
      CGGlyph *glyphs = (CGGlyph *)malloc(sizeof(CGGlyph)*len);
      CTFontGetGlyphsForCharacters(_font, characters, glyphs, len);
  
      // get bounding boxes for glyphs
      CTFontGetBoundingRectsForGlyphs(_font, kCTFontDefaultOrientation, glyphs, _characterFrames, len);
      free(characters); free(glyphs);
  
      // Measure how mush specec will be needed for this attributed string
      // So we can find minimun frame needed
      CFRange fitRange;
      CGSize s = CTFramesetterSuggestFrameSizeWithConstraints(_framesetter, rangeAll, NULL, CGSizeMake(W, MAXFLOAT), &amp;fitRange);
  
      _frameRect = CGRectMake(0, 0, s.width, s.height);
      CGPathRef framePath = CGPathCreateWithRect(_frameRect, NULL);
      _ctFrame = CTFramesetterCreateFrame(_framesetter, rangeAll, framePath, NULL);
      CGPathRelease(framePath);
  
  
      // Get the lines in our frame
      NSArray* lines = (NSArray*)CTFrameGetLines(_ctFrame);
      _lineCount = [lines count];
  
      // Allocate memory to hold line frames information:
      if (_lineOrigins != NULL)free(_lineOrigins);
      _lineOrigins = malloc(sizeof(CGPoint) * _lineCount);
  
      if (_lineFrames != NULL)free(_lineFrames);
      _lineFrames = malloc(sizeof(CGRect) * _lineCount);
  
      // Get the origin point of each of the lines
      CTFrameGetLineOrigins(_ctFrame, CFRangeMake(0, 0), _lineOrigins);
  
      // Solution borrowew from (but simplified):
      // https://github.com/twitter/twui/blob/master/lib/Support/CoreText%2BAdditions.m
  
  
      // Loop throught the lines
      for(CFIndex i = 0; i &lt; _lineCount; ++i) {
  
          CTLineRef line = (__bridge CTLineRef)[lines objectAtIndex:i];
  
          CFRange lineRange = CTLineGetStringRange(line);
          CFIndex lineStartIndex = lineRange.location;
          CFIndex lineEndIndex = lineStartIndex + lineRange.length;
  
          CGPoint lineOrigin = _lineOrigins[i];
          CGFloat ascent, descent, leading;
          CGFloat lineWidth = CTLineGetTypographicBounds(line, &amp;ascent, &amp;descent, &amp;leading);
  
  
          // If we have more than 1 line, we want to find the real height of the line by measuring the distance between the current line and previous line. If it's only 1 line, then we'll guess the line's height.
          BOOL useRealHeight = i &lt; _lineCount - 1;
          CGFloat neighborLineY = i &gt; 0 ? _lineOrigins[i - 1].y : (_lineCount - 1 &gt; i ? _lineOrigins[i + 1].y : 0.0f);
          CGFloat lineHeight = ceil(useRealHeight ? abs(neighborLineY - lineOrigin.y) : ascent + descent + leading);
  
          _lineFrames[i].origin = lineOrigin;
          _lineFrames[i].size = CGSizeMake(lineWidth, lineHeight);
  
          for (int ic = lineStartIndex; ic &lt; lineEndIndex; ic++) {
  
              CGFloat startOffset = CTLineGetOffsetForStringIndex(line, ic, NULL);
              _characterFrames[ic].origin = CGPointMake(startOffset, lineOrigin.y);
          }
      }
  }
  
  
  #pragma mark - Rendering Text:
  
  -(void)renderInContext:(CGContextRef)context contextSize:(CGSize)size{
  
      CGContextSaveGState(context);
  
      // Draw Core Text attributes string:
      CGContextSetTextMatrix(context, CGAffineTransformIdentity);
      CGContextTranslateCTM(context, 0, CGRectGetHeight(_frameRect));
      CGContextScaleCTM(context, 1.0, -1.0);
  
      CTFrameDraw(_ctFrame, context);
  
      // Draw line and letter frames:
      CGContextSetStrokeColorWithColor(context, [UIColor colorWithRed:0.0 green:0.0 blue:1.0 alpha:0.5].CGColor);
      CGContextSetLineWidth(context, 1.0);
  
      CGContextBeginPath(context);
      CGContextAddRects(context, _lineFrames, _lineCount);
      CGContextClosePath(context);
      CGContextStrokePath(context);
  
      CGContextSetStrokeColorWithColor(context, [UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:0.5].CGColor);
      CGContextBeginPath(context);
      CGContextAddRects(context, _characterFrames, _attributedString.string.length);
      CGContextClosePath(context);
      CGContextStrokePath(context);
  
      CGContextRestoreGState(context);
  
  }
  </code></pre>