Как нарисовать строку в точном положении пикселя
Я пытаюсь нарисовать строку (один символ) в 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
так далее..
Также следует отметить, что это будет делать автоматическое, т.е. механическое центрирование по прямоугольнику границ. Это может сильно отличаться от "оптического или визуального центрирования", которое довольно сложно кодировать и в некоторой степени зависит от личного вкуса. Но типография - это искусство, а не профессия.