富文本转路径

+ (UIBezierPath *)attributedString2BezierPath:(NSAttributedString *)attributedString inBounds:(CGSize)bounds {
    NSString *clearText = attributedString.string;
    NSCharacterSet *ignoredCharsSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
    if ([clearText stringByTrimmingCharactersInSet:ignoredCharsSet].length == 0) {
        return [UIBezierPath bezierPath];
    }
    CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)attributedString);
    CFRange textRange = CFRangeMake(0, attributedString.length);
    CGSize frameSize = CTFramesetterSuggestFrameSizeWithConstraints(frameSetter, textRange, NULL, bounds, NULL);
    CGPathRef framePath = [UIBezierPath bezierPathWithRect:CGRectMake(0.0, 0.0, frameSize.width, frameSize.height)].CGPath;
    CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, textRange, framePath, NULL);
    CGMutablePathRef path = CGPathCreateMutable();
    CFArrayRef lines = CTFrameGetLines(frame);
    CGFloat linesShift = 0.0;
    CFIndex lineCount = CFArrayGetCount(lines);
    CGPoint origins[lineCount];
    CTFrameGetLineOrigins(frame, CFRangeMake(0, lineCount), origins);
    for (CFIndex index = 0; index < lineCount; index++) {
        CTLineRef line = CFArrayGetValueAtIndex(lines, index);
        CGPoint lineOrigin = origins[index];
        CGFloat ascent, descent, leading;
        CTLineGetTypographicBounds(line, &ascent, &descent, &leading);
        CFArrayRef lineRuns = CTLineGetGlyphRuns(line);
        CGFloat effectiveDescent = 0.0;
        CGFloat effectiveAscent = 0.0;
        CFIndex lineRunCount = CFArrayGetCount(lineRuns);
        for (CFIndex lineRunIndex = 0; lineRunIndex < lineRunCount; lineRunIndex++) {
            CTRunRef lineRun = CFArrayGetValueAtIndex(lineRuns, lineRunIndex);
            CFIndex glyphsCount = CTRunGetGlyphCount(lineRun);
            if (glyphsCount == 0) {
                continue;
            }
            CGFloat rt_ascent = 0.0;
            CGFloat rt_descent = 0.0;
            CGFloat rt_leading = 0.0;
            CTRunGetTypographicBounds(lineRun, CFRangeMake(0, glyphsCount), &rt_ascent, &rt_descent, &rt_leading);
            effectiveAscent = MAX(effectiveAscent, ABS(rt_ascent));
            effectiveDescent = MAX(effectiveDescent, ABS(rt_descent));
        }
        for (CFIndex lineRunIndex = 0; lineRunIndex < lineRunCount; lineRunIndex++) {
            CTRunRef lineRun = CFArrayGetValueAtIndex(lineRuns, lineRunIndex);
            CFIndex glyphsCount = CTRunGetGlyphCount(lineRun);
            if (glyphsCount == 0) {
                continue;
            }
            NSDictionary *attributes = (__bridge NSDictionary *)CTRunGetAttributes(lineRun);
            UIFont *font = attributes[NSFontAttributeName] ?: [UIFont systemFontOfSize:UIFont.systemFontSize];
            const CGGlyph *glyphPtr = CTRunGetGlyphsPtr(lineRun);
            const CGPoint *positionPtr = CTRunGetPositionsPtr(lineRun);
            for (CFIndex glyphIndex = 0; glyphIndex < glyphsCount; glyphIndex++) {
                CGGlyph glyph = glyphPtr[glyphIndex];
                CGPoint gPosition = positionPtr[glyphIndex];
                CGAffineTransform T = CGAffineTransformMakeScale(1, 1);
                CTFontRef ctFont = (__bridge CTFontRef)(font);
                CGPathRef glyphPath = CTFontCreatePathForGlyph(ctFont, glyph, &T);
                if (glyphPath != NULL) {
                    CGRect pathBounds = CGPathGetBoundingBox(glyphPath);
                    CGAffineTransform pathOffset = CGAffineTransformMakeTranslation(-pathBounds.origin.x, -pathBounds.origin.y);
                    CGPathRef glyphPathRel = CGPathCreateCopyByTransformingPath(glyphPath, &pathOffset);
                    if (glyphPathRel == NULL) {
                        glyphPathRel = glyphPath;
                    }
                    CGPoint position = CGPointMake(lineOrigin.x + gPosition.x + pathBounds.origin.x, lineOrigin.y + gPosition.y + pathBounds.origin.y);
                    CGPoint offset = CGPointMake(position.x, position.y + (ascent - effectiveAscent) + linesShift);
                    CGAffineTransform PT = CGAffineTransformMakeTranslation(offset.x, offset.y);
                    CGPathAddPath(path, &PT, glyphPathRel);
                    if (glyphPathRel != glyphPath) {
                        CGPathRelease(glyphPathRel);
                    }
                    CFRelease(glyphPath);
                }
            }
        }
        linesShift += (ascent + descent) - (effectiveAscent + effectiveDescent);
    }
    CGAffineTransform matrix = CGAffineTransformMakeScale(1, -1);
    matrix = CGAffineTransformTranslate(matrix, 0.0, -frameSize.height);
    CGPathRef finalPath = CGPathCreateMutableCopyByTransformingPath(path, &matrix);
    CFRelease(frameSetter);
    CFRelease(frame);
    CFRelease(path);
    UIBezierPath *resultPath = [UIBezierPath bezierPathWithCGPath:finalPath];
    CGPathRelease(finalPath);
    return resultPath;
}

 

posted @ 2023-04-12 14:48  雨筱逸悠  阅读(17)  评论(0编辑  收藏  举报