ZYBTextBox.cs
上传用户:jsz11269
上传日期:2017-01-14
资源大小:450k
文件大小:39k
源码类别:

Email服务器

开发平台:

C#

  1. using System;
  2. using System.Collections.Specialized;
  3. using System.Drawing;
  4. using System.Drawing.Imaging;
  5. using System.IO;
  6. using System.Runtime.InteropServices;
  7. using System.Text;
  8. using System.Windows.Forms;
  9. using System.Drawing.Printing;
  10. namespace myWorkPad
  11. {
  12.     #region Public Enums
  13.     // Enum for possible RTF colors
  14.     public enum RtfColor
  15.     {
  16.         Black, Maroon, Green, Olive, Navy, Purple, Teal, Gray, Silver,
  17.         Red, Lime, Yellow, Blue, Fuchsia, Aqua, White, Orange
  18.     }
  19.     #endregion
  20.     /// <summary>
  21.     /// This class adds the following functionality to RichTextBox:
  22.     /// 
  23.     /// 1. Allows plain text to be inserted or appended programmatically to RTF
  24.     /// content.
  25.     /// 2. Allows the font, text color, and highlight color of plain text to be
  26.     /// specified when inserting or appending text as RTF.
  27.     /// 3. Allows images to be inserted programmatically, or with interaction from
  28.     /// the user.
  29.     /// </summary>
  30.     /// <remarks>
  31.     /// Many solutions to the problem of programmatically inserting images
  32.     /// into a RichTextBox use the clipboard or hard code the RTF for
  33.     /// the image in the program.  This class is an attempt to make the process of
  34.     /// inserting images at runtime more flexible without the overhead of maintaining
  35.     /// the clipboard or the use of huge, cumbersome strings.
  36.     /// 
  37.     /// RTF Specification v1.6 was used and is referred to many times in this document.
  38.     /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnrtfspec/html/rtfspec.asp
  39.     /// 
  40.     /// For information about the RichEdit (Unmanaged RichTextBox) ...
  41.     /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/richedit/richeditcontrols/aboutricheditcontrols.asp
  42.     /// </remarks>
  43.     public class ZYBRichTextBox : ExtendedRichTextBox.RichTextBoxPrintCtrl
  44.     {
  45.         #region My Enums
  46.         // Specifies the flags/options for the unmanaged call to the GDI+ method
  47.         // Metafile.EmfToWmfBits().
  48.         private enum EmfToWmfBitsFlags
  49.         {
  50.             // Use the default conversion
  51.             EmfToWmfBitsFlagsDefault = 0x00000000,
  52.             // Embedded the source of the EMF metafiel within the resulting WMF
  53.             // metafile
  54.             EmfToWmfBitsFlagsEmbedEmf = 0x00000001,
  55.             // Place a 22-byte header in the resulting WMF file.  The header is
  56.             // required for the metafile to be considered placeable.
  57.             EmfToWmfBitsFlagsIncludePlaceable = 0x00000002,
  58.             // Don't simulate clipping by using the XOR operator.
  59.             EmfToWmfBitsFlagsNoXORClip = 0x00000004
  60.         };
  61.         #endregion
  62.         #region My Structs
  63.         // Definitions for colors in an RTF document
  64.         private struct RtfColorDef
  65.         {
  66.             public const string Black = @"red0green0blue0";
  67.             public const string Maroon = @"red128green0blue0";
  68.             public const string Green = @"red0green128blue0";
  69.             public const string Olive = @"red128green128blue0";
  70.             public const string Navy = @"red0green0blue128";
  71.             public const string Purple = @"red128green0blue128";
  72.             public const string Teal = @"red0green128blue128";
  73.             public const string Gray = @"red128green128blue128";
  74.             public const string Silver = @"red192green192blue192";
  75.             public const string Red = @"red240green26blue2";
  76.             public const string Lime = @"red0green255blue0";
  77.             public const string Yellow = @"red255green255blue0";
  78.             public const string Blue = @"red0green0blue255";
  79.             public const string Fuchsia = @"red255green0blue255";
  80.             public const string Aqua = @"red0green255blue255";
  81.             public const string White = @"red255green255blue255";
  82.             public const string Orange = @"red223green201blue2";
  83.         }
  84.         // Control words for RTF font families
  85.         private struct RtfFontFamilyDef
  86.         {
  87.             public const string Unknown = @"fnil";
  88.             public const string Roman = @"froman";
  89.             public const string Swiss = @"fswiss";
  90.             public const string Modern = @"fmodern";
  91.             public const string Script = @"fscript";
  92.             public const string Decor = @"fdecor";
  93.             public const string Technical = @"ftech";
  94.             public const string BiDirect = @"fbidi";
  95.         }
  96.         #endregion
  97.         #region print Structs
  98.         //Convert the unit used by the .NET framework (1/100 inch) 
  99.         //and the unit used by Win32 API calls (twips 1/1440 inch)
  100.         private const double anInch = 14.4;
  101.         [StructLayout(LayoutKind.Sequential)]
  102.         private struct RECT
  103.         {
  104.             public int Left;
  105.             public int Top;
  106.             public int Right;
  107.             public int Bottom;
  108.         }
  109.         [StructLayout(LayoutKind.Sequential)]
  110.         private struct CHARRANGE
  111.         {
  112.             public int cpMin;         //First character of range (0 for start of doc)
  113.             public int cpMax;           //Last character of range (-1 for end of doc)
  114.         }
  115.         [StructLayout(LayoutKind.Sequential)]
  116.         private struct FORMATRANGE
  117.         {
  118.             public IntPtr hdc;             //Actual DC to draw on
  119.             public IntPtr hdcTarget;       //Target DC for determining text formatting
  120.             public RECT rc;                //Region of the DC to draw to (in twips)
  121.             public RECT rcPage;            //Region of the whole DC (page size) (in twips)
  122.             public CHARRANGE chrg;         //Range of text to draw (see earlier declaration)
  123.         }
  124.         private const int WM_USER = 0x0400;
  125.         private const int EM_FORMATRANGE = WM_USER + 57;
  126.         [DllImport("USER32.dll")]
  127.         private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp); 
  128.         #endregion
  129.         #region My Constants
  130.         // Not used in this application.  Descriptions can be found with documentation
  131.         // of Windows GDI function SetMapMode
  132.         private const int MM_TEXT = 1;
  133.         private const int MM_LOMETRIC = 2;
  134.         private const int MM_HIMETRIC = 3;
  135.         private const int MM_LOENGLISH = 4;
  136.         private const int MM_HIENGLISH = 5;
  137.         private const int MM_TWIPS = 6;
  138.         // Ensures that the metafile maintains a 1:1 aspect ratio
  139.         private const int MM_ISOTROPIC = 7;
  140.         // Allows the x-coordinates and y-coordinates of the metafile to be adjusted
  141.         // independently
  142.         private const int MM_ANISOTROPIC = 8;
  143.         // Represents an unknown font family
  144.         private const string FF_UNKNOWN = "UNKNOWN";
  145.         // The number of hundredths of millimeters (0.01 mm) in an inch
  146.         // For more information, see GetImagePrefix() method.
  147.         private const int HMM_PER_INCH = 2540;
  148.         // The number of twips in an inch
  149.         // For more information, see GetImagePrefix() method.
  150.         private const int TWIPS_PER_INCH = 1440;
  151.         #endregion
  152.         #region My Privates
  153.         // The default text color
  154.         private RtfColor textColor;
  155.         // The default text background color
  156.         private RtfColor highlightColor;
  157.         // Dictionary that maps color enums to RTF color codes
  158.         private HybridDictionary rtfColor;
  159.         // Dictionary that mapas Framework font families to RTF font families
  160.         private HybridDictionary rtfFontFamily;
  161.         // The horizontal resolution at which the control is being displayed
  162.         private float xDpi;
  163.         // The vertical resolution at which the control is being displayed
  164.         private float yDpi;
  165.         #endregion
  166.         #region Elements required to create an RTF document
  167.         /* RTF HEADER
  168.  * ----------
  169.  * 
  170.  * rtf[N] - For text to be considered to be RTF, it must be enclosed in this tag.
  171.  *   rtf1 is used because the RichTextBox conforms to RTF Specification
  172.  *   version 1.
  173.  * ansi - The character set.
  174.  * ansicpg[N] - Specifies that unicode characters might be embedded. ansicpg1252
  175.  *   is the default used by Windows.
  176.  * deff[N] - The default font. deff0 means the default font is the first font
  177.  *   found.
  178.  * deflang[N] - The default language. deflang1033 specifies US English.
  179.  * */
  180.         private const string RTF_HEADER = @"{rtf1ansiansicpg1252deff0deflang1033";
  181.         /* RTF DOCUMENT AREA
  182.          * -----------------
  183.          * 
  184.          * viewkind[N] - The type of view or zoom level.  viewkind4 specifies normal view.
  185.          * uc[N] - The number of bytes corresponding to a Unicode character.
  186.          * pard - Resets to default paragraph properties
  187.          * cf[N] - Foreground color.  cf1 refers to the color at index 1 in
  188.          *   the color table
  189.          * f[N] - Font number. f0 refers to the font at index 0 in the font
  190.          *   table.
  191.          * fs[N] - Font size in half-points.
  192.          * */
  193.         private const string RTF_DOCUMENT_PRE = @"viewkind4uc1pardcf1f0fs20";
  194.         private const string RTF_DOCUMENT_POST = @"cf0fs17}";
  195.         private string RTF_IMAGE_POST = @"}";
  196.         #endregion
  197.         #region Accessors
  198.         // TODO: This can be ommitted along with RemoveBadCharacters
  199.         // Overrides the default implementation of RTF.  This is done because the control
  200.         // was originally developed to run in an instant messenger that uses the
  201.         // Jabber XML-based protocol.  The framework would throw an exception when the
  202.         // XML contained the null character, so I filtered out.
  203.         public new string Rtf
  204.         {
  205.             get { return RemoveBadChars(base.Rtf); }
  206.             set { base.Rtf = value; }
  207.         }
  208.         // The color of the text
  209.         public RtfColor TextColor
  210.         {
  211.             get { return textColor; }
  212.             set { textColor = value; }
  213.         }
  214.         // The color of the highlight
  215.         public RtfColor HiglightColor
  216.         {
  217.             get { return highlightColor; }
  218.             set { highlightColor = value; }
  219.         }
  220.         #endregion
  221.         #region Constructors
  222.         /// <summary>
  223.         /// Initializes the text colors, creates dictionaries for RTF colors and
  224.         /// font families, and stores the horizontal and vertical resolution of
  225.         /// the RichTextBox's graphics context.
  226.         /// </summary>
  227.         public ZYBRichTextBox() : base()
  228.         {
  229.             // Initialize default text and background colors
  230.             textColor = RtfColor.Black;
  231.             highlightColor = RtfColor.White;
  232.             // Initialize the dictionary mapping color codes to definitions
  233.             rtfColor = new HybridDictionary();
  234.             rtfColor.Add(RtfColor.Aqua, RtfColorDef.Aqua);
  235.             rtfColor.Add(RtfColor.Black, RtfColorDef.Black);
  236.             rtfColor.Add(RtfColor.Blue, RtfColorDef.Blue);
  237.             rtfColor.Add(RtfColor.Fuchsia, RtfColorDef.Fuchsia);
  238.             rtfColor.Add(RtfColor.Gray, RtfColorDef.Gray);
  239.             rtfColor.Add(RtfColor.Green, RtfColorDef.Green);
  240.             rtfColor.Add(RtfColor.Lime, RtfColorDef.Lime);
  241.             rtfColor.Add(RtfColor.Maroon, RtfColorDef.Maroon);
  242.             rtfColor.Add(RtfColor.Navy, RtfColorDef.Navy);
  243.             rtfColor.Add(RtfColor.Olive, RtfColorDef.Olive);
  244.             rtfColor.Add(RtfColor.Purple, RtfColorDef.Purple);
  245.             rtfColor.Add(RtfColor.Red, RtfColorDef.Red);
  246.             rtfColor.Add(RtfColor.Silver, RtfColorDef.Silver);
  247.             rtfColor.Add(RtfColor.Teal, RtfColorDef.Teal);
  248.             rtfColor.Add(RtfColor.White, RtfColorDef.White);
  249.             rtfColor.Add(RtfColor.Yellow, RtfColorDef.Yellow);
  250.             rtfColor.Add(RtfColor.Orange, RtfColorDef.Orange);
  251.             // Initialize the dictionary mapping default Framework font families to
  252.             // RTF font families
  253.             rtfFontFamily = new HybridDictionary();
  254.             rtfFontFamily.Add(FontFamily.GenericMonospace.Name, RtfFontFamilyDef.Modern);
  255.             rtfFontFamily.Add(FontFamily.GenericSansSerif, RtfFontFamilyDef.Swiss);
  256.             rtfFontFamily.Add(FontFamily.GenericSerif, RtfFontFamilyDef.Roman);
  257.             rtfFontFamily.Add(FF_UNKNOWN, RtfFontFamilyDef.Unknown);
  258.             // Get the horizontal and vertical resolutions at which the object is
  259.             // being displayed
  260.             using (Graphics _graphics = this.CreateGraphics())
  261.             {
  262.                 xDpi = _graphics.DpiX;
  263.                 yDpi = _graphics.DpiY;
  264.             }
  265.         }
  266.         /// <summary>
  267.         /// Calls the default constructor then sets the text color.
  268.         /// </summary>
  269.         /// <param name="_textColor"></param>
  270.         public ZYBRichTextBox(RtfColor _textColor)
  271.             : this()
  272.         {
  273.             textColor = _textColor;
  274.         }
  275.         /// <summary>
  276.         /// Calls the default constructor then sets te text and highlight colors.
  277.         /// </summary>
  278.         /// <param name="_textColor"></param>
  279.         /// <param name="_highlightColor"></param>
  280.         public ZYBRichTextBox(RtfColor _textColor, RtfColor _highlightColor)
  281.             : this()
  282.         {
  283.             textColor = _textColor;
  284.             highlightColor = _highlightColor;
  285.         }
  286.         #endregion
  287.         #region Append RTF or Text to RichTextBox Contents
  288.         /// <summary>
  289.         /// Assumes the string passed as a paramter is valid RTF text and attempts
  290.         /// to append it as RTF to the content of the control.
  291.         /// </summary>
  292.         /// <param name="_rtf"></param>
  293.         public void AppendRtf(string _rtf)
  294.         {
  295.             // Move caret to the end of the text
  296.             this.Select(this.TextLength, 0);
  297.             // Since SelectedRtf is null, this will append the string to the
  298.             // end of the existing RTF
  299.             this.SelectedRtf = _rtf;
  300.         }
  301.         /// <summary>
  302.         /// Assumes that the string passed as a parameter is valid RTF text and
  303.         /// attempts to insert it as RTF into the content of the control.
  304.         /// </summary>
  305.         /// <remarks>
  306.         /// NOTE: The text is inserted wherever the caret is at the time of the call,
  307.         /// and if any text is selected, that text is replaced.
  308.         /// </remarks>
  309.         /// <param name="_rtf"></param>
  310.         public void InsertRtf(string _rtf)
  311.         {
  312.             this.SelectedRtf = _rtf;
  313.         }
  314.         /// <summary>
  315.         /// Appends the text using the current font, text, and highlight colors.
  316.         /// </summary>
  317.         /// <param name="_text"></param>
  318.         public void AppendTextAsRtf(string _text)
  319.         {
  320.             AppendTextAsRtf(_text, this.Font);
  321.         }
  322.         /// <summary>
  323.         /// Appends the text using the given font, and current text and highlight
  324.         /// colors.
  325.         /// </summary>
  326.         /// <param name="_text"></param>
  327.         /// <param name="_font"></param>
  328.         public void AppendTextAsRtf(string _text, Font _font)
  329.         {
  330.             AppendTextAsRtf(_text, _font, textColor);
  331.         }
  332.         /// <summary>
  333.         /// Appends the text using the given font and text color, and the current
  334.         /// highlight color.
  335.         /// </summary>
  336.         /// <param name="_text"></param>
  337.         /// <param name="_font"></param>
  338.         /// <param name="_color"></param>
  339.         public void AppendTextAsRtf(string _text, Font _font, RtfColor _textColor)
  340.         {
  341.             _text = _text.Replace("\", "\\");
  342.             AppendTextAsRtf(_text, _font, _textColor, highlightColor);
  343.         }
  344.         /// <summary>
  345.         /// Appends the text using the given font, text, and highlight colors.  Simply
  346.         /// moves the caret to the end of the RichTextBox's text and makes a call to
  347.         /// insert.
  348.         /// </summary>
  349.         /// <param name="_text"></param>
  350.         /// <param name="_font"></param>
  351.         /// <param name="_textColor"></param>
  352.         /// <param name="_backColor"></param>
  353.         public void AppendTextAsRtf(string _text, Font _font, RtfColor _textColor, RtfColor _backColor)
  354.         {
  355.             // Move carret to the end of the text
  356.             this.Select(this.TextLength, 0);
  357.             InsertTextAsRtf(_text, _font, _textColor, _backColor);
  358.         }
  359.         #endregion
  360.         #region Insert Plain Text
  361.         /// <summary>
  362.         /// Inserts the text using the current font, text, and highlight colors.
  363.         /// </summary>
  364.         /// <param name="_text"></param>
  365.         public void InsertTextAsRtf(string _text)
  366.         {
  367.             InsertTextAsRtf(_text, this.Font);
  368.         }
  369.         /// <summary>
  370.         /// Inserts the text using the given font, and current text and highlight
  371.         /// colors.
  372.         /// </summary>
  373.         /// <param name="_text"></param>
  374.         /// <param name="_font"></param>
  375.         public void InsertTextAsRtf(string _text, Font _font)
  376.         {
  377.             InsertTextAsRtf(_text, _font, textColor);
  378.         }
  379.         /// <summary>
  380.         /// Inserts the text using the given font and text color, and the current
  381.         /// highlight color.
  382.         /// </summary>
  383.         /// <param name="_text"></param>
  384.         /// <param name="_font"></param>
  385.         /// <param name="_color"></param>
  386.         public void InsertTextAsRtf(string _text, Font _font, RtfColor _textColor)
  387.         {
  388.             InsertTextAsRtf(_text, _font, _textColor, highlightColor);
  389.         }
  390.         /// <summary>
  391.         /// Inserts the text using the given font, text, and highlight colors.  The
  392.         /// text is wrapped in RTF codes so that the specified formatting is kept.
  393.         /// You can only assign valid RTF to the RichTextBox.Rtf property, else
  394.         /// an exception is thrown.  The RTF string should follow this format ...
  395.         /// 
  396.         /// {rtf1ansiansicpg1252deff0deflang1033{fonttbl{[FONTS]}{colortbl ;[COLORS]}}
  397.         /// viewkind4uc1pardcf1f0fs20 [DOCUMENT AREA] }
  398.         /// 
  399.         /// </summary>
  400.         /// <remarks>
  401.         /// NOTE: The text is inserted wherever the caret is at the time of the call,
  402.         /// and if any text is selected, that text is replaced.
  403.         /// </remarks>
  404.         /// <param name="_text"></param>
  405.         /// <param name="_font"></param>
  406.         /// <param name="_color"></param>
  407.         /// <param name="_color"></param>
  408.         public void InsertTextAsRtf(string _text, Font _font, RtfColor _textColor, RtfColor _backColor)
  409.         {
  410.             StringBuilder _rtf = new StringBuilder();
  411.             // Append the RTF header
  412.             _rtf.Append(RTF_HEADER);
  413.             // Create the font table from the font passed in and append it to the
  414.             // RTF string
  415.             _rtf.Append(GetFontTable(_font));
  416.             // Create the color table from the colors passed in and append it to the
  417.             // RTF string
  418.             _rtf.Append(GetColorTable(_textColor, _backColor));
  419.             // Create the document area from the text to be added as RTF and append
  420.             // it to the RTF string.
  421.             _rtf.Append(GetDocumentArea(_text, _font));
  422.             this.SelectedRtf = _rtf.ToString();
  423.         }
  424.         /// <summary>
  425.         /// Creates the Document Area of the RTF being inserted. The document area
  426.         /// (in this case) consists of the text being added as RTF and all the
  427.         /// formatting specified in the Font object passed in. This should have the
  428.         /// form ...
  429.         /// 
  430.         /// viewkind4uc1pardcf1f0fs20 [DOCUMENT AREA] }
  431.         ///
  432.         /// </summary>
  433.         /// <param name="_text"></param>
  434.         /// <param name="_font"></param>
  435.         /// <returns>
  436.         /// The document area as a string.
  437.         /// </returns>
  438.         private string GetDocumentArea(string _text, Font _font)
  439.         {
  440.             StringBuilder _doc = new StringBuilder();
  441.             // Append the standard RTF document area control string
  442.             _doc.Append(RTF_DOCUMENT_PRE);
  443.             // Set the highlight color (the color behind the text) to the
  444.             // third color in the color table.  See GetColorTable for more details.
  445.             _doc.Append(@"highlight2");
  446.             // If the font is bold, attach corresponding tag
  447.             if (_font.Bold)
  448.                 _doc.Append(@"b");
  449.             // If the font is italic, attach corresponding tag
  450.             if (_font.Italic)
  451.                 _doc.Append(@"i");
  452.             // If the font is strikeout, attach corresponding tag
  453.             if (_font.Strikeout)
  454.                 _doc.Append(@"strike");
  455.             // If the font is underlined, attach corresponding tag
  456.             if (_font.Underline)
  457.                 _doc.Append(@"ul");
  458.             // Set the font to the first font in the font table.
  459.             // See GetFontTable for more details.
  460.             _doc.Append(@"f0");
  461.             // Set the size of the font.  In RTF, font size is measured in
  462.             // half-points, so the font size is twice the value obtained from
  463.             // Font.SizeInPoints
  464.             _doc.Append(@"fs");
  465.             _doc.Append((int)Math.Round((2 * _font.SizeInPoints)));
  466.             // Apppend a space before starting actual text (for clarity)
  467.             _doc.Append(@" ");
  468.             // Append actual text, however, replace newlines with RTF par.
  469.             // Any other special text should be handled here (e.g.) tabs, etc.
  470.             _doc.Append(_text.Replace("n", @"par "));
  471.             // RTF isn't strict when it comes to closing control words, but what the
  472.             // heck ...
  473.             // Remove the highlight
  474.             _doc.Append(@"highlight0");
  475.             // If font is bold, close tag
  476.             if (_font.Bold)
  477.                 _doc.Append(@"b0");
  478.             // If font is italic, close tag
  479.             if (_font.Italic)
  480.                 _doc.Append(@"i0");
  481.             // If font is strikeout, close tag
  482.             if (_font.Strikeout)
  483.                 _doc.Append(@"strike0");
  484.             // If font is underlined, cloes tag
  485.             if (_font.Underline)
  486.                 _doc.Append(@"ulnone");
  487.             // Revert back to default font and size
  488.             _doc.Append(@"f0");
  489.             _doc.Append(@"fs20");
  490.             // Close the document area control string
  491.             _doc.Append(RTF_DOCUMENT_POST);
  492.             return _doc.ToString();
  493.         }
  494.         #endregion
  495.         #region Insert Image
  496.         /// <summary>
  497.         /// Inserts an image into the RichTextBox.  The image is wrapped in a Windows
  498.         /// Format Metafile, because although Microsoft discourages the use of a WMF,
  499.         /// the RichTextBox (and even MS Word), wraps an image in a WMF before inserting
  500.         /// the image into a document.  The WMF is attached in HEX format (a string of
  501.         /// HEX numbers).
  502.         /// 
  503.         /// The RTF Specification v1.6 says that you should be able to insert bitmaps,
  504.         /// .jpegs, .gifs, .pngs, and Enhanced Metafiles (.emf) directly into an RTF
  505.         /// document without the WMF wrapper. This works fine with MS Word,
  506.         /// however, when you don't wrap images in a WMF, WordPad and
  507.         /// RichTextBoxes simply ignore them.  Both use the riched20.dll or msfted.dll.
  508.         /// </summary>
  509.         /// <remarks>
  510.         /// NOTE: The image is inserted wherever the caret is at the time of the call,
  511.         /// and if any text is selected, that text is replaced.
  512.         /// </remarks>
  513.         /// <param name="_image"></param>
  514.         public void InsertImage(Image _image)
  515.         {
  516.             StringBuilder _rtf = new StringBuilder();
  517.             // Append the RTF header
  518.             _rtf.Append(RTF_HEADER);
  519.             // Create the font table using the RichTextBox's current font and append
  520.             // it to the RTF string
  521.             _rtf.Append(GetFontTable(this.Font));
  522.             // Create the image control string and append it to the RTF string
  523.             _rtf.Append(GetImagePrefix(_image));
  524.             // Create the Windows Metafile and append its bytes in HEX format
  525.             _rtf.Append(GetRtfImage(_image));
  526.             // Close the RTF image control string
  527.             _rtf.Append(RTF_IMAGE_POST);
  528.             this.SelectedRtf = _rtf.ToString();
  529.         }
  530.         /// <summary>
  531.         /// Creates the RTF control string that describes the image being inserted.
  532.         /// This description (in this case) specifies that the image is an
  533.         /// MM_ANISOTROPIC metafile, meaning that both X and Y axes can be scaled
  534.         /// independently.  The control string also gives the images current dimensions,
  535.         /// and its target dimensions, so if you want to control the size of the
  536.         /// image being inserted, this would be the place to do it. The prefix should
  537.         /// have the form ...
  538.         /// 
  539.         /// {pictwmetafile8picw[A]pich[B]picwgoal[C]pichgoal[D]
  540.         /// 
  541.         /// where ...
  542.         /// 
  543.         /// A = current width of the metafile in hundredths of millimeters (0.01mm)
  544.         /// = Image Width in Inches * Number of (0.01mm) per inch
  545.         /// = (Image Width in Pixels / Graphics Context's Horizontal Resolution) * 2540
  546.         /// = (Image Width in Pixels / Graphics.DpiX) * 2540
  547.         /// 
  548.         /// B = current height of the metafile in hundredths of millimeters (0.01mm)
  549.         /// = Image Height in Inches * Number of (0.01mm) per inch
  550.         /// = (Image Height in Pixels / Graphics Context's Vertical Resolution) * 2540
  551.         /// = (Image Height in Pixels / Graphics.DpiX) * 2540
  552.         /// 
  553.         /// C = target width of the metafile in twips
  554.         /// = Image Width in Inches * Number of twips per inch
  555.         /// = (Image Width in Pixels / Graphics Context's Horizontal Resolution) * 1440
  556.         /// = (Image Width in Pixels / Graphics.DpiX) * 1440
  557.         /// 
  558.         /// D = target height of the metafile in twips
  559.         /// = Image Height in Inches * Number of twips per inch
  560.         /// = (Image Height in Pixels / Graphics Context's Horizontal Resolution) * 1440
  561.         /// = (Image Height in Pixels / Graphics.DpiX) * 1440
  562.         ///
  563.         /// </summary>
  564.         /// <remarks>
  565.         /// The Graphics Context's resolution is simply the current resolution at which
  566.         /// windows is being displayed.  Normally it's 96 dpi, but instead of assuming
  567.         /// I just added the code.
  568.         /// 
  569.         /// According to Ken Howe at pbdr.com, "Twips are screen-independent units
  570.         /// used to ensure that the placement and proportion of screen elements in
  571.         /// your screen application are the same on all display systems."
  572.         /// 
  573.         /// Units Used
  574.         /// ----------
  575.         /// 1 Twip = 1/20 Point
  576.         /// 1 Point = 1/72 Inch
  577.         /// 1 Twip = 1/1440 Inch
  578.         /// 
  579.         /// 1 Inch = 2.54 cm
  580.         /// 1 Inch = 25.4 mm
  581.         /// 1 Inch = 2540 (0.01)mm
  582.         /// </remarks>
  583.         /// <param name="_image"></param>
  584.         /// <returns></returns>
  585.         private string GetImagePrefix(Image _image)
  586.         {
  587.             StringBuilder _rtf = new StringBuilder();
  588.             // Calculate the current width of the image in (0.01)mm
  589.             int picw = (int)Math.Round((_image.Width / xDpi) * HMM_PER_INCH);
  590.             // Calculate the current height of the image in (0.01)mm
  591.             int pich = (int)Math.Round((_image.Height / yDpi) * HMM_PER_INCH);
  592.             // Calculate the target width of the image in twips
  593.             int picwgoal = (int)Math.Round((_image.Width / xDpi) * TWIPS_PER_INCH);
  594.             // Calculate the target height of the image in twips
  595.             int pichgoal = (int)Math.Round((_image.Height / yDpi) * TWIPS_PER_INCH);
  596.             // Append values to RTF string
  597.             _rtf.Append(@"{pictwmetafile8");
  598.             _rtf.Append(@"picw");
  599.             _rtf.Append(picw);
  600.             _rtf.Append(@"pich");
  601.             _rtf.Append(pich);
  602.             _rtf.Append(@"picwgoal");
  603.             _rtf.Append(picwgoal);
  604.             _rtf.Append(@"pichgoal");
  605.             _rtf.Append(pichgoal);
  606.             _rtf.Append(" ");
  607.             return _rtf.ToString();
  608.         }
  609.         /// <summary>
  610.         /// Use the EmfToWmfBits function in the GDI+ specification to convert a 
  611.         /// Enhanced Metafile to a Windows Metafile
  612.         /// </summary>
  613.         /// <param name="_hEmf">
  614.         /// A handle to the Enhanced Metafile to be converted
  615.         /// </param>
  616.         /// <param name="_bufferSize">
  617.         /// The size of the buffer used to store the Windows Metafile bits returned
  618.         /// </param>
  619.         /// <param name="_buffer">
  620.         /// An array of bytes used to hold the Windows Metafile bits returned
  621.         /// </param>
  622.         /// <param name="_mappingMode">
  623.         /// The mapping mode of the image.  This control uses MM_ANISOTROPIC.
  624.         /// </param>
  625.         /// <param name="_flags">
  626.         /// Flags used to specify the format of the Windows Metafile returned
  627.         /// </param>
  628.         [DllImportAttribute("gdiplus.dll")]
  629.         private static extern uint GdipEmfToWmfBits(IntPtr _hEmf, uint _bufferSize,
  630.             byte[] _buffer, int _mappingMode, EmfToWmfBitsFlags _flags);
  631.         /// <summary>
  632.         /// Wraps the image in an Enhanced Metafile by drawing the image onto the
  633.         /// graphics context, then converts the Enhanced Metafile to a Windows
  634.         /// Metafile, and finally appends the bits of the Windows Metafile in HEX
  635.         /// to a string and returns the string.
  636.         /// </summary>
  637.         /// <param name="_image"></param>
  638.         /// <returns>
  639.         /// A string containing the bits of a Windows Metafile in HEX
  640.         /// </returns>
  641.         private string GetRtfImage(Image _image)
  642.         {
  643.             StringBuilder _rtf = null;
  644.             // Used to store the enhanced metafile
  645.             MemoryStream _stream = null;
  646.             // Used to create the metafile and draw the image
  647.             Graphics _graphics = null;
  648.             // The enhanced metafile
  649.             Metafile _metaFile = null;
  650.             // Handle to the device context used to create the metafile
  651.             IntPtr _hdc;
  652.             try
  653.             {
  654.                 _rtf = new StringBuilder();
  655.                 _stream = new MemoryStream();
  656.                 // Get a graphics context from the RichTextBox
  657.                 using (_graphics = this.CreateGraphics())
  658.                 {
  659.                     // Get the device context from the graphics context
  660.                     _hdc = _graphics.GetHdc();
  661.                     // Create a new Enhanced Metafile from the device context
  662.                     _metaFile = new Metafile(_stream, _hdc);
  663.                     // Release the device context
  664.                     _graphics.ReleaseHdc(_hdc);
  665.                 }
  666.                 // Get a graphics context from the Enhanced Metafile
  667.                 using (_graphics = Graphics.FromImage(_metaFile))
  668.                 {
  669.                     // Draw the image on the Enhanced Metafile
  670.                     _graphics.DrawImage(_image, new Rectangle(0, 0, _image.Width, _image.Height));
  671.                 }
  672.                 // Get the handle of the Enhanced Metafile
  673.                 IntPtr _hEmf = _metaFile.GetHenhmetafile();
  674.                 // A call to EmfToWmfBits with a null buffer return the size of the
  675.                 // buffer need to store the WMF bits.  Use this to get the buffer
  676.                 // size.
  677.                 uint _bufferSize = GdipEmfToWmfBits(_hEmf, 0, null, MM_ANISOTROPIC,
  678.                     EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault);
  679.                 // Create an array to hold the bits
  680.                 byte[] _buffer = new byte[_bufferSize];
  681.                 // A call to EmfToWmfBits with a valid buffer copies the bits into the
  682.                 // buffer an returns the number of bits in the WMF.  
  683.                 uint _convertedSize = GdipEmfToWmfBits(_hEmf, _bufferSize, _buffer, MM_ANISOTROPIC,
  684.                     EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault);
  685.                 // Append the bits to the RTF string
  686.                 for (int i = 0; i < _buffer.Length; ++i)
  687.                 {
  688.                     _rtf.Append(String.Format("{0:X2}", _buffer[i]));
  689.                 }
  690.                 return _rtf.ToString();
  691.             }
  692.             finally
  693.             {
  694.                 if (_graphics != null)
  695.                     _graphics.Dispose();
  696.                 if (_metaFile != null)
  697.                     _metaFile.Dispose();
  698.                 if (_stream != null)
  699.                     _stream.Close();
  700.             }
  701.         }
  702.         #endregion
  703.         #region RTF Helpers
  704.         /// <summary>
  705.         /// Creates a font table from a font object.  When an Insert or Append 
  706.         /// operation is performed a font is either specified or the default font
  707.         /// is used.  In any case, on any Insert or Append, only one font is used,
  708.         /// thus the font table will always contain a single font.  The font table
  709.         /// should have the form ...
  710.         /// 
  711.         /// {fonttbl{f0[FAMILY]fcharset0 [FONT_NAME];}
  712.         /// </summary>
  713.         /// <param name="_font"></param>
  714.         /// <returns></returns>
  715.         private string GetFontTable(Font _font)
  716.         {
  717.             StringBuilder _fontTable = new StringBuilder();
  718.             // Append table control string
  719.             _fontTable.Append(@"{fonttbl{f0");
  720.             _fontTable.Append(@"");
  721.             // If the font's family corresponds to an RTF family, append the
  722.             // RTF family name, else, append the RTF for unknown font family.
  723.             if (rtfFontFamily.Contains(_font.FontFamily.Name))
  724.                 _fontTable.Append(rtfFontFamily[_font.FontFamily.Name]);
  725.             else
  726.                 _fontTable.Append(rtfFontFamily[FF_UNKNOWN]);
  727.             // fcharset specifies the character set of a font in the font table.
  728.             // 0 is for ANSI.
  729.             _fontTable.Append(@"fcharset134 ");
  730.             // Append the name of the font
  731.             _fontTable.Append(_font.Name);
  732.             // Close control string
  733.             _fontTable.Append(@";}}");
  734.             return _fontTable.ToString();
  735.         }
  736.         /// <summary>
  737.         /// Creates a font table from the RtfColor structure.  When an Insert or Append
  738.         /// operation is performed, _textColor and _backColor are either specified
  739.         /// or the default is used.  In any case, on any Insert or Append, only three
  740.         /// colors are used.  The default color of the RichTextBox (signified by a
  741.         /// semicolon (;) without a definition), is always the first color (index 0) in
  742.         /// the color table.  The second color is always the text color, and the third
  743.         /// is always the highlight color (color behind the text).  The color table
  744.         /// should have the form ...
  745.         /// 
  746.         /// {colortbl ;[TEXT_COLOR];[HIGHLIGHT_COLOR];}
  747.         /// 
  748.         /// </summary>
  749.         /// <param name="_textColor"></param>
  750.         /// <param name="_backColor"></param>
  751.         /// <returns></returns>
  752.         private string GetColorTable(RtfColor _textColor, RtfColor _backColor)
  753.         {
  754.             StringBuilder _colorTable = new StringBuilder();
  755.             // Append color table control string and default font (;)
  756.             _colorTable.Append(@"{colortbl ;");
  757.             // Append the text color
  758.             _colorTable.Append(rtfColor[_textColor]);
  759.             _colorTable.Append(@";");
  760.             // Append the highlight color
  761.             _colorTable.Append(rtfColor[_backColor]);
  762.             _colorTable.Append(@";}n");
  763.             return _colorTable.ToString();
  764.         }
  765.         /// <summary>
  766.         /// Called by overrided RichTextBox.Rtf accessor.
  767.         /// Removes the null character from the RTF.  This is residue from developing
  768.         /// the control for a specific instant messaging protocol and can be ommitted.
  769.         /// </summary>
  770.         /// <param name="_originalRtf"></param>
  771.         /// <returns>RTF without null character</returns>
  772.         private string RemoveBadChars(string _originalRtf)
  773.         {
  774.             return _originalRtf.Replace("", "");
  775.         }
  776.         #endregion
  777.         #region print
  778.         // Render the contents of the RichTextBox for printing
  779.         // Return the last character printed + 1 (printing start from this point for next page)
  780.         public int Print(int charFrom, int charTo, PrintPageEventArgs e)
  781.         {
  782.             //Calculate the area to render and print
  783.             RECT rectToPrint;
  784.             rectToPrint.Top = (int)(e.MarginBounds.Top * anInch);
  785.             rectToPrint.Bottom = (int)(e.MarginBounds.Bottom * anInch);
  786.             rectToPrint.Left = (int)(e.MarginBounds.Left * anInch);
  787.             rectToPrint.Right = (int)(e.MarginBounds.Right * anInch);
  788.             //Calculate the size of the page
  789.             RECT rectPage;
  790.             rectPage.Top = (int)(e.PageBounds.Top * anInch);
  791.             rectPage.Bottom = (int)(e.PageBounds.Bottom * anInch);
  792.             rectPage.Left = (int)(e.PageBounds.Left * anInch);
  793.             rectPage.Right = (int)(e.PageBounds.Right * anInch);
  794.             IntPtr hdc = e.Graphics.GetHdc();
  795.             FORMATRANGE fmtRange;
  796.             fmtRange.chrg.cpMax = charTo; //Indicate character from to character to 
  797.             fmtRange.chrg.cpMin = charFrom;
  798.             fmtRange.hdc = hdc;                    //Use the same DC for measuring and rendering
  799.             fmtRange.hdcTarget = hdc;              //Point at printer hDC
  800.             fmtRange.rc = rectToPrint;             //Indicate the area on page to print
  801.             fmtRange.rcPage = rectPage;            //Indicate size of page
  802.             IntPtr res = IntPtr.Zero;
  803.             IntPtr wparam = IntPtr.Zero;
  804.             wparam = new IntPtr(1);
  805.             //Get the pointer to the FORMATRANGE structure in memory
  806.             IntPtr lparam = IntPtr.Zero;
  807.             lparam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fmtRange));
  808.             Marshal.StructureToPtr(fmtRange, lparam, false);
  809.             //Send the rendered data for printing 
  810.             res = SendMessage(Handle, EM_FORMATRANGE, wparam, lparam);
  811.             //Free the block of memory allocated
  812.             Marshal.FreeCoTaskMem(lparam);
  813.             //Release the device context handle obtained by a previous call
  814.             e.Graphics.ReleaseHdc(hdc);
  815.             //Return last + 1 character printer
  816.             return res.ToInt32();
  817.         }
  818.         #endregion
  819.     }
  820. }