RTF Render with Scale

  • Thread starter Thread starter AliR \(VC++ MVP\)
  • Start date Start date
A

AliR \(VC++ MVP\)

I'm trying to write a RTF render code in C#. I have the code in C++/MFC and
it works fine, but I have run into a problem with the C# code. I think the
C# code is from Microsoft, and I added scaling to it. The C# code is
working fine on my desktop PC but it cuts off some of the text when I run it
on my laptop. The MFC code works fine both on the laptop and the PC. I
have looked at all the numbers used in the MFC and the C# code and they are
identical. Both PC and Laptop are at 1440x900 96dpi font size.

I have been looking at the code for 3 or 4 days now without any improvment.
Was wondering if anyone here wants to take a stab at it.

You can download both sample projects:
http://www.learnstar.com/AliR/RTFScaler.zip
http://www.learnstar.com/AliR/RTFScalerMFC.zip


Thanks
AliR.


Here is the MFC code
// *** copying/scaling/rotating and shearing the text is done here
void CRTFScalerDlg::RenderText(int nScalePercent,int nRotationDegrees,int
nHorzShearPercent,int nVertShearPercent)
{
// validate the arguments
if (nScalePercent < 1)
nScalePercent = 1;
if (nScalePercent > 10000)
nScalePercent = 10000;
if (nRotationDegrees < 0)
nRotationDegrees = 0;
if (nRotationDegrees > 360)
nRotationDegrees = 360;
if (nHorzShearPercent < 0)
nHorzShearPercent = 0;
if (nHorzShearPercent > 100)
nHorzShearPercent = 100;
if (nVertShearPercent < 0)
nVertShearPercent = 0;
if (nVertShearPercent > 100)
nVertShearPercent = 100;

// setup target window, rect and DC
CWnd* pTargetWin = GetDlgItem(IDC_EDIT1);
CRect crTarget;
pTargetWin->GetClientRect(&crTarget);
crTarget.OffsetRect(0,20);
CDC* pTargetDC = pTargetWin->GetDC();
pTargetDC->IntersectClipRect(&crTarget); // so we don't clobber the parent
dialog
pTargetDC->SetBkMode(TRANSPARENT); // so the legend doesn't erase too
much

// also need advanced graphics mode for the world transform stuff
if (!SetGraphicsMode(pTargetDC->m_hDC,GM_ADVANCED))
{
pTargetDC->DrawText("Nice try but I need Windows NT, 2000, XP or 2003 for
this.",crTarget,DT_SINGLELINE | DT_VCENTER | DT_CENTER);
return;
}

// erase previous contents
FillRect(pTargetDC->m_hDC,crTarget,(HBRUSH)(COLOR_WINDOW + 1));
CString Temp;
Temp.Format("crTarget %d,%d
%d,%d\n",crTarget.left,crTarget.top,crTarget.Width(),crTarget.Height());
TRACE(Temp);

// setup rectangles for metafile fiddling
CSize cTargetSize = crTarget.Size();
pTargetDC->DPtoHIMETRIC(&cTargetSize); // from MM_Text to MM_HIMETRIC
CSize TopLeft;
TopLeft.cx = crTarget.left;
TopLeft.cy = crTarget.top;
pTargetDC->DPtoHIMETRIC(&TopLeft); // from MM_Text to MM_HIMETRIC

CRect cHiMetricRect(0,0,cTargetSize.cx,cTargetSize.cy);
CRect cTwipsRect(0,0,(TWIPS_INCH * cTargetSize.cx + HIMETRIC_INCH / 2) /
HIMETRIC_INCH,
(TWIPS_INCH * cTargetSize.cy + HIMETRIC_INCH / 2) / HIMETRIC_INCH);

Temp.Format("MetaSize
%d,%d\n",cHiMetricRect.Width(),cHiMetricRect.Height());
TRACE(Temp);
Temp.Format("cTwipsRect %d,%d\n",cTwipsRect.Width(),cTwipsRect.Height());
TRACE(Temp);
// create the enhanced metafile
HDC hDCEMF = CreateEnhMetaFile(pTargetDC->m_hDC,NULL,cHiMetricRect,NULL);

// setup the format struct and do the RTF range formatting call
FORMATRANGE stFR;
stFR.hdcTarget = stFR.hdc = hDCEMF; // render to the memory helper EMF
stFR.rcPage = stFR.rc = cTwipsRect; // using this rectangle (in twips)
stFR.chrg.cpMin = 0; // and render all of the text
stFR.chrg.cpMax = -1;
GetDlgItem(IDC_RICHEDIT1)->SendMessage(EM_FORMATRANGE,TRUE,(LPARAM) &stFR);
GetDlgItem(IDC_RICHEDIT1)->SendMessage(EM_FORMATRANGE,TRUE,NULL); // this
call clears the cache

// drawing into the metafile is done, get ourselves an handle to it (used
for the replay)
HENHMETAFILE hEMF = CloseEnhMetaFile(hDCEMF);

// calculate the automagic fudge factors by getting the device metrics
int nHorzSize = pTargetDC->GetDeviceCaps(HORZSIZE ); // width in
millimeters
int nVertSize = pTargetDC->GetDeviceCaps(VERTSIZE ); // height in
millimeters
int nHorzRes = pTargetDC->GetDeviceCaps(HORZRES ); // width in pixels
int nVertRes = pTargetDC->GetDeviceCaps(VERTRES ); // height in
pixels
int nLogPixelsX = pTargetDC->GetDeviceCaps(LOGPIXELSX); // # of pixels per
inch horizontally
int nLogPixelsY = pTargetDC->GetDeviceCaps(LOGPIXELSY); // # of pixels per
inch vertically

float fHorzSizeInches = nHorzSize / 25.4f;
float fVertSizeInches = nVertSize / 25.4f;
float fHorzFudgeFactor = (nHorzRes / fHorzSizeInches) / nLogPixelsX; //
divide expected DPI with actual DPI
float fVertFudgeFactor = (nVertRes / fVertSizeInches) / nLogPixelsY; //

Temp.Format("Fudgfactor %.2f %.2f\n",fHorzFudgeFactor,fVertFudgeFactor);
TRACE(Temp);

// change from degrees to radians
// (also need to change sign since page space is upside down)
float fRotationInRadians = (PI * (0 - nRotationDegrees)) / 180.0F;

// do the world transforms, first apply the scale and fudge factors
XFORM stX;
ZeroMemory(&stX,sizeof(stX));
stX.eM11 = fHorzFudgeFactor * (nScalePercent / 100.0f);
stX.eM22 = fVertFudgeFactor * (nScalePercent / 100.0f);
SetWorldTransform(pTargetDC->m_hDC,&stX);

// then apply the rotation
ZeroMemory(&stX,sizeof(stX));
stX.eM11 = (float) cos(fRotationInRadians);
stX.eM12 = (float) sin(fRotationInRadians);
stX.eM21 = 0 - (float) sin(fRotationInRadians);
stX.eM22 = (float) cos(fRotationInRadians);
ModifyWorldTransform(pTargetDC->m_hDC,&stX,MWT_LEFTMULTIPLY);

// finally apply the horizontal and vertical shearing
ZeroMemory(&stX,sizeof(stX));
stX.eM11 = 1.0f;
stX.eM12 = nHorzShearPercent / 100.0f;
stX.eM21 = nVertShearPercent / 100.0f;
stX.eM22 = 1.0f;
ModifyWorldTransform(pTargetDC->m_hDC,&stX,MWT_LEFTMULTIPLY);

crTarget.OffsetRect(0,-20);
crTarget.OffsetRect(0,20 / (nScalePercent / 100.0f) * fVertFudgeFactor);
// play the metafile
pTargetDC->PlayMetaFile(hEMF,&crTarget);

// that's it, kiss the metafile goodbye
DeleteEnhMetaFile(hEMF);

// also show a legend
ModifyWorldTransform(pTargetDC->m_hDC,NULL,MWT_IDENTITY);
CString sLegend;
sLegend.Format("Scale: %d%% rotation: %dº horizontal shear: %d%%
vertical shear: %d%%.",
nScalePercent,nRotationDegrees,nHorzShearPercent,nVertShearPercent);
pTargetDC->SetTextColor(RGB(55,111,111));
pTargetDC->DrawText(sLegend,crTarget,DT_SINGLELINE | DT_VCENTER |
DT_CENTER);
}


Here is the C# code:

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
{
//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;
}
}

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();

//create a metafile, convert the size to himetrics
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();

//Calculate the area to render.
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; //Indicate character from
to character to
fmtRange.chrg.cpMin = 0;
fmtRange.hdc = hDCEMF; //Use the same DC for
measuring and rendering
fmtRange.hdcTarget = hDCEMF; //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);
SafeNativeMethods.SendMessage(this.Handle,
SafeNativeMethods.EM_FORMATRANGE, wParam, IntPtr.Zero);

//Free the block of memory allocated
Marshal.FreeCoTaskMem(lParam);

//Release the device context handle obtained by a previous call
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.X = layoutArea.Y = 0;
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);

