Search code examples
c#.netbitmapgdi+system.drawing

Tiling Text Over Image at an Angle


I use the following code to draw text at the centre of an Image an Angle

Bitmap bmp = new Bitmap(pictureBox1.Image);
using (Graphics g = Graphics.FromImage(bmp)) {
  g.TranslateTransform(bmp.Width / 2, bmp.Height / 2);
  g.RotateTransform(30);
  SizeF textSize = g.MeasureString("hi", font);
  g.DrawString("hi", font, Brushes.Red, -(textSize.Width / 2), -(textSize.Height / 2));
}

I need to Tile the text all over the image like this

enter image description here

I know that i can increment the coordinates and use a Loop.I have

Bitmap bmp = new Bitmap(pictureBox1.Image);
            for (int i = 0; i < bmp.Width; i += 20)
            {
                for (int y = 0; y < bmp.Height; y += 20)
                {
                    using (Graphics g = Graphics.FromImage(bmp))
                    {
                        g.TranslateTransform(bmp.Width / 2, bmp.Height / 2);                      
                        g.RotateTransform(30);
                        SizeF textSize = g.MeasureString("my test image", DefaultFont);
                        g.DrawString("my test image", DefaultFont, Brushes.Yellow, i, y);
                       
                    }
                }
            }
            pictureBox1.Image = bmp;

This produces the following result

enter image description here

How can i place the text properly by measuring the drawn area properly.May be at a better and faster approach.


Solution

  • Call an additional TranslateTransform to move the text to where you want it at, then draw text with DrawString at (0, 0) coordinates. This will rotate each text around its own center, instead of rotating text around the center of the paragraph.

    Bitmap bmp = new Bitmap(pictureBox1.Image);
    Graphics g = Graphics.FromImage(bmp);
    String text = "TextTile";
    
    Font font = new Font(DefaultFont.Name, 20);
    SizeF size = g.MeasureString(text, font);
    int textwidth = size.ToSize().Width;
    int textheight = size.ToSize().Height;
    
    int y_offset = (int)(textwidth * Math.Sin(45 * Math.PI / 180.0));
    
    //the sin of the angle may return zero or negative value, 
    //it won't work with this formula
    if (y_offset >= 0)
    {
        for (int x = 0; x < bmp.Width; x += textwidth)
        {
            for (int y = 0; y < bmp.Height; y += y_offset)
            {
                //move to this position
                g.TranslateTransform(x, y);
    
                //draw text rotated around its center
                g.TranslateTransform(textwidth, textheight);
                g.RotateTransform(-45);
                g.TranslateTransform(-textwidth, -textheight);
                g.DrawString(text, font, Brushes.Yellow, 0, 0);
    
                //reset
                g.ResetTransform();
            }
        }
    }
    
    pictureBox1.Image = bmp;
    

    The above example uses a larger font with size 20. You can set it back to use DefaultFont.size. It uses 45 degree angle.