新凡

  博客园 :: 首页 :: :: 联系 :: 订阅 :: 管理 ::

ExRichTextBox

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

 

posted on 2013-04-23 22:40  新凡  阅读(292)  评论(0)    收藏  举报