[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 enum DeviceCap : int
{
/// <summary>
/// Device driver version
/// </summary>
DRIVERVERSION = 0,
/// <summary>
/// Device classification
/// </summary>
TECHNOLOGY = 2,
/// <summary>
/// Horizontal size in millimeters
/// </summary>
HORZSIZE = 4,
/// <summary>
/// Vertical size in millimeters
/// </summary>
VERTSIZE = 6,
/// <summary>
/// Horizontal width in pixels
/// </summary>
HORZRES = 8,
/// <summary>
/// Vertical height in pixels
/// </summary>
VERTRES = 10,
/// <summary>
/// Number of bits per pixel
/// </summary>
BITSPIXEL = 12,
/// <summary>
/// Number of planes
/// </summary>
PLANES = 14,
/// <summary>
/// Number of brushes the device has
/// </summary>
NUMBRUSHES = 16,
/// <summary>
/// Number of pens the device has
/// </summary>
NUMPENS = 18,
/// <summary>
/// Number of markers the device has
/// </summary>
NUMMARKERS = 20,
/// <summary>
/// Number of fonts the device has
/// </summary>
NUMFONTS = 22,
/// <summary>
/// Number of colors the device supports
/// </summary>
NUMCOLORS = 24,
/// <summary>
/// Size required for device descriptor
/// </summary>
PDEVICESIZE = 26,
/// <summary>
/// Curve capabilities
/// </summary>
CURVECAPS = 28,
/// <summary>
/// Line capabilities
/// </summary>
LINECAPS = 30,
/// <summary>
/// Polygonal capabilities
/// </summary>
POLYGONALCAPS = 32,
/// <summary>
/// Text capabilities
/// </summary>
TEXTCAPS = 34,
/// <summary>
/// Clipping capabilities
/// </summary>
CLIPCAPS = 36,
/// <summary>
/// Bitblt capabilities
/// </summary>
RASTERCAPS = 38,
/// <summary>
/// Length of the X leg
/// </summary>
ASPECTX = 40,
/// <summary>
/// Length of the Y leg
/// </summary>
ASPECTY = 42,
/// <summary>
/// Length of the hypotenuse
/// </summary>
ASPECTXY = 44,
/// <summary>
/// Shading and Blending caps
/// </summary>
SHADEBLENDCAPS = 45,

/// <summary>
/// Logical pixels inch in X
/// </summary>
LOGPIXELSX = 88,
/// <summary>
/// Logical pixels inch in Y
/// </summary>
LOGPIXELSY = 90,

/// <summary>
/// Number of entries in physical palette
/// </summary>
SIZEPALETTE = 104,
/// <summary>
/// Number of reserved entries in palette
/// </summary>
NUMRESERVED = 106,
/// <summary>
/// Actual color resolution
/// </summary>
COLORRES = 108,

// Printing related DeviceCaps. These replace the
appropriate Escapes
/// <summary>
/// Physical Width in device units
/// </summary>
PHYSICALWIDTH = 110,
/// <summary>
/// Physical Height in device units
/// </summary>
PHYSICALHEIGHT = 111,
/// <summary>
/// Physical Printable Area x margin
/// </summary>
PHYSICALOFFSETX = 112,
/// <summary>
/// Physical Printable Area y margin
/// </summary>
PHYSICALOFFSETY = 113,
/// <summary>
/// Scaling factor x
/// </summary>
SCALINGFACTORX = 114,
/// <summary>
/// Scaling factor y
/// </summary>
SCALINGFACTORY = 115,

/// <summary>
/// Current vertical refresh rate of the display device (for
displays only) in Hz
/// </summary>
VREFRESH = 116,
/// <summary>
/// Horizontal width of entire desktop in pixels
/// </summary>
DESKTOPVERTRES = 117,
/// <summary>
/// Vertical height of entire desktop in pixels
/// </summary>
DESKTOPHORZRES = 118,
/// <summary>
/// Preferred blt alignment
/// </summary>
BLTALIGNMENT = 119
}


public const int WM_USER = 0x0400;
public const int EM_FORMATRANGE = WM_USER + 57;
public const int WS_EX_TRANSPARENT = 0x20;

}
#endregion
}
}
 
Let me also mention that the laptop that is having the funny results is
running Vista 64, the other machines which everything works fine on is
running Vista 32 or XP.

AliR.


AliR (VC++ MVP) said:
I'm trying to write a RTF render code in C#. I have the code in C++/MFC
and it works fine, but I have run into a problem with the C# code. I
think the C# code is from Microsoft, and I added scaling to it. The C#
code is working fine on my desktop PC but it cuts off some of the text
when I run it on my laptop. The MFC code works fine both on the laptop
and the PC. I have looked at all the numbers used in the MFC and the C#
code and they are identical. Both PC and Laptop are at 1440x900 96dpi
font size.

