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

RichTextBoxEx的更多相关文章

  1. RichTextBoxEx2

    using System;using System.Collections.Specialized;using System.Drawing;using System.Drawing.Imaging; ...

  2. 关于richtextbox改变字体颜色,加下划线

    参考了三份有用的资料: 1.关于richtextbox设置字体颜色的问题 http://biancheng.dnbcw.net/c/180381.html 2.C#Winform使用扩展方法自定义富文 ...

  3. 反编译示例:mxd检查

    gisoralce在博客园发布了一个mxd检查工具,主要功能是将arcgis的mxd数据源有效性(含矢量和影像)检查.检查是否为相对路径,自动保存为相对路径. 这是一个未加壳的.NET程序,正好拿来练 ...

  4. C# 第三方库

    基本上选用的都是 https://www.nuget.org 分类中最流行的那个库 1. 日志工具库 NLOG Stackify.com 简单入门文章  https://stackify.com/nl ...

  5. C#中给RICHTEXTBOX加上背景图片

    在系统自带的RichTextBox中是无法给它设置背景图片,但是我们在某些场合可能需要给RichTextBox设置背景图片.那么怎么实现这一想法呢?经过研究发现通过其它巧妙的途径可以给RichText ...

随机推荐

  1. 【Bugly干货分享】iOS内存管理:从MRC到ARC实践

    Bugly 技术干货系列内容主要涉及移动开发方向,是由Bugly邀请腾讯内部各位技术大咖,通过日常工作经验的总结以及感悟撰写而成,内容均属原创,转载请标明出处. 对于iOS程序员来说,内存管理是入门的 ...

  2. Java虚拟机10:类加载器

    类与类加载器 虚拟机设计团队把类加载阶段张的"通过一个类的全限定名来获取此类的二进制字节流"这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类.实现这 ...

  3. Java虚拟机3:常用JVM命令参数

    之后写的东西就会用到虚拟机参数了,现在这里汇个总自己平时用到的.看到的一些虚拟机参数.现在看不懂没关系,反正之后都会用到的: (1)-Xms20M 表示设置堆容量的最小值为20M,必须以M为单位 (2 ...

  4. Entity Framework 5.0系列之Code First数据库迁移

    我们知道无论是"Database First"还是"Model First"当模型发生改变了都可以通过Visual Studio设计视图进行更新,那么对于Cod ...

  5. Hello Mybatis 03 数据关联

    ResultMap 在实际的开发中,数据库不总是我们希望看到的样子.比如我们希望User的主键是id但是数据库偏偏喜欢叫它u_id,这样一来原先的resultType似乎就失效了,不带这么玩的,整个人 ...

  6. EF架构~在ef中支持IQueryable级别的Contains被翻译成了Exists,性能可以接受!

    回到目录 Entityframeworks很聪明 不错,非常不错!ef里的contains比linq to sql里的contains有了明显的提升,事实上,是在进行SQL语句翻译上有所提升,在lin ...

  7. paip.lucene 4.3 中文语义搜索最佳实践

    paip.lucene 4.3 中文语义搜索最佳实践 首先一个问题是要不要使用lucene 自带的分词器...我觉得最好不使用哪自带的分词器.效果还凑火,就是不好控制... 先使用ik,ict,mms ...

  8. Jenkins的系统设置

    1.登录Jenkins进入以下界面: 2.点击 系统管理 3.点击 系统设置 (下图的系统设置是已经设置好的) 4.这里设置主要设置 Jenkins URL (这里我是测试的所以使用默认的)与 邮件的 ...

  9. Asp.Net实现无刷新文件上传并显示进度条(非服务器控件实现)(转)

    Asp.Net实现无刷新文件上传并显示进度条(非服务器控件实现) 相信通过Asp.Net的服务器控件上传文件在简单不过了,通过AjaxToolkit控件实现上传进度也不是什么难事,为什么还要自己辛辛苦 ...

  10. hibernate(四) 双向多对多映射关系

    序言 莫名长了几颗痘,真TM疼,可能是现在运动太少了,天天对着电脑,决定了,今天下午花两小时去跑步了, 现在继上一章节的一对多的映射关系讲解后,今天来讲讲多对多的映射关系把,明白了一对多,多对多个人感 ...