RichTextBoxEx

  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 = 1;
 99         private const int MM_LOMETRIC = 2;
100         private const int MM_HIMETRIC = 3;
101         private const int MM_LOENGLISH = 4;
102         private const int MM_HIENGLISH = 5;
103         private const int MM_TWIPS = 6;
104         // Ensures that the metafile maintains a 1:1 aspect ratio
105         private const int MM_ISOTROPIC = 7;
106         // Allows the x-coordinates and y-coordinates of the metafile to be adjusted
107         // independently
108         private const int MM_ANISOTROPIC = 8;
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 = 2540;
114         // The number of twips in an inch
115         // For more information, see GetImagePrefix() method.
116         private const int TWIPS_PER_INCH = 1440;
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, 0);
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, 0);
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((2 * _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(0, 0, _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, 0, 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 = 0; 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 }
时间: 2024-10-13 01:43:01

RichTextBoxEx的相关文章

richTextBox扩展,实现任意文本的超链接

普通的richTextBox只能为“http://, ftp:// 或其他标准协议”自动添加超链接,不能为之外的文本添加超链接, 现在有个扩展可以实现为任意文本添加超链接,扩展地址: http://www.codeproject.com/Articles/9196/Links-with-arbitrary-text-in-a-RichTextBox 使用方法: 1,新建项目 2,解决方案→添加→现有相(浏览到扩展源码中RichTextBoxLinks.csproj位置)添加RichTextBox

RichTextBoxEx2

using System;using System.Collections.Specialized;using System.Drawing;using System.Drawing.Imaging;using System.IO;using System.Runtime.InteropServices;using System.Text;using System.Windows.Forms; namespace RichTextBoxEx.Controls{ #region Public En