I have been looking at the code for 3 or 4 days now without any
improvment. Was wondering if anyone here wants to take a stab at it.

You can download both sample projects:
http://www.learnstar.com/AliR/RTFScaler.zip
http://www.learnstar.com/AliR/RTFScalerMFC.zip


Thanks
AliR.


Here is the MFC code
// *** copying/scaling/rotating and shearing the text is done here
void CRTFScalerDlg::RenderText(int nScalePercent,int nRotationDegrees,int
nHorzShearPercent,int nVertShearPercent)
{
// validate the arguments
if (nScalePercent < 1)
nScalePercent = 1;
if (nScalePercent > 10000)
nScalePercent = 10000;
if (nRotationDegrees < 0)
nRotationDegrees = 0;
if (nRotationDegrees > 360)
nRotationDegrees = 360;
if (nHorzShearPercent < 0)
nHorzShearPercent = 0;
if (nHorzShearPercent > 100)
nHorzShearPercent = 100;
if (nVertShearPercent < 0)
nVertShearPercent = 0;
if (nVertShearPercent > 100)
nVertShearPercent = 100;

// setup target window, rect and DC
CWnd* pTargetWin = GetDlgItem(IDC_EDIT1);
CRect crTarget;
pTargetWin->GetClientRect(&crTarget);
crTarget.OffsetRect(0,20);
CDC* pTargetDC = pTargetWin->GetDC();
pTargetDC->IntersectClipRect(&crTarget); // so we don't clobber the parent
dialog
pTargetDC->SetBkMode(TRANSPARENT); // so the legend doesn't erase too
much

// also need advanced graphics mode for the world transform stuff
if (!SetGraphicsMode(pTargetDC->m_hDC,GM_ADVANCED))
{
pTargetDC->DrawText("Nice try but I need Windows NT, 2000, XP or 2003 for
this.",crTarget,DT_SINGLELINE | DT_VCENTER | DT_CENTER);
return;
}

// erase previous contents
FillRect(pTargetDC->m_hDC,crTarget,(HBRUSH)(COLOR_WINDOW + 1));
CString Temp;
Temp.Format("crTarget %d,%d
%d,%d\n",crTarget.left,crTarget.top,crTarget.Width(),crTarget.Height());
TRACE(Temp);

// setup rectangles for metafile fiddling
CSize cTargetSize = crTarget.Size();
pTargetDC->DPtoHIMETRIC(&cTargetSize); // from MM_Text to MM_HIMETRIC
CSize TopLeft;
TopLeft.cx = crTarget.left;
TopLeft.cy = crTarget.top;
pTargetDC->DPtoHIMETRIC(&TopLeft); // from MM_Text to MM_HIMETRIC

CRect cHiMetricRect(0,0,cTargetSize.cx,cTargetSize.cy);
CRect cTwipsRect(0,0,(TWIPS_INCH * cTargetSize.cx + HIMETRIC_INCH / 2) /
HIMETRIC_INCH,
(TWIPS_INCH * cTargetSize.cy + HIMETRIC_INCH / 2) / HIMETRIC_INCH);

Temp.Format("MetaSize
%d,%d\n",cHiMetricRect.Width(),cHiMetricRect.Height());
TRACE(Temp);
Temp.Format("cTwipsRect %d,%d\n",cTwipsRect.Width(),cTwipsRect.Height());
TRACE(Temp);
// create the enhanced metafile
HDC hDCEMF = CreateEnhMetaFile(pTargetDC->m_hDC,NULL,cHiMetricRect,NULL);

// setup the format struct and do the RTF range formatting call
FORMATRANGE stFR;
stFR.hdcTarget = stFR.hdc = hDCEMF; // render to the memory helper EMF
stFR.rcPage = stFR.rc = cTwipsRect; // using this rectangle (in twips)
stFR.chrg.cpMin = 0; // and render all of the text
stFR.chrg.cpMax = -1;
GetDlgItem(IDC_RICHEDIT1)->SendMessage(EM_FORMATRANGE,TRUE,(LPARAM)
&stFR);
GetDlgItem(IDC_RICHEDIT1)->SendMessage(EM_FORMATRANGE,TRUE,NULL); // this
call clears the cache

// drawing into the metafile is done, get ourselves an handle to it (used
for the replay)
HENHMETAFILE hEMF = CloseEnhMetaFile(hDCEMF);

// calculate the automagic fudge factors by getting the device metrics
int nHorzSize = pTargetDC->GetDeviceCaps(HORZSIZE ); // width in
millimeters
int nVertSize = pTargetDC->GetDeviceCaps(VERTSIZE ); // height in
millimeters
int nHorzRes = pTargetDC->GetDeviceCaps(HORZRES ); // width in
pixels
int nVertRes = pTargetDC->GetDeviceCaps(VERTRES ); // height in
pixels
int nLogPixelsX = pTargetDC->GetDeviceCaps(LOGPIXELSX); // # of pixels
per inch horizontally
int nLogPixelsY = pTargetDC->GetDeviceCaps(LOGPIXELSY); // # of pixels
per inch vertically

float fHorzSizeInches = nHorzSize / 25.4f;
float fVertSizeInches = nVertSize / 25.4f;
float fHorzFudgeFactor = (nHorzRes / fHorzSizeInches) / nLogPixelsX; //
divide expected DPI with actual DPI
float fVertFudgeFactor = (nVertRes / fVertSizeInches) / nLogPixelsY; //

Temp.Format("Fudgfactor %.2f %.2f\n",fHorzFudgeFactor,fVertFudgeFactor);
TRACE(Temp);

// change from degrees to radians
// (also need to change sign since page space is upside down)
float fRotationInRadians = (PI * (0 - nRotationDegrees)) / 180.0F;

// do the world transforms, first apply the scale and fudge factors
XFORM stX;
ZeroMemory(&stX,sizeof(stX));
stX.eM11 = fHorzFudgeFactor * (nScalePercent / 100.0f);
stX.eM22 = fVertFudgeFactor * (nScalePercent / 100.0f);
SetWorldTransform(pTargetDC->m_hDC,&stX);

// then apply the rotation
ZeroMemory(&stX,sizeof(stX));
stX.eM11 = (float) cos(fRotationInRadians);
stX.eM12 = (float) sin(fRotationInRadians);
stX.eM21 = 0 - (float) sin(fRotationInRadians);
stX.eM22 = (float) cos(fRotationInRadians);
ModifyWorldTransform(pTargetDC->m_hDC,&stX,MWT_LEFTMULTIPLY);

// finally apply the horizontal and vertical shearing
ZeroMemory(&stX,sizeof(stX));
stX.eM11 = 1.0f;
stX.eM12 = nHorzShearPercent / 100.0f;
stX.eM21 = nVertShearPercent / 100.0f;
stX.eM22 = 1.0f;
ModifyWorldTransform(pTargetDC->m_hDC,&stX,MWT_LEFTMULTIPLY);

crTarget.OffsetRect(0,-20);
crTarget.OffsetRect(0,20 / (nScalePercent / 100.0f) * fVertFudgeFactor);
// play the metafile
pTargetDC->PlayMetaFile(hEMF,&crTarget);

// that's it, kiss the metafile goodbye
DeleteEnhMetaFile(hEMF);

// also show a legend
ModifyWorldTransform(pTargetDC->m_hDC,NULL,MWT_IDENTITY);
CString sLegend;
sLegend.Format("Scale: %d%% rotation: %dº horizontal shear: %d%%
vertical shear: %d%%.",
nScalePercent,nRotationDegrees,nHorzShearPercent,nVertShearPercent);
pTargetDC->SetTextColor(RGB(55,111,111));
pTargetDC->DrawText(sLegend,crTarget,DT_SINGLELINE | DT_VCENTER |
DT_CENTER);
}


Here is the C# code:

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
{
//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;
}
}

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();

//create a metafile, convert the size to himetrics
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();

//Calculate the area to render.
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; //Indicate character from
to character to
fmtRange.chrg.cpMin = 0;
fmtRange.hdc = hDCEMF; //Use the same DC for
measuring and rendering
fmtRange.hdcTarget = hDCEMF; //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);
SafeNativeMethods.SendMessage(this.Handle,
SafeNativeMethods.EM_FORMATRANGE, wParam, IntPtr.Zero);

//Free the block of memory allocated
Marshal.FreeCoTaskMem(lParam);

//Release the device context handle obtained by a previous call
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.X = layoutArea.Y = 0;
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);

