7

画像に文字列を描画しています。イメージのサイズは動的です。つまり、イメージは文字列を表示するのに必要な大きさです。それを達成するために、Graphics.DrawString() でテキストをレンダリングする前に、Graphics.MeasureString() でサイズを測定しています。

回転が始まるまでは問題ありません。これまで、文字列をビットマップに描画し、結果として得られるビットマップ全体を回転させていました。

問題は、カラー パレットが非常に限られており、混色がないことです。そのため、テキスト ビットマップを回転させて InterpolationMode.NearestNeighbor を使用することによってのみ可能になる、あらゆる種類のアンチエイリアシングを回避する必要があります。これにより、不要な色がレンダリングされないようになりますが、結果は実際には非常に醜いものになります (ユーザーの観点から)。

私の考え: Graphics.RotateTransform() でテキストを回転させ、クリッピングを回避することで、テキストをビットマップに描画できるはずですよね?

最初に描画する画像のサイズを定義する必要があり、このサイズは回転によって大きくなるため、これを行う方法がわかりません。

どんな助けでも大歓迎です!

4

2 に答える 2

4

このコードはあなたにアイデアを与えます:

    public void DrawText(bool debug, Graphics g, string text, Font font, Brush brush, StringFormat format, float x, float y, float width, float height, float rotation)
    {
        float centerX = width / 2;
        float centerY = height / 2;

        if (debug)
        {
            g.FillEllipse(Brushes.Green, centerX - 5f, centerY - 5f, 10f, 10f);
        }

        GraphicsState gs = g.Save();

        Matrix mat = new Matrix();
        mat.RotateAt(rotation, new PointF(centerX, centerY), MatrixOrder.Append);

        g.Transform = mat;

        SizeF szf = g.MeasureString(text, font);

        g.DrawString(text, font, brush, (width / 2) - (szf.Width / 2), (height / 2) - (szf.Height / 2), format);

        g.Restore(gs);
    }

GraphicsPath を使用して、回転したテキストの境界を測定する方法を次に示します。ロジックは単純で、GraphicsPath はテキストをポイント リストに変換してから、境界の四角形を計算します。

    public RectangleF GetRotatedTextBounds(string text, Font font, StringFormat format, float rotation, float dpiY)
    {
        GraphicsPath gp = new GraphicsPath();

        float emSize = dpiY * font.Size / 72;

        gp.AddString(text, font.FontFamily, (int)font.Style, emSize, new PointF(0, 0), format);

        Matrix mat = new Matrix();
        mat.Rotate(rotation, MatrixOrder.Append);

        gp.Transform(mat);

        return gp.GetBounds();
    }

テストコード:

        float fontSize = 25f;
        float rotation = 30f;

        RectangleF txBounds = GetRotatedTextBounds("TEST TEXT", new Font("Verdana", fontSize, System.Drawing.FontStyle.Bold), StringFormat.GenericDefault, rotation, 96f);

        float inflateValue = 10 * (fontSize / 100f);

        txBounds.Inflate(inflateValue, inflateValue);

        Bitmap bmp = new System.Drawing.Bitmap((int)txBounds.Width, (int)txBounds.Height);
        using (Graphics gr = Graphics.FromImage(bmp))
        {
            gr.Clear(Color.White);
            DrawText(true, gr, "TEST TEXT", new Font("Verdana", fontSize, System.Drawing.FontStyle.Bold), Brushes.Red, new StringFormat(System.Drawing.StringFormatFlags.DisplayFormatControl), 0, 0, txBounds.Width, txBounds.Height, rotation);
        }
于 2011-04-04T22:39:07.703 に答える
2

実行可能な MVC アクションとしての私のソリューション:

public class ImageController : Controller
{

    public ActionResult Test()
    {

        var text = DateTime.Now.ToString();
        var font = new Font("Arial", 20, FontStyle.Regular);
        var angle = 233;

        SizeF textSize = GetEvenTextImageSize(text, font);

        SizeF imageSize;

        if (angle == 0)
            imageSize = textSize;
        else
            imageSize = GetRotatedTextImageSize(textSize, angle);

        using (var canvas = new Bitmap((int)imageSize.Width, (int)imageSize.Height))
        {

            using(var graphics = Graphics.FromImage(canvas))
            {

                graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
                graphics.SmoothingMode = SmoothingMode.HighQuality;
                graphics.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;

                SizeF textContainerSize = graphics.VisibleClipBounds.Size;
                graphics.TranslateTransform(textContainerSize.Width / 2, textContainerSize.Height / 2);
                graphics.RotateTransform(angle);

                graphics.DrawString(text, font, Brushes.Black, -(textSize.Width / 2), -(textSize.Height / 2));

            }

            var stream = new MemoryStream();
            canvas.Save(stream, ImageFormat.Png);
            stream.Seek(0, SeekOrigin.Begin);
            return new FileStreamResult(stream, "image/png");

        }

    }

    private static SizeF GetEvenTextImageSize(string text, Font font)
    {
        using (var image = new Bitmap(1, 1, PixelFormat.Format32bppArgb))
        {
            using (Graphics graphics = Graphics.FromImage(image))
            {
                return graphics.MeasureString(text, font);
            }
        }
    }

    private static SizeF GetRotatedTextImageSize(SizeF fontSize, int angle)
    {

        // Source: http://www.codeproject.com/KB/graphics/rotateimage.aspx

        double theta = angle * Math.PI / 180.0;

        while (theta < 0.0)
            theta += 2 * Math.PI;

        double adjacentTop, oppositeTop;
        double adjacentBottom, oppositeBottom;

        if ((theta >= 0.0 && theta < Math.PI / 2.0) || (theta >= Math.PI && theta < (Math.PI + (Math.PI / 2.0))))
        {
            adjacentTop = Math.Abs(Math.Cos(theta)) * fontSize.Width;
            oppositeTop = Math.Abs(Math.Sin(theta)) * fontSize.Width;
            adjacentBottom = Math.Abs(Math.Cos(theta)) * fontSize.Height;
            oppositeBottom = Math.Abs(Math.Sin(theta)) * fontSize.Height;
        }
        else
        {
            adjacentTop = Math.Abs(Math.Sin(theta)) * fontSize.Height;
            oppositeTop = Math.Abs(Math.Cos(theta)) * fontSize.Height;
            adjacentBottom = Math.Abs(Math.Sin(theta)) * fontSize.Width;
            oppositeBottom = Math.Abs(Math.Cos(theta)) * fontSize.Width;
        }

        int nWidth = (int)Math.Ceiling(adjacentTop + oppositeBottom);
        int nHeight = (int)Math.Ceiling(adjacentBottom + oppositeTop);

        return new SizeF(nWidth, nHeight);

    }

}
于 2011-04-05T10:41:47.153 に答える