2011-11-07 9 views
2

iOSプラットフォーム上でCore Graphicsを使用して回転したテキストを描くことを試みています。回転していないときはテキストはうまく描画されますが、レンダリングシステムは回転したテキストのピクセルをロックしようとします。iOS上で回転したテキストを描画するとジャンプ文字が作成される

例:コアグラフィックスコンテキストを少し回転させて(2度のように)テキストを描画すると、コアグラフィックスが文字をピクセル(フォントヒント)にロックするため、個々の文字が上下にジャンプするように見えます。 。私はピクセルグリッドにロックされていなければテキストがぼやけるかもしれないが、それは受け入れられる。ジャンプする文字はありません。だから、どのように私は垂直フォントのヒントを無効にすることができますか?水平のヒントは問題ありませんが、すべてオフにすることもOKです。カスタムUIViewのため


コード:(ない正確 "エラー" に案内する挿入このコードも同様、赤線)

- (void)drawRect:(CGRect)rect { 
    CGContextRef context = UIGraphicsGetCurrentContext(); 
    [self.backgroundColor setFill]; 
    CGContextFillRect(context, rect); 
    CGContextSaveGState(context); 
    // rotate context 
    CGContextTranslateCTM(context, self.bounds.size.width/2.0, self.bounds.size.width/2.0); 
    CGContextRotateCTM(context, 2.0 * M_PI/180.0); 
    CGContextTranslateCTM(context, -self.bounds.size.width/2.0, -self.bounds.size.width/2.0); 

    [[UIColor blackColor] setFill]; 
    [self.title drawInRect:[self bounds] withFont:[UIFont systemFontOfSize:15.0]]; 
    CGContextRestoreGState(context); 
} 

結果:

Image of the jumping characters

+0

そのコードから実際の画像、またはその画像の実際のコードを表示しない理由はありますか? –

+0

約100行のコードを貼り付けたくありません。テキストレンダリング部分は上記とまったく同じです(ただし、私の例では空のXcodeプロジェクトへの単純なcnpのためにテキストを黒で描いていますが、デフォルトの背景は白です)。ヒント "エラー"は上のサンプルコードで発生しますそれはシステムに内在する "エラー"(レンダリングされたテキストをぼかさないために実際にはエラーではありませんが、整列していて、OKのテキストをぼかす場合) – Dunkelstern

+0

私はその効果を見ている間に、 m 'は傾けられているだけではありません。 Photoshopではなくコードで赤い線を描くとどうなるでしょうか? (私は文字と行の一致を推測しています。) –

答えて

1

私が見つけた唯一の解決策は、コアテキストを使用してグリフの実際のベジェパスを取得し、それらを描画し、垂直方向のヒントを回避することです。次のコードの抜粋はかなり長いです:

CGRect textRect = CGRectMake(0.0, 0.0, 300.0, 190.0); 
CGContextRef context = UIGraphicsGetCurrentContext(); 

// Flip coordinate system vertically. 
CGContextSaveGState(context); 
CGFloat rectHeight = textRect.size.height; 
CGContextTranslateCTM(context, 0.0, rectHeight); 
CGContextScaleCTM(context, 1.0f, -1.0f); 

// Positive degrees because of flip. 
CGAffineTransform rotationTransform = CGAffineTransformMakeRotation(2.0 * M_PI/180.0); 
CGContextConcatCTM(context, rotationTransform); 


CGFloat pointSize = 15.0; 
CTFontRef font = CTFontCreateUIFontForLanguage(kCTFontSystemFontType, 
               pointSize, 
               NULL); 

CGContextSetTextMatrix(context, CGAffineTransformIdentity); 

NSDictionary *initialAttributes = (
            @{ 
            (NSString *)kCTFontAttributeName   : (__bridge id)font, 
            (NSString *)kCTForegroundColorAttributeName : (__bridge id)[UIColor blackColor].CGColor 
            } 
            ); 

NSMutableAttributedString *attributedString = 
[[NSMutableAttributedString alloc] initWithString:[self string] 
             attributes:initialAttributes]; 


// 
// For typesetting a frame, we should create a paragraph style. 
// Includes fix for CTFramesetter’s wrong line spacing behavior. 
// See Technical Q&A QA1698: “How do I work-around an issue where some lines 
// in my Core Text output have extra line spacing?” 
// 

