2011-11-07 3 views
2

iOS 플랫폼에서 Core Graphics로 약간 회전 된 텍스트를 그리려합니다. 텍스트는 회전하지 않을 때 잘 렌더링되지만 렌더링 시스템은 회전 된 텍스트의 픽셀을 고정하려고합니다.iOS에서 회전 된 텍스트를 그리면 점핑 문자가 생성됩니다.

예 : Core Graphics 컨텍스트를 약간의 양 (예 : 2도)으로 회전시킨 다음 텍스트를 그리면 Core Graphics가 문자를 픽셀로 잠급니다 (글꼴 힌팅) . 픽셀 격자에 고정되지 않으면 텍스트가 흐려질 수 있지만 수용 할 수 있습니다. 점프 문자가 아닙니다. 그렇다면 세로 글꼴 힌트를 어떻게 비활성화 할 수 있습니까? 수평을 암시하는 것은 괜찮을 것이다. 그러나 그것을 완전히 없애는 것은 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를 사용하는 예제에서는 검은 색으로 텍스트를 그립니다) 힌트 "error"는 맨 위에있는 예제 코드에서 발생합니다 너무 시스템의 내재 된 "오류"(실제로 렌더링 된 텍스트를 흐리게하지 않기 때문에 오류가 아니지만, 나는 그것을 정렬하고 그것이 괜찮은 텍스트를 흐리게한다면) – 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); 
관련 문제