I found this class recent extending the graphics class, i changed it a little, and it does everything i could ask for!
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.Text;
public static class Graphics_DrawRtfText
{
private static RichTextBoxDrawer rtfDrawer;
public static void DrawRtfText(this Graphics graphics, string rtf, RectangleF layoutArea,float xFactor)
{
if (Graphics_DrawRtfText.rtfDrawer == null)
{
Graphics_DrawRtfText.rtfDrawer = new RichTextBoxDrawer();
}
Graphics_DrawRtfText.rtfDrawer.Rtf = rtf;
Graphics_DrawRtfText.rtfDrawer.Draw(graphics, layoutArea,xFactor);
}
private class RichTextBoxDrawer : RichTextBox
{
private const double anInch = 14.4;
public void LineSpace()
{
SafeNativeMethods.PARAFORMAT2 fmt = new SafeNativeMethods.PARAFORMAT2();
fmt.cbSize = Marshal.SizeOf(fmt);
fmt.dwMask |= SafeNativeMethods.PFM_LINESPACING | SafeNativeMethods.PFM_SPACEAFTER;
fmt.dyLineSpacing = (int)(22 * this.SelectionFont.SizeInPoints);
fmt.bLineSpacingRule = Convert.ToByte(4);
SafeNativeMethods.SendMessage(this.Handle, SafeNativeMethods.EM_SETPARAFORMAT, 0, ref fmt);
}
public void LineSpace(int _linespace)
{
SafeNativeMethods.PARAFORMAT2 fmt = new SafeNativeMethods.PARAFORMAT2();
fmt.cbSize = Marshal.SizeOf(fmt);
fmt.dwMask |= SafeNativeMethods.PFM_LINESPACING | SafeNativeMethods.PFM_SPACEAFTER;
fmt.dyLineSpacing = _linespace;
fmt.bLineSpacingRule = Convert.ToByte(4);
SafeNativeMethods.SendMessage(this.Handle, SafeNativeMethods.EM_SETPARAFORMAT, 0, ref fmt);
}
protected override CreateParams CreateParams
{
get
{
CreateParams createParams = base.CreateParams;
if (SafeNativeMethods.LoadLibrary("msftedit.dll") != IntPtr.Zero)
{
createParams.ExStyle |= SafeNativeMethods.WS_EX_TRANSPARENT;
createParams.ClassName = "RICHEDIT50W";
}
return createParams;
}
}
private void DPToHIMETRIC(Graphics graphics,ref SizeF size)
{
size.Width = (size.Width * 2540.0f) / graphics.DpiX;
size.Height = (size.Height * 2540.0f) / graphics.DpiY;
}
public void Draw(Graphics graphics, RectangleF layoutArea, float xFactor)
{
System.Diagnostics.Debug.WriteLine("LayoutArea " + layoutArea);
SizeF metaSize = layoutArea.Size;
DPToHIMETRIC(graphics, ref metaSize);
System.Diagnostics.Debug.WriteLine("MetaSize " + metaSize);
IntPtr hdc = graphics.GetHdc();
Metafile metafile = new Metafile(hdc, new RectangleF(0,0,metaSize.Width,metaSize.Height));
graphics.ReleaseHdc(hdc);
Graphics g = Graphics.FromImage(metafile);
IntPtr hDCEMF = g.GetHdc();
SafeNativeMethods.RECT rectLayoutArea;
rectLayoutArea.Left = 0;
rectLayoutArea.Top = 0;
rectLayoutArea.Right = (int)((1440 * metaSize.Width + 2540 / 2) / 2540);
rectLayoutArea.Bottom = (int)((1440 * metaSize.Height + 2540 / 2) / 2540);
System.Diagnostics.Debug.WriteLine(String.Format("RectLayoutArea ({0},{1})",rectLayoutArea.Right,rectLayoutArea.Bottom));
SafeNativeMethods.FORMATRANGE fmtRange;
fmtRange.chrg.cpMax = -1;
fmtRange.chrg.cpMin = 0;
fmtRange.hdc = hDCEMF;
fmtRange.hdcTarget = hDCEMF;
fmtRange.rc = rectLayoutArea;
fmtRange.rcPage = rectLayoutArea;
IntPtr wParam = IntPtr.Zero;
wParam = new IntPtr(1);
IntPtr lParam = IntPtr.Zero;
lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fmtRange));
Marshal.StructureToPtr(fmtRange, lParam, false);
SafeNativeMethods.SendMessage(this.Handle, SafeNativeMethods.EM_FORMATRANGE, wParam, lParam);
SafeNativeMethods.SendMessage(this.Handle, SafeNativeMethods.EM_FORMATRANGE, wParam, IntPtr.Zero);
Marshal.FreeCoTaskMem(lParam);
g.ReleaseHdc(hDCEMF);
g.Dispose();
hdc = graphics.GetHdc();
int nHorzSize = SafeNativeMethods.GetDeviceCaps(hdc, SafeNativeMethods.DeviceCap.HORZSIZE);
int nVertSize = SafeNativeMethods.GetDeviceCaps(hdc, SafeNativeMethods.DeviceCap.VERTSIZE);
int nHorzRes = SafeNativeMethods.GetDeviceCaps(hdc, SafeNativeMethods.DeviceCap.HORZRES);
int nVertRes = SafeNativeMethods.GetDeviceCaps(hdc, SafeNativeMethods.DeviceCap.VERTRES);
int nLogPixelsX = SafeNativeMethods.GetDeviceCaps(hdc, SafeNativeMethods.DeviceCap.LOGPIXELSX);
int nLogPixelsY = SafeNativeMethods.GetDeviceCaps(hdc, SafeNativeMethods.DeviceCap.LOGPIXELSY);
graphics.ReleaseHdc(hdc);
float fHorzSizeInches = nHorzSize / 25.4f;
float fVertSizeInches = nVertSize / 25.4f;
float fHorzFudgeFactor = (nHorzRes / fHorzSizeInches) / nLogPixelsX;
float fVertFudgeFactor = (nVertRes / fVertSizeInches) / nLogPixelsY;
System.Diagnostics.Debug.WriteLine("Fudge Factor " + fHorzFudgeFactor.ToString() + " " + fVertFudgeFactor.ToString() + " XFactor " + xFactor.ToString());
Pen RedPen = new Pen(Color.Red);
graphics.DrawRectangle(RedPen, layoutArea.X * xFactor, layoutArea.Y * xFactor, layoutArea.Width * xFactor, layoutArea.Height * xFactor);
float Left = layoutArea.Left;
float Top = layoutArea.Top;
layoutArea.Offset(-Left, -Top);
layoutArea.Offset(Left / fHorzFudgeFactor, Top / fVertFudgeFactor);
System.Drawing.Drawing2D.GraphicsState state = graphics.Save();
graphics.ScaleTransform(fHorzFudgeFactor * xFactor, fVertFudgeFactor * xFactor);
graphics.DrawImage(metafile, layoutArea);
graphics.Restore(state);
System.Diagnostics.Debug.WriteLine("Layout Aread : "+layoutArea);
}
#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);
[DllImport("gdi32.dll")]
public static extern int GetDeviceCaps(IntPtr hdc, DeviceCap nIndex);
[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, ref PARAFORMAT2 lParam);
[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;
public int cpMax;
}
[StructLayout(LayoutKind.Sequential)]
public struct FORMATRANGE
{
public IntPtr hdc;
public IntPtr hdcTarget;
public RECT rc;
public RECT rcPage;
public CHARRANGE chrg;
}
public enum DeviceCap : int
{
DRIVERVERSION = 0,
TECHNOLOGY = 2,
HORZSIZE = 4,
VERTSIZE = 6,
HORZRES = 8,
VERTRES = 10,
BITSPIXEL = 12,
PLANES = 14,
NUMBRUSHES = 16,
NUMPENS = 18,
NUMMARKERS = 20,
NUMFONTS = 22,
NUMCOLORS = 24,
PDEVICESIZE = 26,
CURVECAPS = 28,
LINECAPS = 30,
POLYGONALCAPS = 32,
TEXTCAPS = 34,
CLIPCAPS = 36,
RASTERCAPS = 38,
ASPECTX = 40,
ASPECTY = 42,
ASPECTXY = 44,
SHADEBLENDCAPS = 45,
LOGPIXELSX = 88,
LOGPIXELSY = 90,
SIZEPALETTE = 104,
NUMRESERVED = 106,
COLORRES = 108,
PHYSICALWIDTH = 110,
PHYSICALHEIGHT = 111,
PHYSICALOFFSETX = 112,
PHYSICALOFFSETY = 113,
SCALINGFACTORX = 114,
SCALINGFACTORY = 115,
VREFRESH = 116,
DESKTOPVERTRES = 117,
DESKTOPHORZRES = 118,
BLTALIGNMENT = 119
}
public struct PARAFORMAT2
{
public int cbSize;
public uint dwMask;
public short wNumbering;
public short wReserved;
public int dxStartIndent;
public int dxRightIndent;
public int dxOffset;
public short wAlignment;
public short cTabCount;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public int[] rgxTabs;
public int dySpaceBefore;
public int dySpaceAfter;
public int dyLineSpacing;
public short sStyle;
public byte bLineSpacingRule;
public byte bOutlineLevel;
public short wShadingWeight;
public short wShadingStyle;
public short wNumberingStart;
public short wNumberingStyle;
public short wNumberingTab;
public short wBorderSpace;
public short wBorderWidth;
public short wBorders;
}
public const int EM_FORMATRANGE = WM_USER + 57;
public const int PFM_SPACEAFTER = 128;
public const int PFM_LINESPACING = 256;
public const int EM_SETPARAFORMAT = 1095;
public const int WM_USER = 0x0400;
public const int WS_EX_TRANSPARENT = 0x20;
}
#endregion
}
}