// Center alignment looks best when filling an ellipse. 
CTTextAlignment alignment = kCTLeftTextAlignment; 
CTLineBreakMode lineBreakMode = kCTLineBreakByWordWrapping; 

// This is the leading in the historical sense, which is added to the point 
// size but does not include it like the line height does. 
CGFloat leading = 2.0; 

// Still, for the fix we do need the line height. 
CGFloat lineHeight = pointSize + leading; 

CTParagraphStyleSetting paragraphStyleSettings[] = 
{ 
    { 
     kCTParagraphStyleSpecifierAlignment, 
     sizeof(alignment), 
     &alignment 
    }, 

    { 
     kCTParagraphStyleSpecifierLineBreakMode, 
     sizeof(lineBreakMode), 
     &lineBreakMode 
    }, 

    // These two specifiers fix the line spacing when set to line height. 
    { 
     kCTParagraphStyleSpecifierMinimumLineHeight, 
     sizeof(lineHeight), 
     &lineHeight 
    }, 

    { 
     kCTParagraphStyleSpecifierMaximumLineHeight, 
     sizeof(lineHeight), 
     &lineHeight 
    } 

    // Very important: Do not set kCTParagraphStyleSpecifierLineSpacing too, 
    // or it will be added again! 
}; 

CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(
                  paragraphStyleSettings, 
                  sizeof(paragraphStyleSettings)/sizeof(paragraphStyleSettings[0]) 
                  ); 

// Apply paragraph style to entire string. This cannot be done when the 
// string is empty, by the way, because attributes can only be applied to 
// existing characters. 
NSRange stringRange = NSMakeRange(0, [attributedString length]); 

[attributedString addAttribute:(NSString *)kCTParagraphStyleAttributeName 
         value:(__bridge id)(paragraphStyle) 
         range:stringRange]; 


// Create bezier path to contain our text. 
CGMutablePathRef path = CGPathCreateMutable(); 
CGPathAddRect(path, NULL, textRect); 

CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)(attributedString)); 

// Range with length 0 indicates that we want to typeset until we run out of 
// text or space. 
CTFrameRef frame = CTFramesetterCreateFrame(
              framesetter, 
              CFRangeMake(0, 0), 
              path, 
              NULL 
              ); 


CFArrayRef lines = CTFrameGetLines(frame); 
CFIndex lineCount = CFArrayGetCount(lines); 
CFRange range = CFRangeMake(0, 0); 
CGPoint lineOrigins[lineCount]; 
CTFrameGetLineOrigins(frame, range, lineOrigins); 

for (NSUInteger lineIndex = 0; lineIndex < lineCount; ++lineIndex) 
{ 
    CTLineRef line = CFArrayGetValueAtIndex(lines, lineIndex); 
    CGPoint lineOrigin = lineOrigins[lineIndex]; 
    CFArrayRef runs = CTLineGetGlyphRuns(line); 
    CFIndex runCount = CFArrayGetCount(runs); 

    for (NSUInteger runIndex = 0; runIndex < runCount; ++runIndex) 
    { 
     CTRunRef run = CFArrayGetValueAtIndex(runs, runIndex); 
     CFIndex glyphCount = CTRunGetGlyphCount(run); 

     CGGlyph glyphBuffer[glyphCount]; 
     CTRunGetGlyphs(run, range, glyphBuffer); 

     CGPoint positionsBuffer[glyphCount]; 
     CTRunGetPositions(run, range, positionsBuffer); 

     for (NSUInteger glyphIndex = 0; glyphIndex < glyphCount; ++glyphIndex) 
     { 
      CGGlyph glyph = glyphBuffer[glyphIndex]; 
      CGPoint position = positionsBuffer[glyphIndex]; 
      CGAffineTransform positionTransform = CGAffineTransformMakeTranslation(lineOrigin.x + position.x, 
                        lineOrigin.y + position.y); 
      CGPathRef glyphPath = CTFontCreatePathForGlyph(font, glyph, &positionTransform); 
      CGContextAddPath(context, glyphPath); 
     } 
    } 
} 

CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor); 
CGContextFillPath(context); 


CFRelease(font); 
CFRelease(framesetter); 

// Use specialized release function when it exists. 
CGPathRelease(path); 

CGContextRestoreGState(context); 
関連する問題