[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 enum DeviceCap : int
{
/// <summary>
/// Device driver version
/// </summary>
DRIVERVERSION = 0,
/// <summary>
/// Device classification
/// </summary>
TECHNOLOGY = 2,
/// <summary>
/// Horizontal size in millimeters
/// </summary>
HORZSIZE = 4,
/// <summary>
/// Vertical size in millimeters
/// </summary>
VERTSIZE = 6,
/// <summary>
/// Horizontal width in pixels
/// </summary>
HORZRES = 8,
/// <summary>
/// Vertical height in pixels
/// </summary>
VERTRES = 10,
/// <summary>
/// Number of bits per pixel
/// </summary>
BITSPIXEL = 12,
/// <summary>
/// Number of planes
/// </summary>
PLANES = 14,
/// <summary>
/// Number of brushes the device has
/// </summary>
NUMBRUSHES = 16,
/// <summary>
/// Number of pens the device has
/// </summary>
NUMPENS = 18,
/// <summary>
/// Number of markers the device has
/// </summary>
NUMMARKERS = 20,
/// <summary>
/// Number of fonts the device has
/// </summary>
NUMFONTS = 22,
/// <summary>
/// Number of colors the device supports
/// </summary>
NUMCOLORS = 24,
/// <summary>
/// Size required for device descriptor
/// </summary>
PDEVICESIZE = 26,
/// <summary>
/// Curve capabilities
/// </summary>
CURVECAPS = 28,
/// <summary>
/// Line capabilities
/// </summary>
LINECAPS = 30,
/// <summary>
/// Polygonal capabilities
/// </summary>
POLYGONALCAPS = 32,
/// <summary>
/// Text capabilities
/// </summary>
TEXTCAPS = 34,
/// <summary>
/// Clipping capabilities
/// </summary>
CLIPCAPS = 36,
/// <summary>
/// Bitblt capabilities
/// </summary>
RASTERCAPS = 38,
/// <summary>
/// Length of the X leg
/// </summary>
ASPECTX = 40,
/// <summary>
/// Length of the Y leg
/// </summary>
ASPECTY = 42,
/// <summary>
/// Length of the hypotenuse
/// </summary>
ASPECTXY = 44,
/// <summary>
/// Shading and Blending caps
/// </summary>
SHADEBLENDCAPS = 45,

/// <summary>
/// Logical pixels inch in X
/// </summary>
LOGPIXELSX = 88,
/// <summary>
/// Logical pixels inch in Y
/// </summary>
LOGPIXELSY = 90,

/// <summary>
/// Number of entries in physical palette
/// </summary>
SIZEPALETTE = 104,
/// <summary>
/// Number of reserved entries in palette
/// </summary>
NUMRESERVED = 106,
/// <summary>
/// Actual color resolution
/// </summary>
COLORRES = 108,

// Printing related DeviceCaps. These replace the
appropriate Escapes
/// <summary>
/// Physical Width in device units
/// </summary>
PHYSICALWIDTH = 110,
/// <summary>
/// Physical Height in device units
/// </summary>
PHYSICALHEIGHT = 111,
/// <summary>
/// Physical Printable Area x margin
/// </summary>
PHYSICALOFFSETX = 112,
/// <summary>
/// Physical Printable Area y margin
/// </summary>
PHYSICALOFFSETY = 113,
/// <summary>
/// Scaling factor x
/// </summary>
SCALINGFACTORX = 114,
/// <summary>
/// Scaling factor y
/// </summary>
SCALINGFACTORY = 115,

/// <summary>
/// Current vertical refresh rate of the display device
(for displays only) in Hz
/// </summary>
VREFRESH = 116,
/// <summary>
/// Horizontal width of entire desktop in pixels
/// </summary>
DESKTOPVERTRES = 117,
/// <summary>
/// Vertical height of entire desktop in pixels
/// </summary>
DESKTOPHORZRES = 118,
/// <summary>
/// Preferred blt alignment
/// </summary>
BLTALIGNMENT = 119
}


public const int WM_USER = 0x0400;
public const int EM_FORMATRANGE = WM_USER + 57;
public const int WS_EX_TRANSPARENT = 0x20;

}
#endregion
}
}
 
I setup another machine with Vista 64 and it is happening there too. So it
looks like Vista 64 is the problem!

AliR.

AliR (VC++ MVP) said:
Let me also mention that the laptop that is having the funny results is
running Vista 64, the other machines which everything works fine on is
running Vista 32 or XP.

AliR.


AliR (VC++ MVP) said:
I'm trying to write a RTF render code in C#. I have the code in C++/MFC
and it works fine, but I have run into a problem with the C# code. I
think the C# code is from Microsoft, and I added scaling to it. The C#
code is working fine on my desktop PC but it cuts off some of the text
when I run it on my laptop. The MFC code works fine both on the laptop
and the PC. I have looked at all the numbers used in the MFC and the C#
code and they are identical. Both PC and Laptop are at 1440x900 96dpi
font size.

I have been looking at the code for 3 or 4 days now without any
improvment. Was wondering if anyone here wants to take a stab at it.

You can download both sample projects:
http://www.learnstar.com/AliR/RTFScaler.zip
http://www.learnstar.com/AliR/RTFScalerMFC.zip


Thanks
AliR.


