2010-05-10 75 views
4

我目前動態創建位圖和使用圖形從位圖對象繪製一個字符串就可以了,像這樣:如何將曲線文本渲染到位圖中?

System.Drawing.Graphics graph = System.Drawing.Graphics.FromImage(bmp); 
graph.DrawString(text, font, brush, new System.Drawing.Point(0, 0)); 

此方法返回跨連續寫入字符串矩形位圖從左至右。 我想也能夠以彩虹的形狀繪製字符串。 我該怎麼做?

+1

這些答案有幫助嗎?我剛剛遇到了這個問題,可能很快就會編寫類似的代碼,但沒有一個答案被接受 - 我想知道他們是否存在問題,以及您最終做了什麼。 – 2013-05-13 11:48:54

回答

1

我認爲,唯一的辦法就是單獨呈現每個字符,並使用

Graphics.RotateTransform 

旋轉文本。你需要自己計算旋轉角度和渲染偏移量。您可以使用

Graphics.MeasureCharacterRanges 

來獲取每個字符的大小。

+0

我個人很喜歡這個解決方案! +1 :)感謝您的建議。 – 2014-08-17 12:27:25

0

不幸的是,在GDI +中,沒有辦法將字符串附加到路徑上(這是您要查找的內容)。

所以唯一的方法就是「手工」。這意味着將字符串分解爲字符並根據自己的路徑計算放置它們。

除非你想把lot的工作放到這裏,你應該嘗試找到一個庫(可能是完整的GDI +替代品)來做到這一點或放棄你的彩虹。

使用WPF,你可以在路徑上呈現文本(see link for a howto

16

最近,我有這個問題(我是呈現文本打印到光盤),所以這裏是我的解決方案:

private void DrawCurvedText(Graphics graphics, string text, Point centre, float distanceFromCentreToBaseOfText, float radiansToTextCentre, Font font, Brush brush) 
{ 
    // Circumference for use later 
    var circleCircumference = (float)(Math.PI * 2 * distanceFromCentreToBaseOfText); 

    // Get the width of each character 
    var characterWidths = GetCharacterWidths(graphics, text, font).ToArray(); 

    // The overall height of the string 
    var characterHeight = graphics.MeasureString(text, font).Height; 

    var textLength = characterWidths.Sum(); 

    // The string length above is the arc length we'll use for rendering the string. Work out the starting angle required to 
    // centre the text across the radiansToTextCentre. 
    float fractionOfCircumference = textLength/circleCircumference; 

    float currentCharacterRadians = radiansToTextCentre + (float)(Math.PI * fractionOfCircumference); 

    for (int characterIndex = 0; characterIndex < text.Length; characterIndex++) 
    { 
     char @char = text[characterIndex]; 

     // Polar to cartesian 
     float x = (float)(distanceFromCentreToBaseOfText * Math.Sin(currentCharacterRadians)); 
     float y = -(float)(distanceFromCentreToBaseOfText * Math.Cos(currentCharacterRadians)); 

     using (GraphicsPath characterPath = new GraphicsPath()) 
     { 
      characterPath.AddString(@char.ToString(), font.FontFamily, (int)font.Style, font.Size, Point.Empty, 
            StringFormat.GenericTypographic); 

      var pathBounds = characterPath.GetBounds(); 

      // Transformation matrix to move the character to the correct location. 
      // Note that all actions on the Matrix class are prepended, so we apply them in reverse. 
      var transform = new Matrix(); 

      // Translate to the final position 
      transform.Translate(centre.X + x, centre.Y + y); 

      // Rotate the character 
      var rotationAngleDegrees = currentCharacterRadians * 180F/(float)Math.PI - 180F; 
      transform.Rotate(rotationAngleDegrees); 

      // Translate the character so the centre of its base is over the origin 
      transform.Translate(-pathBounds.Width/2F, -characterHeight); 

      characterPath.Transform(transform); 

      // Draw the character 
      graphics.FillPath(brush, characterPath); 
     } 

     if (characterIndex != text.Length - 1) 
     { 
      // Move "currentCharacterRadians" on to the next character 
      var distanceToNextChar = (characterWidths[characterIndex] + characterWidths[characterIndex + 1])/2F; 
      float charFractionOfCircumference = distanceToNextChar/circleCircumference; 
      currentCharacterRadians -= charFractionOfCircumference * (float)(2F * Math.PI); 
     } 
    } 
} 

private IEnumerable<float> GetCharacterWidths(Graphics graphics, string text, Font font) 
{ 
    // The length of a space. Necessary because a space measured using StringFormat.GenericTypographic has no width. 
    // We can't use StringFormat.GenericDefault for the characters themselves, as it adds unwanted spacing. 
    var spaceLength = graphics.MeasureString(" ", font, Point.Empty, StringFormat.GenericDefault).Width; 

    return text.Select(c => c == ' ' ? spaceLength : graphics.MeasureString(c.ToString(), font, Point.Empty, StringFormat.GenericTypographic).Width); 
} 

screenshot of curved text in program output

+1

在互聯網上所有無數帖子中,這是我發現的一個相當簡單的做法的唯一例子。我正在使用貝塞爾曲線來實現它。謝謝@Simon。 – Echilon 2013-09-10 16:06:12

+0

一個輕微的觀察與此是文本逆時針。是否有可能使其順時針旋轉? – Echilon 2013-09-10 16:15:07

+3

嗨@Echilon,你可以通過改變幾行來反轉曲線:計算'rotationAngleDegrees'時刪除'-180F',並且在分配'currentCharacterRadians'的兩個地方,將減法改爲加法,反之亦然! – 2013-09-11 04:45:10