带有重音字符的绘图文字(即法文文本)

时间:2012-06-22 04:39:10

标签: ios nsstring drawing core-graphics

我想在图像上绘制文字。我已尝试使用CGContextShowTextAtPointNSString drawAtPoint,但它们都无法显示带有重音字符的文字(即文本是否为法语)。基本上我希望能够显示unicode字符。任何提示/解决方案?

我使用Core-Graphics(UIImage类别方法)的解决方案:

- (UIImage *)overlayText:(NSString *)overlayText withFontName:(NSString *)fontName andFontSize:(CGFloat)fontSize {
    // Refererence:
    // http://iphonesdksnippets.com/post/2009/05/05/Add-text-to-image-%28UIImage%29.aspx

    int w = self.size.width;
    int h = self.size.height; 

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 4 * w, colorSpace, kCGImageAlphaPremultipliedFirst);

    CGContextDrawImage(context, CGRectMake(0, 0, w, h), self.CGImage);
    CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1);

    char *charText = (char *)[overlayText cStringUsingEncoding:NSASCIIStringEncoding];
    char *charFontName = (char *)[fontName cStringUsingEncoding:NSASCIIStringEncoding];

    CGContextSelectFont(context, charFontName, fontSize, kCGEncodingMacRoman);
    CGContextSetTextDrawingMode(context, kCGTextFill);
    CGContextSetRGBFillColor(context, 255, 255, 255, 1);

    // rotate text
    // CGContextSetTextMatrix(context, CGAffineTransformMakeRotation(-M_PI / 4));
    CGFloat textWidth = [overlayText calculateCGTextWidthWithFont:charFontName size:fontSize];
    CGFloat xTextPosition = MAX(10.0, w - textWidth - 10.0); // 10.0 inset

    CGFloat yTextPosition = 10.0;
    CGContextShowTextAtPoint(context, xTextPosition, yTextPosition, charText, strlen(charText));

    CGImageRef imageMasked = CGBitmapContextCreateImage(context);
    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);

    return [UIImage imageWithCGImage:imageMasked];    
}

使用NSStringUIImage类别方法)的解决方案:

- (UIImage *)overlayText:(NSString *)overlayText withFontName:(NSString *)fontName andFontSize:(CGFloat)fontSize {
    UIFont *font = [UIFont fontWithName:fontName size:fontSize];

    char *charFontName = (char *)[fontName cStringUsingEncoding:NSASCIIStringEncoding];
    CGFloat textWidth = [overlayText calculateCGTextWidthWithFont:charFontName size:fontSize];
    CGFloat xTextPosition = MAX(10.0, self.size.width - textWidth - 10.0); // 10.0 margin/inset
    CGFloat yTextPosition = self.size.height - fontSize - 10.0;   // 10.0 margin/inset

    UIGraphicsBeginImageContext(self.size);
    [self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)];

    [[UIColor whiteColor] set];    
    [overlayText drawAtPoint:CGPointMake(xTextPosition, yTextPosition) withFont:font];

    UIImage *overlayTextImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return overlayTextImage;
}

我的核心文本解决方案(UIImage类别方法):

- (UIImage *)overlayText:(NSString *)overlayText withFontName:(NSString *)fontName andFontSize:(CGFloat)fontSize {
    char *charFontName = (char *)[fontName cStringUsingEncoding:NSASCIIStringEncoding];
    CGFloat textWidth = [overlayText calculateCGTextWidthWithFont:charFontName size:fontSize];
    CGFloat xTextPosition = 10.0; // MAX(10.0, self.size.width - textWidth - 10.0); // 10.0 margin/inset
    CGFloat yTextPosition = self.size.height - fontSize - 10.0;   // 10.0 margin/inset

    UIGraphicsBeginImageContext(self.size);
    [self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)];

    // flip the coordinate system
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetTextMatrix(context, CGAffineTransformIdentity);
    CGContextTranslateCTM(context, 0, self.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);

    // create an attributed string
    CFMutableAttributedStringRef attributedOverlayText = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);

    if (overlayText != nil)
        CFAttributedStringReplaceString(attributedOverlayText, CFRangeMake(0, 0), (CFStringRef)overlayText);

    CFAttributedStringSetAttribute(attributedOverlayText, CFRangeMake(0, CFAttributedStringGetLength(attributedOverlayText)), kCTForegroundColorAttributeName, [[UIColor whiteColor] CGColor]);

    CTFontRef ctFont = CTFontCreateWithName((CFStringRef)fontName, fontSize, NULL);
    CFAttributedStringSetAttribute(attributedOverlayText, CFRangeMake(0, CFAttributedStringGetLength(attributedOverlayText)), kCTFontAttributeName, ctFont);
    CFRelease(ctFont);

    // draw attributed string using CTLineDraw
    CTLineRef line = CTLineCreateWithAttributedString((CFAttributedStringRef)attributedOverlayText);
    CGContextSetTextPosition(context, xTextPosition, yTextPosition);
    CTLineDraw(line, context);

    UIImage *overlayTextImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return overlayTextImage;
}

