467,135 Members | 1,220 Online
Bytes | Developer Community
Ask Question

Home New Posts Topics Members FAQ

Post your question to a community of 467,135 developers. It's quick & easy.

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.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.Heigh t());
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,n VertShearPercent);
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.Bot tom));

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
}
}

Oct 27 '08 #1
  • viewed: 5033
Share:
2 Replies
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)" <Al**@online.nospamwrote in message
news:pq****************@nlpi068.nbdc.sbc.com...
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.Heigh t());
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,n VertShearPercent);
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.Bot tom));

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
}
}

Oct 28 '08 #2
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)" <Al**@online.nospamwrote in message
news:5c****************@flpi144.ffdc.sbc.com...
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)" <Al**@online.nospamwrote in message
news:pq****************@nlpi068.nbdc.sbc.com...
>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.Widt h(),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.Heig ht());
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,n VertShearPercent);
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.Bo ttom));

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
}
}


Oct 28 '08 #3

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

2 posts views Thread by John Fouhy | last post: by
4 posts views Thread by codecraig | last post: by
5 posts views Thread by Guess | last post: by
3 posts views Thread by Jerry Spence1 | last post: by
reply views Thread by TonyJ | last post: by
19 posts views Thread by Matteo Migliore | last post: by
22 posts views Thread by Jesse Burns | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.