23May/084
Draw RTF Text on a Graphics Object in C#
With this code you can draw some RTF text on a Graphics object.
Code modified from this code: How to print the content of a RichTextBox control by using Visual C# .NET or Visual C# 2005
Also, the control transparency code was taken from here:Simple Vector Shapes (Tried to get his code working, but there were some problems, also some of the code is in a different language)
Anyway, it's an extension method, so you can do this in a Form:
protected override void OnPaint(PaintEventArgs e) { e.Graphics.Clear(Color.Fuchsia); e.Graphics.DrawRtfText(this.richTextBox1.Rtf, this.richTextBox1.ClientRectangle); base.OnPaint(e); }
Here's the full code listing; just add a new .cs and throw it in:
using System; using System.Drawing; using System.Runtime.InteropServices; using System.Windows.Forms; public static class Graphics_DrawRtfText { private static RichTextBoxDrawer rtfDrawer; public static void DrawRtfText(this Graphics graphics, string rtf, Rectangle layoutArea) { if (Graphics_DrawRtfText.rtfDrawer == null) { Graphics_DrawRtfText.rtfDrawer = new RichTextBoxDrawer(); } Graphics_DrawRtfText.rtfDrawer.Rtf = rtf; Graphics_DrawRtfText.rtfDrawer.Draw(graphics, layoutArea); } private class RichTextBoxDrawer : RichTextBox { //Code converted from code found here: http://support.microsoft.com/kb/812425/en-us //Convert the unit used by the .NET framework (1/100 inch) //and the unit used by Win32 API calls (twips 1/1440 inch) private const double anInch = 14.4; protected override CreateParams CreateParams { get { CreateParams createParams = base.CreateParams; if (SafeNativeMethods.LoadLibrary("msftedit.dll") != IntPtr.Zero) { createParams.ExStyle |= SafeNativeMethods.WS_EX_TRANSPARENT; // transparent createParams.ClassName = "RICHEDIT50W"; } return createParams; } } public void Draw(Graphics graphics, Rectangle layoutArea) { //Calculate the area to render. SafeNativeMethods.RECT rectLayoutArea; rectLayoutArea.Top = (int)(layoutArea.Top * anInch); rectLayoutArea.Bottom = (int)(layoutArea.Bottom * anInch); rectLayoutArea.Left = (int)(layoutArea.Left * anInch); rectLayoutArea.Right = (int)(layoutArea.Right * anInch); IntPtr hdc = graphics.GetHdc(); SafeNativeMethods.FORMATRANGE fmtRange; fmtRange.chrg.cpMax = -1; //Indicate character from to character to fmtRange.chrg.cpMin = 0; fmtRange.hdc = hdc; //Use the same DC for measuring and rendering fmtRange.hdcTarget = hdc; //Point at printer hDC fmtRange.rc = rectLayoutArea; //Indicate the area on page to print fmtRange.rcPage = rectLayoutArea; //Indicate size of page IntPtr wParam = IntPtr.Zero; wParam = new IntPtr(1); //Get the pointer to the FORMATRANGE structure in memory IntPtr lParam = IntPtr.Zero; lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fmtRange)); Marshal.StructureToPtr(fmtRange, lParam, false); SafeNativeMethods.SendMessage(this.Handle, SafeNativeMethods.EM_FORMATRANGE, wParam, lParam); //Free the block of memory allocated Marshal.FreeCoTaskMem(lParam); //Release the device context handle obtained by a previous call graphics.ReleaseHdc(hdc); } #region SafeNativeMethods private static class SafeNativeMethods { [DllImport("USER32.dll")] public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp); [DllImport("kernel32.dll", CharSet = CharSet.Auto)] public static extern IntPtr LoadLibrary(string lpFileName); [StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left; public int Top; public int Right; public int Bottom; } [StructLayout(LayoutKind.Sequential)] public struct CHARRANGE { public int cpMin; //First character of range (0 for start of doc) public int cpMax; //Last character of range (-1 for end of doc) } [StructLayout(LayoutKind.Sequential)] public struct FORMATRANGE { public IntPtr hdc; //Actual DC to draw on public IntPtr hdcTarget; //Target DC for determining text formatting public RECT rc; //Region of the DC to draw to (in twips) public RECT rcPage; //Region of the whole DC (page size) (in twips) public CHARRANGE chrg; //Range of text to draw (see earlier declaration) } public const int WM_USER = 0x0400; public const int EM_FORMATRANGE = WM_USER + 57; public const int WS_EX_TRANSPARENT = 0x20; } #endregion } }
You might want to do some testing, it's not exactly production code!
February 5th, 2009 - 05:05
Thanks!
This bit of code solved a problem for me.
September 9th, 2009 - 19:17
This is very useful. Do you know if there is a managed-only solution that would work on Mono?
November 24th, 2009 - 08:41
Hi,
This is a great improvement on my previous code. I was creating a bitmap and using DrawImage. However, it only works correctly if there is no transform matrix applied. Do you know how to use the transformed graphics object (Rotate, Translate and Scale applied)?
March 10th, 2010 - 14:32
Great!
BUt have you any idea how to archive SCALING richtext? this code unfortunatelly works with zoom=1f!!
Any ideas?