1 个答案:

答案 0 :(得分:0)

我对上述解决方案的问题是,我基本上没有为文本获得正确的“宽度”。

这是适用于我的解决方案(使用Core Text):

- (UIImage *)overlayText:(NSString *)overlayText withFontName:(NSString *)fontName andFontSize:(CGFloat)fontSize {
    // Develope's Note:
    // Problem with implementing a solution using CG is that it doesn't support unicode character drawing i.e French    

    // Begin new image context
    UIGraphicsBeginImageContext(self.size);

    // Draw image
    [self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)];

    // Flip the coordinate system
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetTextMatrix(context, CGAffineTransformIdentity);
    CGContextTranslateCTM(context, 0, self.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);

    // Create an attributed string
    CFMutableAttributedStringRef attributedOverlayText = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);

    if (overlayText != nil)
        CFAttributedStringReplaceString(attributedOverlayText, CFRangeMake(0, 0), (__bridge CFStringRef)overlayText);

    // Set text color
    CFAttributedStringSetAttribute(attributedOverlayText, 
                                   CFRangeMake(0, CFAttributedStringGetLength(attributedOverlayText)), 
                                   kCTForegroundColorAttributeName, 
                                   [[UIColor whiteColor] CGColor]);

    // Set text font
    CTFontRef ctFont = CTFontCreateWithName((__bridge CFStringRef)fontName, fontSize, NULL);
    CFAttributedStringSetAttribute(attributedOverlayText, 
                                   CFRangeMake(0, CFAttributedStringGetLength(attributedOverlayText)), 
                                   kCTFontAttributeName, 
                                   ctFont);
    CFRelease(ctFont);

    // Set text alignment (paragraph style)
    CTTextAlignment alignment = kCTRightTextAlignment;
    CTParagraphStyleSetting settings[] = {kCTParagraphStyleSpecifierAlignment, sizeof(alignment), &alignment};
    CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(settings, sizeof(settings) / sizeof(settings[0]));
    CFAttributedStringSetAttribute(attributedOverlayText, 
                                   CFRangeMake(0, CFAttributedStringGetLength(attributedOverlayText)), 
                                   kCTParagraphStyleAttributeName, 
                                   paragraphStyle);    
    CFRelease(paragraphStyle);

    // Create framesetter with the attributed text
    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attributedOverlayText);
    CFRange stringRange = CFRangeMake(0, CFAttributedStringGetLength(attributedOverlayText));
    CGSize fitRange = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, 
                                                                   CFRangeMake(0, 0), 
                                                                   NULL, 
                                                                   CGSizeMake(self.size.width - (2 * 10.0), CGFLOAT_MAX), 
                                                                   NULL);

    // Developer's Note:
    // We can't use fontSize for the framesetter's height.
    // We can't use fitRange.height in the bounding rectangle, because then we won't get the correct text alignment
    // Calculate the width (and correspondingly the xTextPosition)
    CGRect boundingRect = CGRectMake(10.0, 
                                     10.0, 
                                     self.size.width - (2 * 10.0), 
                                     fitRange.height);

    CGMutablePathRef boundingPath = CGPathCreateMutable();
    CGPathAddRect(boundingPath, NULL, boundingRect);  

    // Draw attributed text using CTFrameDraw
    CTFrameRef frame = CTFramesetterCreateFrame(framesetter, stringRange, boundingPath, NULL);
    CTFrameDraw(frame, context);
    CFRelease(framesetter);

    // Draw boundary (debugging purposes only)
    if (NO) {
        // Inner boundary
        CGContextSetStrokeColorWithColor(context, [UIColor yellowColor].CGColor);
        CGContextSetLineWidth(context, 2.0);
        CGContextStrokeRect(context, CGPathGetBoundingBox(boundingPath));

        // Outer boundary
        CGMutablePathRef controlBoundaryPath = CGPathCreateMutable();
        CGPathAddRect(controlBoundaryPath, NULL, CGRectMake(0, 0, self.size.width, self.size.height));

        CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
        CGContextSetLineWidth(context, 2.0);
        CGContextStrokeRect(context, CGPathGetBoundingBox(controlBoundaryPath));

        CFRelease(controlBoundaryPath);
    }

    // Draw attributed string using CTLineDraw 
    // (Doesn't work if we want to right align the text)
    //    CTLineRef line = CTLineCreateWithAttributedString((CFAttributedStringRef)attributedOverlayText);
    //    CGContextSetTextPosition(context, xTextPosition, yTextPosition);
    //    CTLineDraw(line, context);

    UIImage *overlayTextImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return overlayTextImage;
}

希望这有助于某人。