Рисование строки с полным выравниванием в .NET - PullRequest
0 голосов
/ 10 октября 2011

Мне нужно записать строку в растровое изображение с полным выравниванием.Я знаю, что StringFormat.Alignment не поддерживает полное выравнивание.Итак, я ищу решение для рисования строки на растровом изображении с полным выравниванием.RictTextBox имеет полное оправдание, но я думаю, что он использует WinAPI для выравнивания текста.Может быть, я могу нарисовать текст с помощью RichTextBox, но я не знаю, как получить растровое изображение элемента управления (скриншот) без отображения в форме.Есть ли какая-нибудь хитрость или альтернативная сторонняя библиотека для System.Drawing.Graphics?

1 Ответ

2 голосов
/ 28 октября 2011

Я использовал метод для рисования RichTextBox на растровом изображении.

public class ExtendedRichTextBox : RichTextBox
{
    private const double inch = 1440 / 96;//Not 14.4!!, believe me you can see someone use 1.44 but it doesn't work on big bitmaps. They round the 1440/96 as 14.4 but it works on only small sized works. use /96

    public void DrawToBitmap(Graphics graphics, Rectangle bound)
    {
        Update();  // Ensure RTB fully painted
        IntPtr hDC = graphics.GetHdc();
        FORMATRANGE fmtRange;

        RECT rect;
        rect.Left = (int)Math.Ceiling(bound.X * inch);
        rect.Top = (int)Math.Ceiling(bound.Y * inch);
        rect.Right = (int)Math.Ceiling(bound.Right * inch);
        rect.Bottom = (int)Math.Ceiling(bound.Bottom * inch);
        int fromAPI;

        fmtRange.hdc = hDC;
        fmtRange.hdcTarget = hDC;

        fmtRange.chrg.cpMin = 0;
        fmtRange.chrg.cpMax = -1;
        fmtRange.rc = rect;
        fmtRange.rcPage = rect;

        IntPtr lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fmtRange));
        Marshal.StructureToPtr(fmtRange, lParam, false);
        fromAPI = SendMessage(Handle, EM_FORMATRANGE, 0, lParam);
        fromAPI = SendMessage(Handle, EM_FORMATRANGE, 1, lParam);
        Marshal.FreeCoTaskMem(lParam);
        fromAPI = SendMessage(Handle, EM_FORMATRANGE, 0, new IntPtr(0));
        graphics.ReleaseHdc(hDC);
    }
}

Вы можете найти реализации WinApi на сайте pinvoke.Но вы можете взять и здесь:

[DllImport("USER32.dll")]
private static extern Int32 SendMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam);
private const int WM_USER = 0x400;
private const int EM_FORMATRANGE = WM_USER + 57;
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
    public int Left;
    public int Top;
    public int Right;
    public int Bottom;
}

[StructLayout(LayoutKind.Sequential)]
private struct CHARRANGE
{
    public int cpMin;
    public int cpMax;
}

[StructLayout(LayoutKind.Sequential)]
private struct FORMATRANGE
{
    public IntPtr hdc;
    public IntPtr hdcTarget;
    public RECT rc;
    public RECT rcPage;
    public CHARRANGE chrg;
}

А вот пример использования.

var richtext = new ExtendedRichTextBox(); 
/*I've implemented a RichTextBox but it isn't realted with this question. 
You can use simply RichTextBox. ExtendedRichTextBox has support rtl.*/

richtext.Font = font;
richtext.ForeColor = textColor;
richtext.Text = sometext;
richtext.SelectAll();
richtext.RightToLeft = rtl;
richtext.SelectionAlignment = align;

//Fix the rtl bug in RichTextBox
if (rtl == RightToLeft.Yes)
{
    if (align == TextAlign.Center)
        richtext.Rtf = richtext.Rtf.Replace(@"\qr", @"\qc");
    else if (align == TextAlign.Left)
        richtext.Rtf = richtext.Rtf.Replace(@"\qr", @"\ql");
    else if (align == TextAlign.Justify)
        richtext.Rtf = richtext.Rtf.Replace(@"\qr", @"\qj");
}

//textRect is where we want to put text in.
var tempBitmap = new Bitmap(textRect.Width, textRect.Height);
richtext.DrawToBitmap(Graphics.FromImage(tempBitmap), tempRect);
tempBitmap.MakeTransparent(richtext.BackColor);
graph.DrawImage(tempBitmap, panelRect.X, panelRect.Y);
...