Here is the MFC code
// *** copying/scaling/rotating and shearing the text is done here
void CRTFScalerDlg::RenderText(int nScalePercent,int nRotationDegrees,int
nHorzShearPercent,int nVertShearPercent)
{
// validate the arguments
if (nScalePercent < 1)
nScalePercent = 1;
if (nScalePercent > 10000)
nScalePercent = 10000;
if (nRotationDegrees < 0)
nRotationDegrees = 0;
if (nRotationDegrees > 360)
nRotationDegrees = 360;
if (nHorzShearPercent < 0)
nHorzShearPercent = 0;
if (nHorzShearPercent > 100)
nHorzShearPercent = 100;
if (nVertShearPercent < 0)
nVertShearPercent = 0;
if (nVertShearPercent > 100)
nVertShearPercent = 100;

// setup target window, rect and DC
CWnd* pTargetWin = GetDlgItem(IDC_EDIT1);
CRect crTarget;
pTargetWin->GetClientRect(&crTarget);
crTarget.OffsetRect(0,20);
CDC* pTargetDC = pTargetWin->GetDC();
pTargetDC->IntersectClipRect(&crTarget); // so we don't clobber the
parent dialog
pTargetDC->SetBkMode(TRANSPARENT); // so the legend doesn't erase too
much

// also need advanced graphics mode for the world transform stuff
if (!SetGraphicsMode(pTargetDC->m_hDC,GM_ADVANCED))
{
pTargetDC->DrawText("Nice try but I need Windows NT, 2000, XP or 2003
for this.",crTarget,DT_SINGLELINE | DT_VCENTER | DT_CENTER);
return;
}

// erase previous contents
FillRect(pTargetDC->m_hDC,crTarget,(HBRUSH)(COLOR_WINDOW + 1));
CString Temp;
Temp.Format("crTarget %d,%d
%d,%d\n",crTarget.left,crTarget.top,crTarget.Width(),crTarget.Height());
TRACE(Temp);

// setup rectangles for metafile fiddling
CSize cTargetSize = crTarget.Size();
pTargetDC->DPtoHIMETRIC(&cTargetSize); // from MM_Text to MM_HIMETRIC
CSize TopLeft;
TopLeft.cx = crTarget.left;
TopLeft.cy = crTarget.top;
pTargetDC->DPtoHIMETRIC(&TopLeft); // from MM_Text to MM_HIMETRIC

CRect cHiMetricRect(0,0,cTargetSize.cx,cTargetSize.cy);
CRect cTwipsRect(0,0,(TWIPS_INCH * cTargetSize.cx + HIMETRIC_INCH / 2) /
HIMETRIC_INCH,
(TWIPS_INCH * cTargetSize.cy + HIMETRIC_INCH / 2) / HIMETRIC_INCH);

Temp.Format("MetaSize
%d,%d\n",cHiMetricRect.Width(),cHiMetricRect.Height());
TRACE(Temp);
Temp.Format("cTwipsRect %d,%d\n",cTwipsRect.Width(),cTwipsRect.Height());
TRACE(Temp);
// create the enhanced metafile
HDC hDCEMF = CreateEnhMetaFile(pTargetDC->m_hDC,NULL,cHiMetricRect,NULL);

// setup the format struct and do the RTF range formatting call
FORMATRANGE stFR;
stFR.hdcTarget = stFR.hdc = hDCEMF; // render to the memory helper EMF
stFR.rcPage = stFR.rc = cTwipsRect; // using this rectangle (in
twips)
stFR.chrg.cpMin = 0; // and render all of the text
stFR.chrg.cpMax = -1;
GetDlgItem(IDC_RICHEDIT1)->SendMessage(EM_FORMATRANGE,TRUE,(LPARAM)
&stFR);
GetDlgItem(IDC_RICHEDIT1)->SendMessage(EM_FORMATRANGE,TRUE,NULL); // this
call clears the cache

// drawing into the metafile is done, get ourselves an handle to it (used
for the replay)
HENHMETAFILE hEMF = CloseEnhMetaFile(hDCEMF);

// calculate the automagic fudge factors by getting the device metrics
int nHorzSize = pTargetDC->GetDeviceCaps(HORZSIZE ); // width in
millimeters
int nVertSize = pTargetDC->GetDeviceCaps(VERTSIZE ); // height in
millimeters
int nHorzRes = pTargetDC->GetDeviceCaps(HORZRES ); // width in
pixels
int nVertRes = pTargetDC->GetDeviceCaps(VERTRES ); // height in
pixels
int nLogPixelsX = pTargetDC->GetDeviceCaps(LOGPIXELSX); // # of pixels
per inch horizontally
int nLogPixelsY = pTargetDC->GetDeviceCaps(LOGPIXELSY); // # of pixels
per inch vertically

float fHorzSizeInches = nHorzSize / 25.4f;
float fVertSizeInches = nVertSize / 25.4f;
float fHorzFudgeFactor = (nHorzRes / fHorzSizeInches) / nLogPixelsX; //
divide expected DPI with actual DPI
float fVertFudgeFactor = (nVertRes / fVertSizeInches) / nLogPixelsY; //

Temp.Format("Fudgfactor %.2f %.2f\n",fHorzFudgeFactor,fVertFudgeFactor);
TRACE(Temp);

// change from degrees to radians
// (also need to change sign since page space is upside down)
float fRotationInRadians = (PI * (0 - nRotationDegrees)) / 180.0F;

// do the world transforms, first apply the scale and fudge factors
XFORM stX;
ZeroMemory(&stX,sizeof(stX));
stX.eM11 = fHorzFudgeFactor * (nScalePercent / 100.0f);
stX.eM22 = fVertFudgeFactor * (nScalePercent / 100.0f);
SetWorldTransform(pTargetDC->m_hDC,&stX);

// then apply the rotation
ZeroMemory(&stX,sizeof(stX));
stX.eM11 = (float) cos(fRotationInRadians);
stX.eM12 = (float) sin(fRotationInRadians);
stX.eM21 = 0 - (float) sin(fRotationInRadians);
stX.eM22 = (float) cos(fRotationInRadians);
ModifyWorldTransform(pTargetDC->m_hDC,&stX,MWT_LEFTMULTIPLY);

// finally apply the horizontal and vertical shearing
ZeroMemory(&stX,sizeof(stX));
stX.eM11 = 1.0f;
stX.eM12 = nHorzShearPercent / 100.0f;
stX.eM21 = nVertShearPercent / 100.0f;
stX.eM22 = 1.0f;
ModifyWorldTransform(pTargetDC->m_hDC,&stX,MWT_LEFTMULTIPLY);

crTarget.OffsetRect(0,-20);
crTarget.OffsetRect(0,20 / (nScalePercent / 100.0f) * fVertFudgeFactor);
// play the metafile
pTargetDC->PlayMetaFile(hEMF,&crTarget);

// that's it, kiss the metafile goodbye
DeleteEnhMetaFile(hEMF);

// also show a legend
ModifyWorldTransform(pTargetDC->m_hDC,NULL,MWT_IDENTITY);
CString sLegend;
sLegend.Format("Scale: %d%% rotation: %dº horizontal shear: %d%%
vertical shear: %d%%.",
nScalePercent,nRotationDegrees,nHorzShearPercent,nVertShearPercent);
pTargetDC->SetTextColor(RGB(55,111,111));
pTargetDC->DrawText(sLegend,crTarget,DT_SINGLELINE | DT_VCENTER |
DT_CENTER);
}


Here is the C# code:

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
{
//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;
}
}

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();

