Как нарисовать строку в точном положении пикселя

Я пытаюсь нарисовать строку (один символ) в C# в точечный рисунок в точном положении с помощью:

Bitmap bmp = new Bitmap(64, 64);
Graphics g = Graphics.FromImage(bmp);
g.DrawString("W", font1, new SolidBrush(myColor), new Point(32,32);

Вокруг одной буквы столько пустого пространства, что я не могу угадать "нужную" позицию, чтобы нарисовать символ, чтобы он был в правильном положении в конце.

Теперь у меня есть точная размерность символа в пикселях (глядя на биты в отдельно отображаемом растровом изображении). Но эта информация бесполезна, если я не могу нарисовать символ в точной позиции (например, в центре или в верхнем правом углу или....).

Существуют ли другие способы рисования текста в C# на растровом изображении? Или есть какие-то методы преобразования, чтобы преобразовать реальное положение пикселя в то, что нужно DrawString?

1 ответ

Не нужно смотреть на пиксели или начать работать со своим собственным шрифтом.

Вы можете использовать GraphicsPath вместо DrawString или же TextRenderer, так как он даст вам знать его прямоугольник чистых границ с GraphicsPath.GetBounds(),

Когда вы знаете это, вы можете рассчитать, как переместить Graphics использование объекта TranslateTransform:

введите описание изображения здесь

private void button1_Click(object sender, EventArgs e)
{
    string text = "Y";                  // whatever
    Bitmap bmp = new Bitmap(64, 64);    // whatever
    bmp.SetResolution(96, 96);          // whatever
    float fontSize = 32f;               // whatever

    using ( Graphics g = Graphics.FromImage(bmp))
    using ( GraphicsPath GP = new GraphicsPath())
    using ( FontFamily fontF = new FontFamily("Arial"))
    {
        testPattern(g, bmp.Size);      // optional

        GP.AddString(text, fontF, 0, fontSize, Point.Empty,
                     StringFormat.GenericTypographic);
        // this is the net bounds without any whitespace:
        Rectangle br = Rectangle.Round(GP.GetBounds());

        g.DrawRectangle(Pens.Red,br); // just for testing

        // now we center:
        g.TranslateTransform( (bmp.Width - br.Width )  / 2 - br.X,
                              (bmp.Height - br.Height )/ 2 - br.Y);
        // and fill
        g.FillPath(Brushes.Black, GP);
        g.ResetTransform();
    }

    // whatever you want to do..
    pictureBox1.Image = bmp;
    bmp.Save("D:\\__test.png", ImageFormat.Png);

}

Небольшая процедура тестирования, чтобы мы лучше видели центрирование:

void testPattern(Graphics g, Size sz)
{
    List<Brush> brushes = new List<Brush>() 
    {   Brushes.SlateBlue, Brushes.Yellow, 
        Brushes.DarkGoldenrod, Brushes.Lavender };
    int bw2 = sz.Width / 2;
    int bh2 = sz.Height / 2;
    for (int i = bw2; i > 0; i--)
        g.FillRectangle(brushes[i%4],bw2 - i, bh2 - i, i + i, i + i );

}

GetBounds метод возвращает RectangleF; в моем примере это {X=0.09375, Y=6.0625, Width=21, Height=22.90625}, Обратите внимание, что из-за округления вещи всегда могут быть выключены одним.

Вы можете или не можете изменить Graphics установка на особый Smoothingmodes так далее..

Также следует отметить, что это будет делать автоматическое, т.е. механическое центрирование по прямоугольнику границ. Это может сильно отличаться от "оптического или визуального центрирования", которое довольно сложно кодировать и в некоторой степени зависит от личного вкуса. Но типография - это искусство, а не профессия.

Другие вопросы по тегам