473,804 Members | 3,067 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

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,i nt nRotationDegree s,int
nHorzShearPerce nt,int nVertShearPerce nt)
{
// validate the arguments
if (nScalePercent < 1)
nScalePercent = 1;
if (nScalePercent 10000)
nScalePercent = 10000;
if (nRotationDegre es < 0)
nRotationDegree s = 0;
if (nRotationDegre es 360)
nRotationDegree s = 360;
if (nHorzShearPerc ent < 0)
nHorzShearPerce nt = 0;
if (nHorzShearPerc ent 100)
nHorzShearPerce nt = 100;
if (nVertShearPerc ent < 0)
nVertShearPerce nt = 0;
if (nVertShearPerc ent 100)
nVertShearPerce nt = 100;

// setup target window, rect and DC
CWnd* pTargetWin = GetDlgItem(IDC_ EDIT1);
CRect crTarget;
pTargetWin->GetClientRect( &crTarget);
crTarget.Offset Rect(0,20);
CDC* pTargetDC = pTargetWin->GetDC();
pTargetDC->IntersectClipR ect(&crTarget); // so we don't clobber the parent
dialog
pTargetDC->SetBkMode(TRAN SPARENT); // so the legend doesn't erase too
much

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

// erase previous contents
FillRect(pTarge tDC->m_hDC,crTarget ,(HBRUSH)(COLOR _WINDOW + 1));
CString Temp;
Temp.Format("cr Target %d,%d
%d,%d\n",crTarg et.left,crTarge t.top,crTarget. Width(),crTarge t.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("Me taSize
%d,%d\n",cHiMet ricRect.Width() ,cHiMetricRect. Height());
TRACE(Temp);
Temp.Format("cT wipsRect %d,%d\n",cTwips Rect.Width(),cT wipsRect.Height ());
TRACE(Temp);
// create the enhanced metafile
HDC hDCEMF = CreateEnhMetaFi le(pTargetDC->m_hDC,NULL,cHi MetricRect,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,TR UE,(LPARAM) &stFR);
GetDlgItem(IDC_ RICHEDIT1)->SendMessage(EM _FORMATRANGE,TR UE,NULL); // this
call clears the cache

// drawing into the metafile is done, get ourselves an handle to it (used
for the replay)
HENHMETAFILE hEMF = CloseEnhMetaFil e(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 fHorzFudgeFacto r = (nHorzRes / fHorzSizeInches ) / nLogPixelsX; //
divide expected DPI with actual DPI
float fVertFudgeFacto r = (nVertRes / fVertSizeInches ) / nLogPixelsY; //

Temp.Format("Fu dgfactor %.2f %.2f\n",fHorzFu dgeFactor,fVert FudgeFactor);
TRACE(Temp);

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

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

// then apply the rotation
ZeroMemory(&stX ,sizeof(stX));
stX.eM11 = (float) cos(fRotationIn Radians);
stX.eM12 = (float) sin(fRotationIn Radians);
stX.eM21 = 0 - (float) sin(fRotationIn Radians);
stX.eM22 = (float) cos(fRotationIn Radians);
ModifyWorldTran sform(pTargetDC->m_hDC,&stX,MWT _LEFTMULTIPLY);

// finally apply the horizontal and vertical shearing
ZeroMemory(&stX ,sizeof(stX));
stX.eM11 = 1.0f;
stX.eM12 = nHorzShearPerce nt / 100.0f;
stX.eM21 = nVertShearPerce nt / 100.0f;
stX.eM22 = 1.0f;
ModifyWorldTran sform(pTargetDC->m_hDC,&stX,MWT _LEFTMULTIPLY);

crTarget.Offset Rect(0,-20);
crTarget.Offset Rect(0,20 / (nScalePercent / 100.0f) * fVertFudgeFacto r);
// play the metafile
pTargetDC->PlayMetaFile(h EMF,&crTarget);

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

// also show a legend
ModifyWorldTran sform(pTargetDC->m_hDC,NULL,MWT _IDENTITY);
CString sLegend;
sLegend.Format( "Scale: %d%% rotation: %dº horizontal shear: %d%%
vertical shear: %d%%.",
nScalePercent,n RotationDegrees ,nHorzShearPerc ent,nVertShearP ercent);
pTargetDC->SetTextColor(R GB(55,111,111)) ;
pTargetDC->DrawText(sLege nd,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_DrawRt fText
{
private static RichTextBoxDraw er rtfDrawer;
public static void DrawRtfText(thi s Graphics graphics, string rtf,
RectangleF layoutArea,floa t xFactor)
{
if (Graphics_DrawR tfText.rtfDrawe r == null)
{
Graphics_DrawRt fText.rtfDrawer = new RichTextBoxDraw er();
}
Graphics_DrawRt fText.rtfDrawer .Rtf = rtf;
Graphics_DrawRt fText.rtfDrawer .Draw(graphics, layoutArea,xFac tor);
}

private class RichTextBoxDraw er : 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.CreatePara ms;
if (SafeNativeMeth ods.LoadLibrary ("msftedit.dll" ) !=
IntPtr.Zero)
{
createParams.Ex Style |=
SafeNativeMetho ds.WS_EX_TRANSP ARENT; // transparent
createParams.Cl assName = "RICHEDIT50 W";
}
return createParams;
}
}

private void DPToHIMETRIC(Gr aphics 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.Diagnost ics.Debug.Write Line("LayoutAre a " + layoutArea);

SizeF metaSize = layoutArea.Size ;
DPToHIMETRIC(gr aphics, ref metaSize);

System.Diagnost ics.Debug.Write Line("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.Releas eHdc(hdc);

Graphics g = Graphics.FromIm age(metafile);
IntPtr hDCEMF = g.GetHdc();

//Calculate the area to render.
SafeNativeMetho ds.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.Diagnost ics.Debug.Write Line(String.For mat("RectLayout Area
({0},{1})",rect LayoutArea.Righ t,rectLayoutAre a.Bottom));

SafeNativeMetho ds.FORMATRANGE fmtRange;
fmtRange.chrg.c pMax = -1; //Indicate character from
to character to
fmtRange.chrg.c pMin = 0;
fmtRange.hdc = hDCEMF; //Use the same DC for
measuring and rendering
fmtRange.hdcTar get = 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.AllocCo TaskMem(Marshal .SizeOf(fmtRang e));
Marshal.Structu reToPtr(fmtRang e, lParam, false);

SafeNativeMetho ds.SendMessage( this.Handle,
SafeNativeMetho ds.EM_FORMATRAN GE, wParam, lParam);
SafeNativeMetho ds.SendMessage( this.Handle,
SafeNativeMetho ds.EM_FORMATRAN GE, wParam, IntPtr.Zero);

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

//Release the device context handle obtained by a previous call
g.ReleaseHdc(hD CEMF);
g.Dispose();

hdc = graphics.GetHdc ();
int nHorzSize = SafeNativeMetho ds.GetDeviceCap s(hdc,
SafeNativeMetho ds.DeviceCap.HO RZSIZE);
int nVertSize = SafeNativeMetho ds.GetDeviceCap s(hdc,
SafeNativeMetho ds.DeviceCap.VE RTSIZE);
int nHorzRes = SafeNativeMetho ds.GetDeviceCap s(hdc,
SafeNativeMetho ds.DeviceCap.HO RZRES);
int nVertRes = SafeNativeMetho ds.GetDeviceCap s(hdc,
SafeNativeMetho ds.DeviceCap.VE RTRES);
int nLogPixelsX = SafeNativeMetho ds.GetDeviceCap s(hdc,
SafeNativeMetho ds.DeviceCap.LO GPIXELSX);
int nLogPixelsY = SafeNativeMetho ds.GetDeviceCap s(hdc,
SafeNativeMetho ds.DeviceCap.LO GPIXELSY);
graphics.Releas eHdc(hdc);

float fHorzSizeInches = nHorzSize / 25.4f;
float fVertSizeInches = nVertSize / 25.4f;
float fHorzFudgeFacto r = (nHorzRes / fHorzSizeInches ) /
nLogPixelsX;
float fVertFudgeFacto r = (nVertRes / fVertSizeInches ) /
nLogPixelsY;

System.Diagnost ics.Debug.Write Line("Fudge Factor " +
fHorzFudgeFacto r.ToString() + " " + fVertFudgeFacto r.ToString() + " XFactor
" + xFactor.ToStrin g());

Pen RedPen = new Pen(Color.Red);
graphics.DrawRe ctangle(RedPen, layoutArea.X * xFactor,
layoutArea.Y * xFactor, layoutArea.Widt h * xFactor, layoutArea.Heig ht *
xFactor);

float Left = layoutArea.Left ;
float Top = layoutArea.Top;
//layoutArea.X = layoutArea.Y = 0;
layoutArea.Offs et(-Left, -Top);
layoutArea.Offs et(Left / fHorzFudgeFacto r, Top /
fVertFudgeFacto r);

System.Drawing. Drawing2D.Graph icsState state = graphics.Save() ;
graphics.ScaleT ransform(fHorzF udgeFactor * xFactor,
fVertFudgeFacto r * xFactor);
graphics.DrawIm age(metafile, layoutArea);
graphics.Restor e(state);
System.Diagnost ics.Debug.Write Line("Layout Aread :
"+layoutAre a);
}

#region SafeNativeMetho ds
private static class SafeNativeMetho ds
{
[DllImport("USER 32.dll")]
public static extern IntPtr SendMessage(Int Ptr hWnd, int msg,
IntPtr wp, IntPtr lp);

[DllImport("kern el32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr LoadLibrary(str ing lpFileName);

[DllImport("gdi3 2.dll")]
public static extern int GetDeviceCaps(I ntPtr hdc, DeviceCap
nIndex);

[StructLayout(La youtKind.Sequen tial)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}

[StructLayout(La youtKind.Sequen tial)]
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(La youtKind.Sequen tial)]
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_TRANSPARE NT = 0x20;

}
#endregion
}
}

Oct 27 '08 #1
2 5573
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.no spamwrote in message
news:pq******** ********@nlpi06 8.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,i nt nRotationDegree s,int
nHorzShearPerce nt,int nVertShearPerce nt)
{
// validate the arguments
if (nScalePercent < 1)
nScalePercent = 1;
if (nScalePercent 10000)
nScalePercent = 10000;
if (nRotationDegre es < 0)
nRotationDegree s = 0;
if (nRotationDegre es 360)
nRotationDegree s = 360;
if (nHorzShearPerc ent < 0)
nHorzShearPerce nt = 0;
if (nHorzShearPerc ent 100)
nHorzShearPerce nt = 100;
if (nVertShearPerc ent < 0)
nVertShearPerce nt = 0;
if (nVertShearPerc ent 100)
nVertShearPerce nt = 100;

// setup target window, rect and DC
CWnd* pTargetWin = GetDlgItem(IDC_ EDIT1);
CRect crTarget;
pTargetWin->GetClientRect( &crTarget);
crTarget.Offset Rect(0,20);
CDC* pTargetDC = pTargetWin->GetDC();
pTargetDC->IntersectClipR ect(&crTarget); // so we don't clobber the parent
dialog
pTargetDC->SetBkMode(TRAN SPARENT); // so the legend doesn't erase too
much

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

// erase previous contents
FillRect(pTarge tDC->m_hDC,crTarget ,(HBRUSH)(COLOR _WINDOW + 1));
CString Temp;
Temp.Format("cr Target %d,%d
%d,%d\n",crTarg et.left,crTarge t.top,crTarget. Width(),crTarge t.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("Me taSize
%d,%d\n",cHiMet ricRect.Width() ,cHiMetricRect. Height());
TRACE(Temp);
Temp.Format("cT wipsRect %d,%d\n",cTwips Rect.Width(),cT wipsRect.Height ());
TRACE(Temp);
// create the enhanced metafile
HDC hDCEMF = CreateEnhMetaFi le(pTargetDC->m_hDC,NULL,cHi MetricRect,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,TR UE,(LPARAM)
&stFR);
GetDlgItem(IDC_ RICHEDIT1)->SendMessage(EM _FORMATRANGE,TR UE,NULL); // this
call clears the cache

// drawing into the metafile is done, get ourselves an handle to it (used
for the replay)
HENHMETAFILE hEMF = CloseEnhMetaFil e(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 fHorzFudgeFacto r = (nHorzRes / fHorzSizeInches ) / nLogPixelsX; //
divide expected DPI with actual DPI
float fVertFudgeFacto r = (nVertRes / fVertSizeInches ) / nLogPixelsY; //

Temp.Format("Fu dgfactor %.2f %.2f\n",fHorzFu dgeFactor,fVert FudgeFactor);
TRACE(Temp);

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

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

// then apply the rotation
ZeroMemory(&stX ,sizeof(stX));
stX.eM11 = (float) cos(fRotationIn Radians);
stX.eM12 = (float) sin(fRotationIn Radians);
stX.eM21 = 0 - (float) sin(fRotationIn Radians);
stX.eM22 = (float) cos(fRotationIn Radians);
ModifyWorldTran sform(pTargetDC->m_hDC,&stX,MWT _LEFTMULTIPLY);

// finally apply the horizontal and vertical shearing
ZeroMemory(&stX ,sizeof(stX));
stX.eM11 = 1.0f;
stX.eM12 = nHorzShearPerce nt / 100.0f;
stX.eM21 = nVertShearPerce nt / 100.0f;
stX.eM22 = 1.0f;
ModifyWorldTran sform(pTargetDC->m_hDC,&stX,MWT _LEFTMULTIPLY);

crTarget.Offset Rect(0,-20);
crTarget.Offset Rect(0,20 / (nScalePercent / 100.0f) * fVertFudgeFacto r);
// play the metafile
pTargetDC->PlayMetaFile(h EMF,&crTarget);

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

// also show a legend
ModifyWorldTran sform(pTargetDC->m_hDC,NULL,MWT _IDENTITY);
CString sLegend;
sLegend.Format( "Scale: %d%% rotation: %dº horizontal shear: %d%%
vertical shear: %d%%.",
nScalePercent,n RotationDegrees ,nHorzShearPerc ent,nVertShearP ercent);
pTargetDC->SetTextColor(R GB(55,111,111)) ;
pTargetDC->DrawText(sLege nd,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_DrawRt fText
{
private static RichTextBoxDraw er rtfDrawer;
public static void DrawRtfText(thi s Graphics graphics, string rtf,
RectangleF layoutArea,floa t xFactor)
{
if (Graphics_DrawR tfText.rtfDrawe r == null)
{
Graphics_DrawRt fText.rtfDrawer = new RichTextBoxDraw er();
}
Graphics_DrawRt fText.rtfDrawer .Rtf = rtf;
Graphics_DrawRt fText.rtfDrawer .Draw(graphics, layoutArea,xFac tor);
}

private class RichTextBoxDraw er : 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.CreatePara ms;
if (SafeNativeMeth ods.LoadLibrary ("msftedit.dll" ) !=
IntPtr.Zero)
{
createParams.Ex Style |=
SafeNativeMetho ds.WS_EX_TRANSP ARENT; // transparent
createParams.Cl assName = "RICHEDIT50 W";
}
return createParams;
}
}

private void DPToHIMETRIC(Gr aphics 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.Diagnost ics.Debug.Write Line("LayoutAre a " + layoutArea);

SizeF metaSize = layoutArea.Size ;
DPToHIMETRIC(gr aphics, ref metaSize);

System.Diagnost ics.Debug.Write Line("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.Releas eHdc(hdc);

Graphics g = Graphics.FromIm age(metafile);
IntPtr hDCEMF = g.GetHdc();

//Calculate the area to render.
SafeNativeMetho ds.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.Diagnost ics.Debug.Write Line(String.For mat("RectLayout Area
({0},{1})",rect LayoutArea.Righ t,rectLayoutAre a.Bottom));

SafeNativeMetho ds.FORMATRANGE fmtRange;
fmtRange.chrg.c pMax = -1; //Indicate character from
to character to
fmtRange.chrg.c pMin = 0;
fmtRange.hdc = hDCEMF; //Use the same DC for
measuring and rendering
fmtRange.hdcTar get = 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.AllocCo TaskMem(Marshal .SizeOf(fmtRang e));
Marshal.Structu reToPtr(fmtRang e, lParam, false);

SafeNativeMetho ds.SendMessage( this.Handle,
SafeNativeMetho ds.EM_FORMATRAN GE, wParam, lParam);
SafeNativeMetho ds.SendMessage( this.Handle,
SafeNativeMetho ds.EM_FORMATRAN GE, wParam, IntPtr.Zero);

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

//Release the device context handle obtained by a previous call
g.ReleaseHdc(hD CEMF);
g.Dispose();

hdc = graphics.GetHdc ();
int nHorzSize = SafeNativeMetho ds.GetDeviceCap s(hdc,
SafeNativeMetho ds.DeviceCap.HO RZSIZE);
int nVertSize = SafeNativeMetho ds.GetDeviceCap s(hdc,
SafeNativeMetho ds.DeviceCap.VE RTSIZE);
int nHorzRes = SafeNativeMetho ds.GetDeviceCap s(hdc,
SafeNativeMetho ds.DeviceCap.HO RZRES);
int nVertRes = SafeNativeMetho ds.GetDeviceCap s(hdc,
SafeNativeMetho ds.DeviceCap.VE RTRES);
int nLogPixelsX = SafeNativeMetho ds.GetDeviceCap s(hdc,
SafeNativeMetho ds.DeviceCap.LO GPIXELSX);
int nLogPixelsY = SafeNativeMetho ds.GetDeviceCap s(hdc,
SafeNativeMetho ds.DeviceCap.LO GPIXELSY);
graphics.Releas eHdc(hdc);

float fHorzSizeInches = nHorzSize / 25.4f;
float fVertSizeInches = nVertSize / 25.4f;
float fHorzFudgeFacto r = (nHorzRes / fHorzSizeInches ) /
nLogPixelsX;
float fVertFudgeFacto r = (nVertRes / fVertSizeInches ) /
nLogPixelsY;

System.Diagnost ics.Debug.Write Line("Fudge Factor " +
fHorzFudgeFacto r.ToString() + " " + fVertFudgeFacto r.ToString() + "
XFactor " + xFactor.ToStrin g());

Pen RedPen = new Pen(Color.Red);
graphics.DrawRe ctangle(RedPen, layoutArea.X * xFactor,
layoutArea.Y * xFactor, layoutArea.Widt h * xFactor, layoutArea.Heig ht *
xFactor);

float Left = layoutArea.Left ;
float Top = layoutArea.Top;
//layoutArea.X = layoutArea.Y = 0;
layoutArea.Offs et(-Left, -Top);
layoutArea.Offs et(Left / fHorzFudgeFacto r, Top /
fVertFudgeFacto r);

System.Drawing. Drawing2D.Graph icsState state = graphics.Save() ;
graphics.ScaleT ransform(fHorzF udgeFactor * xFactor,
fVertFudgeFacto r * xFactor);
graphics.DrawIm age(metafile, layoutArea);
graphics.Restor e(state);
System.Diagnost ics.Debug.Write Line("Layout Aread :
"+layoutAre a);
}

#region SafeNativeMetho ds
private static class SafeNativeMetho ds
{
[DllImport("USER 32.dll")]
public static extern IntPtr SendMessage(Int Ptr hWnd, int msg,
IntPtr wp, IntPtr lp);

[DllImport("kern el32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr LoadLibrary(str ing lpFileName);

[DllImport("gdi3 2.dll")]
public static extern int GetDeviceCaps(I ntPtr hdc, DeviceCap
nIndex);

[StructLayout(La youtKind.Sequen tial)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}

[StructLayout(La youtKind.Sequen tial)]
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(La youtKind.Sequen tial)]
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_TRANSPARE NT = 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.no spamwrote in message
news:5c******** ********@flpi14 4.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.no spamwrote in message
news:pq******** ********@nlpi06 8.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,i nt nRotationDegree s,int
nHorzShearPerc ent,int nVertShearPerce nt)
{
// validate the arguments
if (nScalePercent < 1)
nScalePercent = 1;
if (nScalePercent 10000)
nScalePercent = 10000;
if (nRotationDegre es < 0)
nRotationDegree s = 0;
if (nRotationDegre es 360)
nRotationDegree s = 360;
if (nHorzShearPerc ent < 0)
nHorzShearPerce nt = 0;
if (nHorzShearPerc ent 100)
nHorzShearPerce nt = 100;
if (nVertShearPerc ent < 0)
nVertShearPerce nt = 0;
if (nVertShearPerc ent 100)
nVertShearPerce nt = 100;

// setup target window, rect and DC
CWnd* pTargetWin = GetDlgItem(IDC_ EDIT1);
CRect crTarget;
pTargetWin->GetClientRect( &crTarget);
crTarget.Offse tRect(0,20);
CDC* pTargetDC = pTargetWin->GetDC();
pTargetDC->IntersectClipR ect(&crTarget); // so we don't clobber the
parent dialog
pTargetDC->SetBkMode(TRAN SPARENT); // so the legend doesn't erase too
much

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

// erase previous contents
FillRect(pTarg etDC->m_hDC,crTarget ,(HBRUSH)(COLOR _WINDOW + 1));
CString Temp;
Temp.Format("c rTarget %d,%d
%d,%d\n",crTar get.left,crTarg et.top,crTarget .Width(),crTarg et.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_INC H,
(TWIPS_INCH * cTargetSize.cy + HIMETRIC_INCH / 2) / HIMETRIC_INCH);

Temp.Format("M etaSize
%d,%d\n",cHiMe tricRect.Width( ),cHiMetricRect .Height());
TRACE(Temp);
Temp.Format("c TwipsRect %d,%d\n",cTwips Rect.Width(),cT wipsRect.Height ());
TRACE(Temp);
// create the enhanced metafile
HDC hDCEMF = CreateEnhMetaFi le(pTargetDC->m_hDC,NULL,cHi MetricRect,NULL );

// setup the format struct and do the RTF range formatting call
FORMATRANGE stFR;
stFR.hdcTarg et = stFR.hdc = hDCEMF; // render to the memory helper EMF
stFR.rcPage = stFR.rc = cTwipsRect; // using this rectangle (in
twips)
stFR.chrg.cpMi n = 0; // and render all of the text
stFR.chrg.cpMa x = -1;
GetDlgItem(IDC _RICHEDIT1)->SendMessage(EM _FORMATRANGE,TR UE,(LPARAM)
&stFR);
GetDlgItem(IDC _RICHEDIT1)->SendMessage(EM _FORMATRANGE,TR UE,NULL); // this
call clears the cache

// drawing into the metafile is done, get ourselves an handle to it (used
for the replay)
HENHMETAFILE hEMF = CloseEnhMetaFil e(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 fHorzFudgeFacto r = (nHorzRes / fHorzSizeInches ) / nLogPixelsX; //
divide expected DPI with actual DPI
float fVertFudgeFacto r = (nVertRes / fVertSizeInches ) / nLogPixelsY; //

Temp.Format("F udgfactor %.2f %.2f\n",fHorzFu dgeFactor,fVert FudgeFactor);
TRACE(Temp);

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

// do the world transforms, first apply the scale and fudge factors
XFORM stX;
ZeroMemory(&st X,sizeof(stX));
stX.eM11 = fHorzFudgeFacto r * (nScalePercent / 100.0f);
stX.eM22 = fVertFudgeFacto r * (nScalePercent / 100.0f);
SetWorldTransf orm(pTargetDC->m_hDC,&stX);

// then apply the rotation
ZeroMemory(&st X,sizeof(stX));
stX.eM11 = (float) cos(fRotationIn Radians);
stX.eM12 = (float) sin(fRotationIn Radians);
stX.eM21 = 0 - (float) sin(fRotationIn Radians);
stX.eM22 = (float) cos(fRotationIn Radians);
ModifyWorldTra nsform(pTargetD C->m_hDC,&stX,MWT _LEFTMULTIPLY);

// finally apply the horizontal and vertical shearing
ZeroMemory(&st X,sizeof(stX));
stX.eM11 = 1.0f;
stX.eM12 = nHorzShearPerce nt / 100.0f;
stX.eM21 = nVertShearPerce nt / 100.0f;
stX.eM22 = 1.0f;
ModifyWorldTra nsform(pTargetD C->m_hDC,&stX,MWT _LEFTMULTIPLY);

crTarget.Offse tRect(0,-20);
crTarget.Offse tRect(0,20 / (nScalePercent / 100.0f) * fVertFudgeFacto r);
// play the metafile
pTargetDC->PlayMetaFile(h EMF,&crTarget);

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

// also show a legend
ModifyWorldTra nsform(pTargetD C->m_hDC,NULL,MWT _IDENTITY);
CString sLegend;
sLegend.Format ("Scale: %d%% rotation: %dº horizontal shear: %d%%
vertical shear: %d%%.",
nScalePercent,n RotationDegrees ,nHorzShearPerc ent,nVertShearP ercent);
pTargetDC->SetTextColor(R GB(55,111,111)) ;
pTargetDC->DrawText(sLege nd,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_DrawRt fText
{
private static RichTextBoxDraw er rtfDrawer;
public static void DrawRtfText(thi s Graphics graphics, string rtf,
RectangleF layoutArea,floa t xFactor)
{
if (Graphics_DrawR tfText.rtfDrawe r == null)
{
Graphics_DrawRt fText.rtfDrawer = new RichTextBoxDraw er();
}
Graphics_DrawRt fText.rtfDrawer .Rtf = rtf;
Graphics_DrawRt fText.rtfDrawer .Draw(graphics, layoutArea,xFac tor);
}

private class RichTextBoxDraw er : 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.CreatePara ms;
if (SafeNativeMeth ods.LoadLibrary ("msftedit.dll" ) !=
IntPtr.Zero)
{
createParams.Ex Style |=
SafeNativeMeth ods.WS_EX_TRANS PARENT; // transparent
createParams.Cl assName = "RICHEDIT50 W";
}
return createParams;
}
}

private void DPToHIMETRIC(Gr aphics 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.Diagnost ics.Debug.Write Line("LayoutAre a " +
layoutArea);

SizeF metaSize = layoutArea.Size ;
DPToHIMETRIC(gr aphics, ref metaSize);

System.Diagnost ics.Debug.Write Line("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.Heigh t));

graphics.Releas eHdc(hdc);

Graphics g = Graphics.FromIm age(metafile);
IntPtr hDCEMF = g.GetHdc();

//Calculate the area to render.
SafeNativeMetho ds.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.Diagnos tics.Debug.Writ eLine(String.Fo rmat("RectLayou tArea
({0},{1})",rec tLayoutArea.Rig ht,rectLayoutAr ea.Bottom));

SafeNativeMetho ds.FORMATRANGE fmtRange;
fmtRange.chrg.c pMax = -1; //Indicate character from
to character to
fmtRange.chrg.c pMin = 0;
fmtRange.hdc = hDCEMF; //Use the same DC for
measuring and rendering
fmtRange.hdcTar get = 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.AllocCo TaskMem(Marshal .SizeOf(fmtRang e));
Marshal.Structu reToPtr(fmtRang e, lParam, false);

SafeNativeMetho ds.SendMessage( this.Handle,
SafeNativeMeth ods.EM_FORMATRA NGE, wParam, lParam);
SafeNativeMetho ds.SendMessage( this.Handle,
SafeNativeMeth ods.EM_FORMATRA NGE, wParam, IntPtr.Zero);

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

//Release the device context handle obtained by a previous
call
g.ReleaseHdc(hD CEMF);
g.Dispose();

hdc = graphics.GetHdc ();
int nHorzSize = SafeNativeMetho ds.GetDeviceCap s(hdc,
SafeNativeMeth ods.DeviceCap.H ORZSIZE);
int nVertSize = SafeNativeMetho ds.GetDeviceCap s(hdc,
SafeNativeMeth ods.DeviceCap.V ERTSIZE);
int nHorzRes = SafeNativeMetho ds.GetDeviceCap s(hdc,
SafeNativeMeth ods.DeviceCap.H ORZRES);
int nVertRes = SafeNativeMetho ds.GetDeviceCap s(hdc,
SafeNativeMeth ods.DeviceCap.V ERTRES);
int nLogPixelsX = SafeNativeMetho ds.GetDeviceCap s(hdc,
SafeNativeMeth ods.DeviceCap.L OGPIXELSX);
int nLogPixelsY = SafeNativeMetho ds.GetDeviceCap s(hdc,
SafeNativeMeth ods.DeviceCap.L OGPIXELSY);
graphics.Releas eHdc(hdc);

float fHorzSizeInches = nHorzSize / 25.4f;
float fVertSizeInches = nVertSize / 25.4f;
float fHorzFudgeFacto r = (nHorzRes / fHorzSizeInches ) /
nLogPixelsX;
float fVertFudgeFacto r = (nVertRes / fVertSizeInches ) /
nLogPixelsY;

System.Diagnost ics.Debug.Write Line("Fudge Factor " +
fHorzFudgeFact or.ToString() + " " + fVertFudgeFacto r.ToString() + "
XFactor " + xFactor.ToStrin g());

Pen RedPen = new Pen(Color.Red);
graphics.DrawRe ctangle(RedPen, layoutArea.X * xFactor,
layoutArea.Y * xFactor, layoutArea.Widt h * xFactor, layoutArea.Heig ht *
xFactor);

float Left = layoutArea.Left ;
float Top = layoutArea.Top;
//layoutArea.X = layoutArea.Y = 0;
layoutArea.Offs et(-Left, -Top);
layoutArea.Offs et(Left / fHorzFudgeFacto r, Top /
fVertFudgeFact or);

System.Drawing. Drawing2D.Graph icsState state =
graphics.Save( );
graphics.ScaleT ransform(fHorzF udgeFactor * xFactor,
fVertFudgeFact or * xFactor);
graphics.DrawIm age(metafile, layoutArea);
graphics.Restor e(state);
System.Diagnost ics.Debug.Write Line("Layout Aread :
"+layoutArea );
}

#region SafeNativeMetho ds
private static class SafeNativeMetho ds
{
[DllImport("USER 32.dll")]
public static extern IntPtr SendMessage(Int Ptr hWnd, int msg,
IntPtr wp, IntPtr lp);

[DllImport("kern el32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr LoadLibrary(str ing lpFileName);

[DllImport("gdi3 2.dll")]
public static extern int GetDeviceCaps(I ntPtr hdc, DeviceCap
nIndex);

[StructLayout(La youtKind.Sequen tial)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}

[StructLayout(La youtKind.Sequen tial)]
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(La youtKind.Sequen tial)]
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_TRANSPARE NT = 0x20;

}
#endregion
}
}


Oct 28 '08 #3

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
3744
by: John Fouhy | last post by:
So I've got a horizontal scale widget in my GUI. When I click the mouse in the area to the right of the GUI, the scale advances by 1. 13 +-------------------------+ |<| X |>| +-------------------------+ || \/
4
6612
by: codecraig | last post by:
Hi, I am using Tkinter and I have a Label and a Scale. I want to update my label everytime the Scale value changes. What is the best way of doing this? Do i have to bind for every event type? Or is there some better way? If I do have to bind each type of event to the scale, what types occur for a Scale? Thanks.
5
316
by: Guess | last post by:
The situation is as follows: 1. I would like to serve a web page that takes considerable time to process. 2. While the page is processing, the client displays an appropriate wait message. What are the consequences of having this long processing page when there are many simultaneous requests from many clients for the same page (say 75+).
3
7297
by: John Bonds | last post by:
I'm looking for some sort of digital scale to integrate into .NET. Does anybody know of anything (like a postal scale) that attaches to USB, serial or whatever that comes with a DLL or an API that I could integrate into .NET? Thanks, John
3
7127
by: Jay Patel | last post by:
Hello, I need to write visual basic.net code to interface with a Mettler Toledo Shipping Scale that interfaces with a PC via USB or a serial port. I have seen example code on how to communicate via a serial connection (RS-232), but am not sure as the process if it is connected via USB. Is the USB port seen then as a COMM port, or is there a different type of connection a USB port creates that I would have to open? The scale will take as...
3
2038
by: Jerry Spence1 | last post by:
A very useful feature was added in 2.0 of .NET framework which was the scaling of a form and all the controls within it. This is really useful but I am finding very little information of how to use it. I have managed to implement it as follows: Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim addSize As New SizeF(0.5F, 0.5F)
0
1497
by: TonyJ | last post by:
Hello! We have a pc running a form application. If I push some buttons in this application I want to send some commands to a scale which is connected to a specific IP address. When I sent a command I also receive an answer from the scale. I want to communicate with the scale using TCP or UDP. The commands that can be sent to the scale are very short about 3 to 5 characters.
19
4900
by: Matteo Migliore | last post by:
Hi! I've to scale a vector of numbers of size N to a vector of size M. The trasformation is like a zoom on images but I need on a vector. The second size can be M >= N or M <= N, M 0. The value for each element can be from 0 to 255. Is there some methods that can I use?
22
3671
by: Jesse Burns | last post by:
I'm about to start working on my first large scale site (in my opinion) that will hopefully have 1000+ users a day. ok, this isn't on the google/facebook scale, but it's going to be have more hits than just family and friends. Either way, I'm planning on this site blowing up once I have enough of a feature set, so I'm concerned about performance and scalability in the long run. I've worked for a software company, but I've never...
0
9569
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10558
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10318
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
10302
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
10069
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
1
7608
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6844
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5503
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
1
4277
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.