//create a metafile, convert the size to himetrics
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();

//Calculate the area to render.
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; //Indicate character from
to character to
fmtRange.chrg.cpMin = 0;
fmtRange.hdc = hDCEMF; //Use the same DC for
measuring and rendering
fmtRange.hdcTarget = hDCEMF; //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);
SafeNativeMethods.SendMessage(this.Handle,
SafeNativeMethods.EM_FORMATRANGE, wParam, IntPtr.Zero);

//Free the block of memory allocated
Marshal.FreeCoTaskMem(lParam);

//Release the device context handle obtained by a previous
call
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.X = layoutArea.Y = 0;
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);

[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 enum DeviceCap : int
{
/// <summary>
/// Device driver version
/// </summary>
DRIVERVERSION = 0,
/// <summary>
/// Device classification
/// </summary>
TECHNOLOGY = 2,
/// <summary>
/// Horizontal size in millimeters
/// </summary>
HORZSIZE = 4,
/// <summary>
/// Vertical size in millimeters
/// </summary>
VERTSIZE = 6,
/// <summary>
/// Horizontal width in pixels
/// </summary>
HORZRES = 8,
/// <summary>
/// Vertical height in pixels
/// </summary>
VERTRES = 10,
/// <summary>
/// Number of bits per pixel
/// </summary>
BITSPIXEL = 12,
/// <summary>
/// Number of planes
/// </summary>
PLANES = 14,
/// <summary>
/// Number of brushes the device has
/// </summary>
NUMBRUSHES = 16,
/// <summary>
/// Number of pens the device has
/// </summary>
NUMPENS = 18,
/// <summary>
/// Number of markers the device has
/// </summary>
NUMMARKERS = 20,
/// <summary>
/// Number of fonts the device has
/// </summary>
NUMFONTS = 22,
/// <summary>
/// Number of colors the device supports
/// </summary>
NUMCOLORS = 24,
/// <summary>
/// Size required for device descriptor
/// </summary>
PDEVICESIZE = 26,
/// <summary>
/// Curve capabilities
/// </summary>
CURVECAPS = 28,
/// <summary>
/// Line capabilities
/// </summary>
LINECAPS = 30,
/// <summary>
/// Polygonal capabilities
/// </summary>
POLYGONALCAPS = 32,
/// <summary>
/// Text capabilities
/// </summary>
TEXTCAPS = 34,
/// <summary>
/// Clipping capabilities
/// </summary>
CLIPCAPS = 36,
/// <summary>
/// Bitblt capabilities
/// </summary>
RASTERCAPS = 38,
/// <summary>
/// Length of the X leg
/// </summary>
ASPECTX = 40,
/// <summary>
/// Length of the Y leg
/// </summary>
ASPECTY = 42,
/// <summary>
/// Length of the hypotenuse
/// </summary>
ASPECTXY = 44,
/// <summary>
/// Shading and Blending caps
/// </summary>
SHADEBLENDCAPS = 45,

/// <summary>
/// Logical pixels inch in X
/// </summary>
LOGPIXELSX = 88,
/// <summary>
/// Logical pixels inch in Y
/// </summary>
LOGPIXELSY = 90,

/// <summary>
/// Number of entries in physical palette
/// </summary>
SIZEPALETTE = 104,
/// <summary>
/// Number of reserved entries in palette
/// </summary>
NUMRESERVED = 106,
/// <summary>
/// Actual color resolution
/// </summary>
COLORRES = 108,

// Printing related DeviceCaps. These replace the
appropriate Escapes
/// <summary>
/// Physical Width in device units
/// </summary>
PHYSICALWIDTH = 110,
/// <summary>
/// Physical Height in device units
/// </summary>
PHYSICALHEIGHT = 111,
/// <summary>
/// Physical Printable Area x margin
/// </summary>
PHYSICALOFFSETX = 112,
/// <summary>
/// Physical Printable Area y margin
/// </summary>
PHYSICALOFFSETY = 113,
/// <summary>
/// Scaling factor x
/// </summary>
SCALINGFACTORX = 114,
/// <summary>
/// Scaling factor y
/// </summary>
SCALINGFACTORY = 115,

/// <summary>
/// Current vertical refresh rate of the display device
(for displays only) in Hz
/// </summary>
VREFRESH = 116,
/// <summary>
/// Horizontal width of entire desktop in pixels
/// </summary>
DESKTOPVERTRES = 117,
/// <summary>
/// Vertical height of entire desktop in pixels
/// </summary>
DESKTOPHORZRES = 118,
/// <summary>
/// Preferred blt alignment
/// </summary>
BLTALIGNMENT = 119
}


public const int WM_USER = 0x0400;
public const int EM_FORMATRANGE = WM_USER + 57;
public const int WS_EX_TRANSPARENT = 0x20;

}
#endregion
}
}
 
Hi!

Great article! Since RichtextBox.DrawToBitmap() seems not to be working correctly I wonder if there is a proper implementation for displaying/drawing richtext by something like Graphics.DrawStringRTF().
I have done quite a little bit of research - there are many solutions out there but they all have major shortcomings.

1. copy richtextBox content to a bitmap works - but without scaling/zooming which is essential for me! Scaling this bitmap results in bad resolution/quality
Example: http://www.andrewvos.com/?p=392[^]
-> no option.

2. RichtextBox.DrawToBitmap() seems not to work -> i am compiling to .net framework 2.0, does anyone know if its better on 3.0 or 3.5? -> no option with 2.0!

3. commercial / open source 3rd party rendering? I found something on ComponentOne but it was only for PDF-printing -> no option!

If nothing helps i have to write a renderer by myself -> not a good perspective since MS could fix this error by correcting RichttextBox.DrawToBitmap() with a few keystrokes..

Any ideas?

Thx martin



AliR \(VC++ MVP\) wrote:

I setup another machine with Vista 64 and it is happening there too.
28-Oct-08

I setup another machine with Vista 64 and it is happening there too. So i
looks like Vista 64 is the problem

AliR.

Previous Posts In This Thread:

RTF Render with Scale
I'm trying to write a RTF render code in C#. I have the code in C++/MFC and
it works fine, but I have run into a problem with the C# code. I think the
C# code is from Microsoft, and I added scaling to it. The C# code is
working fine on my desktop PC but it cuts off some of the text when I run it
on my laptop. The MFC code works fine both on the laptop and the PC. I
have looked at all the numbers used in the MFC and the C# code and they are
identical. Both PC and Laptop are at 1440x900 96dpi font size

