I have code that allows me to basically write the contents of a
richtextbox to a bitmap (code below). This code works fine, but it
always draws the text "normal size" regardless of the setting of
ZoomFactor. How can I get the "zoomed" verison of the text into a
bitmap?
Thanks in advance!
-------------------------------------------------------------------------------------------------------------------------------------
[ StructLayout( LayoutKind.Sequential )]
private struct STRUCT_RECT
{
public Int32 left;
public Int32 top;
public Int32 right;
public Int32 bottom;
}
[ StructLayout( LayoutKind.Sequential )]
private struct STRUCT_CHARRANGE
{
public Int32 cpMin;
public Int32 cpMax;
}
[ StructLayout( LayoutKind.Sequential )]
private struct STRUCT_FORMATRANGE
{
public IntPtr hdc;
public IntPtr hdcTarget;
public STRUCT_RECT rc;
public STRUCT_RECT rcPage;
public STRUCT_CHARRANGE chrg;
}
[DllImport("user32.dll")]
private static extern Int32 SendMessage(IntPtr hWnd, Int32 msg,
Int32 wParam, IntPtr lParam);
[DllImport("user32.dll")]
private static extern Int32 SendMessageA(IntPtr hWnd, Int32 msg,
Int32 wParam, Int32 lParam);
// Windows Messages defines
private const Int32 WM_USER = 0x400;
private const Int32 EM_FORMATRANGE = WM_USER+57;
private const Int32 EM_GETEVENTMASK = WM_USER+59;
private const Int32 EM_REQUESTRESIZE = WM_USER+65;
private const Int32 EM_SETEVENTMASK = WM_USER+69;
private const Int32 ENM_REQUESTRESIZE = 0x40000;
/// <summary>
/// Render the RTF to a bitmap.
/// </summary>
/// <param name="measureOnly">If true, only the calculation is
performed,
/// otherwise the text is rendered as well</param>
/// <param name="g">Graphics object to render onto</param>
/// <returns>(Index of last character that fit) + 1</returns>
private int RTFToImage(bool measureOnly, Graphics g)
{
// Specify which characters to print
STRUCT_CHARRANGE cr;
cr.cpMin = 0;
cr.cpMax = -1;
// Specify the area inside page margins
STRUCT_RECT rc;
rc.top = PixelsToTwips(0, g.DpiX);
rc.bottom = PixelsToTwips((int)g.VisibleClipBounds.Height,
g.DpiX);
rc.left = PixelsToTwips(0, g.DpiX);
rc.right = PixelsToTwips((int)g.VisibleClipBounds.Width, g.DpiX);
// Specify the page area
STRUCT_RECT rcPage;
rcPage.top = PixelsToTwips(0, g.DpiX);
rcPage.bottom = PixelsToTwips((int)g.VisibleClipBounds.Height,
g.DpiX);
rcPage.left = PixelsToTwips(0, g.DpiX);
rcPage.right = PixelsToTwips((int)g.VisibleClipBounds.Width, g.DpiX);
// Get device context of output device
IntPtr hdc = g.GetHdc();
// Fill in the FORMATRANGE struct
STRUCT_FORMATRANGE fr;
fr.chrg = cr;
fr.hdc = hdc;
fr.hdcTarget = hdc;
fr.rc = rc;
fr.rcPage = rcPage;
// Non-Zero wParam means render, Zero means measure
Int32 wParam = (measureOnly ? 0 : 1);
// Allocate memory for the FORMATRANGE struct and
// copy the contents of our struct to this memory
IntPtr lParam = Marshal.AllocCoTaskMem( Marshal.SizeOf( fr ) );
Marshal.StructureToPtr(fr, lParam, false);
// Send the actual Win32 message
int res = SendMessage(Handle, EM_FORMATRANGE, wParam, lParam);
// Free allocated memory
Marshal.FreeCoTaskMem(lParam);
// and release the device context
g.ReleaseHdc(hdc);
return res;
}
/// <summary>
/// Convert between 1/100 inch (unit used by the .NET framework)
/// and twips (1/1440 inch, used by Win32 API calls)
/// </summary>
/// <param name="n">Value in 1/100 inch</param>
/// <returns>Value in twips</returns>
private Int32 HundredthInchToTwips(int n)
{
return (Int32)(n*14.4);
}
private Int32 PixelsToTwips(int n, float dpi)
{
return (Int32)(((float)n/dpi)*1440.0f);
}