Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to apply Graphics scale and translate to the TextRenderer

I'm using scaling and transforming my graphics object when painting a custom control, in order to apply zooming and scrolling. I use the following:

            Matrix mx = new Matrix();
            mx.Scale(mZoomFactor, mZoomFactor);
            mx.Translate(-clip.X + mGraphicsOffsetx, -clip.Y + mGraphicsOffsety);

            e.Graphics.Clip = new Region(this.Bounds);
            e.Graphics.Transform = mx;

Then when I paint my strings using:

Graphics g = ...
g.DrawString(...)

The scalling and transforming is correctly applied to the strings, they are zoomed out and in and so on.

However if I use the following to paint my strings:

TextRenderer.DrawText(...)

The text is not correctly scaled and transformed.

Do you know how to apply this concepts to the TextRenderer?

like image 284
Daniel Peñalba Avatar asked Jan 13 '12 12:01

Daniel Peñalba


1 Answers

The comments above are accurate--TextRenderer.DrawText, being GDI, has limited support for coordinate transformation given its resolution dependence. As you've noticed, coordinate translation is supported but scaling is not (and neither is coordinate rotation).

The solution we've used (and the only resource I've been able to find on the internet) is to manually scale the Font and Rectangle objects to reflect the scaling applied by Matrix.Scale(float, float) in conjunction with Graphics.Transform:

    private Font GetScaledFont(Graphics g, Font f, float scale)
    {
        return new Font(f.FontFamily,
                        f.SizeInPoints * scale,
                        f.Style,
                        GraphicsUnit.Point,
                        f.GdiCharSet,
                        f.GdiVerticalFont);
    }

    private Rectangle GetScaledRect(Graphics g, Rectangle r, float scale)
    {
        return new Rectangle((int)Math.Ceiling(r.X * scale),
                            (int)Math.Ceiling(r.Y * scale),
                            (int)Math.Ceiling(r.Width * scale),
                            (int)Math.Ceiling(r.Height * scale));
    }

Here is the entire test form:

public partial class Form1 : Form
{
    private PictureBox box = new PictureBox();

    public Form1()
    {
        InitializeComponent();
        this.Load += new EventHandler(Form1_Load);
    }

    public void Form1_Load(object sender, EventArgs e)
    {
        box.Dock = DockStyle.Fill;
        box.BackColor = Color.White;

        box.Paint += new PaintEventHandler(DrawTest);
        this.Controls.Add(box);
    }

    public void DrawTest(object sender, PaintEventArgs e)
    {
        Graphics g = e.Graphics;

        string text = "Test Text";
        float scale = 1.5F;
        float translate = 200F;

        var flags = TextFormatFlags.PreserveGraphicsClipping | TextFormatFlags.PreserveGraphicsTranslateTransform;

        var mx = new Matrix();
        mx.Scale(scale, scale);
        mx.Translate(translate, translate);

        g.Clip = new Region(Bounds);
        g.Transform = mx;

        Size rendererPSize = Bounds.Size;
        Font f = GetScaledFont(g, new Font("Arial", 12), scale);
        Size rendererRSize = TextRenderer.MeasureText(g, text, f, rendererPSize, flags);

        Rectangle rendererRect = new Rectangle(0, 0, rendererRSize.Width, rendererRSize.Height);
        Rectangle r = GetScaledRect(g, rendererRect, scale);

        TextRenderer.DrawText(g, text, f, realRect, Color.Black, flags);
    }

    private Font GetScaledFont(Graphics g, Font f, float scale)
    {
        return new Font(f.FontFamily,
                        f.SizeInPoints * scale,
                        f.Style,
                        GraphicsUnit.Point,
                        f.GdiCharSet,
                        f.GdiVerticalFont);
    }

    private Rectangle GetScaledRect(Graphics g, Rectangle r, float scale)
    {
        return new Rectangle((int)Math.Ceiling(r.X * scale),
                            (int)Math.Ceiling(r.Y * scale),
                            (int)Math.Ceiling(r.Width * scale),
                            (int)Math.Ceiling(r.Height * scale));
    }
}
like image 68
LiquidPony Avatar answered Nov 05 '22 03:11

LiquidPony