I have been looking at the code for 3 or 4 days now without any improvment.
Was wondering if anyone here wants to take a stab at it

You can download both sample projects
http://www.learnstar.com/AliR/RTFScaler.zi
http://www.learnstar.com/AliR/RTFScalerMFC.zi

Thank
AliR

Here is the MFC cod
// *** copying/scaling/rotating and shearing the text is done her
void CRTFScalerDlg::RenderText(int nScalePercent,int nRotationDegrees,int
nHorzShearPercent,int nVertShearPercent

// validate the argument
if (nScalePercent < 1
nScalePercent = 1
if (nScalePercent > 10000
nScalePercent = 10000
if (nRotationDegrees < 0
nRotationDegrees = 0
if (nRotationDegrees > 360
nRotationDegrees = 360
if (nHorzShearPercent < 0
nHorzShearPercent = 0
if (nHorzShearPercent > 100
nHorzShearPercent = 100
if (nVertShearPercent < 0
nVertShearPercent = 0
if (nVertShearPercent > 100
nVertShearPercent = 100

// setup target window, rect and D
CWnd* pTargetWin = GetDlgItem(IDC_EDIT1)
CRect crTarget
pTargetWin->GetClientRect(&crTarget)
crTarget.OffsetRect(0,20)
CDC* pTargetDC = pTargetWin->GetDC()
pTargetDC->IntersectClipRect(&crTarget); // so we don't clobber the parent
dialo
pTargetDC->SetBkMode(TRANSPARENT); // so the legend doesn't erase too
muc

// also need advanced graphics mode for the world transform stuf
if (!SetGraphicsMode(pTargetDC->m_hDC,GM_ADVANCED)

pTargetDC->DrawText("Nice try but I need Windows NT, 2000, XP or 2003 for
this.",crTarget,DT_SINGLELINE | DT_VCENTER | DT_CENTER)
return


// erase previous content
FillRect(pTargetDC->m_hDC,crTarget,(HBRUSH)(COLOR_WINDOW + 1))
CString Temp
Temp.Format("crTarget %d,%d
%d,%d\n",crTarget.left,crTarget.top,crTarget.Width(),crTarget.Height())
TRACE(Temp)

// setup rectangles for metafile fiddlin
CSize cTargetSize = crTarget.Size()
pTargetDC->DPtoHIMETRIC(&cTargetSize); // from MM_Text to MM_HIMETRI
CSize TopLeft
TopLeft.cx = crTarget.left
TopLeft.cy = crTarget.top
pTargetDC->DPtoHIMETRIC(&TopLeft); // from MM_Text to MM_HIMETRI

CRect cHiMetricRect(0,0,cTargetSize.cx,cTargetSize.cy)
CRect cTwipsRect(0,0,(TWIPS_INCH * cTargetSize.cx + HIMETRIC_INCH / 2) /
HIMETRIC_INCH,
(TWIPS_INCH * cTargetSize.cy + HIMETRIC_INCH / 2) / HIMETRIC_INCH);

Temp.Format("MetaSize
%d,%d\n",cHiMetricRect.Width(),cHiMetricRect.Height());
TRACE(Temp);
Temp.Format("cTwipsRect %d,%d\n",cTwipsRect.Width(),cTwipsRect.Height());
TRACE(Temp);
// create the enhanced metafile
HDC hDCEMF = CreateEnhMetaFile(pTargetDC->m_hDC,NULL,cHiMetricRect,NULL);

// setup the format struct and do the RTF range formatting call
FORMATRANGE stFR;
stFR.hdcTarget = stFR.hdc = hDCEMF; // render to the memory helper EMF
stFR.rcPage = stFR.rc = cTwipsRect; // using this rectangle (in twips)
stFR.chrg.cpMin = 0; // and render all of the text
stFR.chrg.cpMax = -1;
GetDlgItem(IDC_RICHEDIT1)->SendMessage(EM_FORMATRANGE,TRUE,(LPARAM) &stFR);
GetDlgItem(IDC_RICHEDIT1)->SendMessage(EM_FORMATRANGE,TRUE,NULL); // this
call clears the cache

// drawing into the metafile is done, get ourselves an handle to it (used
for the replay)
HENHMETAFILE hEMF = CloseEnhMetaFile(hDCEMF);

// calculate the automagic fudge factors by getting the device metrics
int nHorzSize = pTargetDC->GetDeviceCaps(HORZSIZE ); // width in
millimeters
int nVertSize = pTargetDC->GetDeviceCaps(VERTSIZE ); // height in
millimeters
int nHorzRes = pTargetDC->GetDeviceCaps(HORZRES ); // width in pixels
int nVertRes = pTargetDC->GetDeviceCaps(VERTRES ); // height in
pixels
int nLogPixelsX = pTargetDC->GetDeviceCaps(LOGPIXELSX); // # of pixels per
inch horizontally
int nLogPixelsY = pTargetDC->GetDeviceCaps(LOGPIXELSY); // # of pixels per
inch vertically

float fHorzSizeInches = nHorzSize / 25.4f;
float fVertSizeInches = nVertSize / 25.4f;
float fHorzFudgeFactor = (nHorzRes / fHorzSizeInches) / nLogPixelsX; //
divide expected DPI with actual DPI
float fVertFudgeFactor = (nVertRes / fVertSizeInches) / nLogPixelsY; //

Temp.Format("Fudgfactor %.2f %.2f\n",fHorzFudgeFactor,fVertFudgeFactor);
TRACE(Temp);

// change from degrees to radians
// (also need to change sign since page space is upside down)
float fRotationInRadians = (PI * (0 - nRotationDegrees)) / 180.0F;

// do the world transforms, first apply the scale and fudge factors
XFORM stX;
ZeroMemory(&stX,sizeof(stX));
stX.eM11 = fHorzFudgeFactor * (nScalePercent / 100.0f);
stX.eM22 = fVertFudgeFactor * (nScalePercent / 100.0f);
SetWorldTransform(pTargetDC->m_hDC,&stX);

// then apply the rotation
ZeroMemory(&stX,sizeof(stX));
stX.eM11 = (float) cos(fRotationInRadians);
stX.eM12 = (float) sin(fRotationInRadians);
stX.eM21 = 0 - (float) sin(fRotationInRadians);
stX.eM22 = (float) cos(fRotationInRadians);
ModifyWorldTransform(pTargetDC->m_hDC,&stX,MWT_LEFTMULTIPLY);

// finally apply the horizontal and vertical shearing
ZeroMemory(&stX,sizeof(stX));
stX.eM11 = 1.0f;
stX.eM12 = nHorzShearPercent / 100.0f;
stX.eM21 = nVertShearPercent / 100.0f;
stX.eM22 = 1.0f;
ModifyWorldTransform(pTargetDC->m_hDC,&stX,MWT_LEFTMULTIPLY);

crTarget.OffsetRect(0,-20);
crTarget.OffsetRect(0,20 / (nScalePercent / 100.0f) * fVertFudgeFactor);
// play the metafile
pTargetDC->PlayMetaFile(hEMF,&crTarget);

// that's it, kiss the metafile goodbye
DeleteEnhMetaFile(hEMF);

// also show a legend
ModifyWorldTransform(pTargetDC->m_hDC,NULL,MWT_IDENTITY);
CString sLegend;
sLegend.Format("Scale: %d%% rotation: %d? horizontal shear: %d%%
vertical shear: %d%%.",
nScalePercent,nRotationDegrees,nHorzShearPercent,nVertShearPercent);
pTargetDC->SetTextColor(RGB(55,111,111));
pTargetDC->DrawText(sLegend,crTarget,DT_SINGLELINE | DT_VCENTER |
DT_CENTER);
}


Here is the C# code:

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
{
//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;
}
}

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();

//create a metafile, convert the size to himetrics
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();

//Calculate the area to render.
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; //Indicate character from
to character to
fmtRange.chrg.cpMin = 0;
fmtRange.hdc = hDCEMF; //Use the same DC for
measuring and rendering
fmtRange.hdcTarget = hDCEMF; //Point at printer hDC
fmtRange.rc = rectLayoutArea; //Indicate the area on page
to print
fmtRange.rcPage = rectLayoutArea; //Indicate size of pag

IntPtr wParam = IntPtr.Zero
wParam = new IntPtr(1)

//Get the pointer to the FORMATRANGE structure in memor
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)

//Free the block of memory allocate
Marshal.FreeCoTaskMem(lParam)

//Release the device context handle obtained by a previous cal
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.X = layoutArea.Y = 0
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 SafeNativeMethod
private static class SafeNativeMethod

[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)

[StructLayout(LayoutKind.Sequential)
public struct REC

public int Left
public int Top
public int Right
public int Bottom


[StructLayout(LayoutKind.Sequential)
public struct CHARRANG

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 FORMATRANG

public IntPtr hdc; //Actual DC to draw o
public IntPtr hdcTarget; //Target DC for determining text
formattin
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 enum DeviceCap : int
{
/// <summary>
/// Device driver version
/// </summary>
DRIVERVERSION = 0,
/// <summary>
/// Device classification
/// </summary>
TECHNOLOGY = 2,
/// <summary>
/// Horizontal size in millimeters
/// </summary>
HORZSIZE = 4,
/// <summary>
/// Vertical size in millimeters
/// </summary>
VERTSIZE = 6,
/// <summary>
/// Horizontal width in pixels
/// </summary>
HORZRES = 8,
/// <summary>
/// Vertical height in pixels
/// </summary>
VERTRES = 10,
/// <summary>
/// Number of bits per pixel
/// </summary>
BITSPIXEL = 12,
/// <summary>
/// Number of planes
/// </summary>
PLANES = 14,
/// <summary>
/// Number of brushes the device has
/// </summary>
NUMBRUSHES = 16,
/// <summary>
/// Number of pens the device has
/// </summary>
NUMPENS = 18,
/// <summary>
/// Number of markers the device has
/// </summary>
NUMMARKERS = 20,
/// <summary>
/// Number of fonts the device has
/// </summary>
NUMFONTS = 22,
/// <summary>
/// Number of colors the device supports
/// </summary>
NUMCOLORS = 24,
/// <summary>
/// Size required for device descriptor
/// </summary>
PDEVICESIZE = 26,
/// <summary>
/// Curve capabilities
/// </summary>
CURVECAPS = 28,
/// <summary>
/// Line capabilities
/// </summary>
LINECAPS = 30,
/// <summary>
/// Polygonal capabilities
/// </summary>
POLYGONALCAPS = 32,
/// <summary>
/// Text capabilities
/// </summary>
TEXTCAPS = 34,
/// <summary>
/// Clipping capabilities
/// </summary>
CLIPCAPS = 36,
/// <summary>
/// Bitblt capabilities
/// </summary>
RASTERCAPS = 38,
/// <summary>
/// Length of the X leg
/// </summary>
ASPECTX = 40,
/// <summary>
/// Length of the Y leg
/// </summary>
ASPECTY = 42,
/// <summary>
/// Length of the hypotenuse
/// </summary>
ASPECTXY = 44,
/// <summary>
/// Shading and Blending caps
/// </summary>
SHADEBLENDCAPS = 45,

/// <summary>
/// Logical pixels inch in X
/// </summary>
LOGPIXELSX = 88,
/// <summary>
/// Logical pixels inch in Y
/// </summary>
LOGPIXELSY = 90,

/// <summary>
/// Number of entries in physical palette
/// </summary>
SIZEPALETTE = 104,
/// <summary>
/// Number of reserved entries in palette
/// </summary>
NUMRESERVED = 106,
/// <summary>
/// Actual color resolution
/// </summary>
COLORRES = 108,

// Printing related DeviceCaps. These replace the
appropriate Escapes
/// <summary>
/// Physical Width in device units
/// </summary>
PHYSICALWIDTH = 110,
/// <summary>
/// Physical Height in device units
/// </summary>
PHYSICALHEIGHT = 111,
/// <summary>
/// Physical Printable Area x margin
/// </summary>
PHYSICALOFFSETX = 112,
/// <summary>
/// Physical Printable Area y margin
/// </summary>
PHYSICALOFFSETY = 113,
/// <summary>
/// Scaling factor x
/// </summary>
SCALINGFACTORX = 114,
/// <summary>
/// Scaling factor y
/// </summary>
SCALINGFACTORY = 115,

/// <summary>
/// Current vertical refresh rate of the display device (for
displays only) in Hz
/// </summary>
VREFRESH = 116,
/// <summary>
/// Horizontal width of entire desktop in pixels
/// </summary>
DESKTOPVERTRES = 117,
/// <summary>
/// Vertical height of entire desktop in pixels
/// </summary>
DESKTOPHORZRES = 118,
/// <summary>
/// Preferred blt alignment
/// </summary>
BLTALIGNMENT = 119
}


public const int WM_USER = 0x0400;
public const int EM_FORMATRANGE = WM_USER + 57;
public const int WS_EX_TRANSPARENT = 0x20;

}
#endregion
}
}

Let me also mention that the laptop that is having the funny results is
Let me also mention that the laptop that is having the funny results is
running Vista 64, the other machines which everything works fine on is
running Vista 32 or XP.

AliR.

I setup another machine with Vista 64 and it is happening there too.
I setup another machine with Vista 64 and it is happening there too. So it
looks like Vista 64 is the problem!

AliR.


Submitted via EggHeadCafe - Software Developer Portal of Choice
DataContractSerializer Basics
http://www.eggheadcafe.com/tutorial...c-94d2f3b1b265/datacontractserializer-ba.aspx
 
Back
Top