Insert Plain Text and Images into RichTextBox at Runtime‘

https://www.codeproject.com/Articles/4544/Insert-Plain-Text-and-Images-into-RichTextBox-at-R

Khendys Gordon, 15 Jul 2003

   4.90 (120 votes)

1

2

3

4

5

4.90/5 - 120 votes
5 removed
μ 4.77, σa 0.93 [?]
 
Rate:
Add a reason or comment to your vote: x
Adding a comment to your rating is optional
This article describes how to programmatically insert text and images into a RichTextBox at runtime.

Introduction

If you've searched the Internet for an easy way to insert images into a RichTextBox, chances are you've come across variations of the following solution which copies the image to the clipboard, pastes it in the target RichTextBox, and clears the contents of the clipboard.

public void InsertImage()  {
...
string lstrFile = fileDialog.FileName;
Bitmap myBitmap = new Bitmap(lstrFile);
// Copy the bitmap to the clipboard.
Clipboard.SetDataObject(myBitmap);
// Get the format for the object type.
DataFormats.Format myFormat = DataFormats.GetFormat (DataFormats.Bitmap);
// After verifying that the data can be pasted, paste
if(NoteBox.CanPaste(myFormat)) {
NoteBox.Paste(myFormat);
}
else {
MessageBox.Show("The data format that you attempted site" +
" is not supportedby this control.");
}
...
}

This is not a good solution because it alters the clipboard without informing the user, which can be a real inconvenience. Other solutions hard-code thousands of lines of the HEX representation of images into the program, but that's not very flexible (or practical). There is also no standard way of inserting plain text into a RichTextBox at runtime. This article offer a solution to these problems.

The solution must:

  1. Allow plain text to be programmatically inserted into or appended to the content if a RichTextBox at runtime.
  2. Allow the font, text color, and highlight color (background color of the text) to be specified when inserting or appending plain text to the content of a RichTextBox.
  3. Allow images to be inserted programmatically without the use of the clipboard.

The content of a RichTextBox can be in either plain text format or Rich Text Format. Henceforth Rich Text Format is simply as RTF.

NOTE: Converting plain text to RTF is really about appending strings to create the RTF codes. It is very simple, but one needs to be familiar with the RTF document structure and control words. In an effort not to turn the article into an RTF tutorial, the methods for inserting plain text will be discussed briefly, however for a full explanation the reader should view the source code and should read the RTF Specification v1.6.

Background

Before getting into the solution, an introduction to RTF documents and Metafiles is warranted.

RTF Documents

RTF is a structured file format that uses control words and symbols to create a file that can be used in different operating environments. When being read, the RTF control words and symbols are processed by an RTF reader which converts RTF into formatted text. This is similar to how a browser displays HTML to a user. In this case, the RTF reader is the RichTextBox.

The RTF Specification is a 250+ page document, so attempting to summarize it in this article would be a severe injustice to its authors. The only RTF control words that will be explained are those used when inserting an image. For a complete introduction to RTF, please read RTF Specification v1.6.

Metafiles

In the .NET Framework, the Metafile class is derived from the Image class, however metafiles are not raster images like those that can be converted to Bitmap objects. A raster image is composed of rectangular arrays of pixels known as bitmaps. A metafile is a vector image which contains a geometrical representation of an image in terms of drawing commands. A Metafile can be converted to a Bitmap using the .NET Framework, but a Bitmap cannot be converted to a Metafile using .NET only. However, bitmaps can be embedded within metafiles.

The .NET Framework offers support for two types of metafiles: Windows Metafile Format (WMF) and Enhanced Metafile Format (EMF). These metafiles differ in the drawing commands they support; Enhanced Metafiles support many more drawing commands than Windows Metafiles. According to Microsoft's documentation, the WMF format should not be used and is only included for backward compatibility, however this solution uses the WMF. For complete documentation on metafiles click here.

Inserting and Appending Plain Text

Insertion of RTF into a RichTextBox is done by assigning a string representation of an RTF document to the RichTextBox.Rtf property or the RichTextBox.SelectedRtf property. When the latter is used to insert, if there is text selected at the time of insertion, the text will be replaced. If no text is selected, the text is inserted at the location of the caret.

Appending Text

Plain text is appended to the content of the RichTextBox by moving the caret to the end of the RTF text in the RichTextBox and performing an insert.

/// Appends the text using the given font, text,
/// and highlight colors. Simply
/// moves the caret to the end of the RichTextBox's text
/// and makes a call to insert.
public void AppendTextAsRtf(string _text, Font _font,
RtfColor _textColor, RtfColor _backColor) { // Move carret to the end of the text
this.Select(this.TextLength, 0); InsertTextAsRtf(_text, _font, _textColor, _backColor);
}

There are three other overloads of AppendTextAsRtf which all eventually call the overload above.

/// Appends the text using the current font, text, and highlight colors.
public void AppendTextAsRtf(string _text) {
AppendTextAsRtf(_text, this.Font);
} /// Appends the text using the given font, and
/// current text and highlight colors.
public void AppendTextAsRtf(string _text, Font _font) {
AppendTextAsRtf(_text, _font, textColor);
} /// Appends the text using the given font and text color, and the current
/// highlight color.
public void AppendTextAsRtf(string _text, Font _font, RtfColor _textColor) {
AppendTextAsRtf(_text, _font, _textColor, highlightColor);
}

Inserting Text

When inserting text into a RichTextBox, the text must be a document in Rich Text Format. An RTF document consists of a header and document area which must conform to the RTF Specification. The header consists of, among other things, the language being used, and tables of the fonts and colors used in the document. The document area is where the actual contents of the document are stored and formatted. Upon a call to the InsertTextAsRtf method, an RTF header is constructed and the plain text is added to and formatted in the document area.

public void InsertTextAsRtf(string _text, Font _font,
RtfColor _textColor, RtfColor _backColor) { StringBuilder _rtf = new StringBuilder(); // Append the RTF header
_rtf.Append(RTF_HEADER); // Create the font table from the font passed in and append it to the
// RTF string
_rtf.Append(GetFontTable(_font)); // Create the color table from the colors passed in and append it to the
// RTF string
_rtf.Append(GetColorTable(_textColor, _backColor)); // Create the document area from the text to be added as RTF and append
// it to the RTF string.
_rtf.Append(GetDocumentArea(_text, _font)); this.SelectedRtf = _rtf.ToString();
}

There are three other overloads to InsertTextAsRtf which are shown below. For an in-depth look at this procedure please view the source code and refer to the RTF Specification v1.6.

/// Inserts the text using the current font, text, and highlight colors.
public void InsertTextAsRtf(string _text) {
InsertTextAsRtf(_text, this.Font);
} /// Inserts the text using the given font, and current text and highlight
/// colors.
public void InsertTextAsRtf(string _text, Font _font) {
InsertTextAsRtf(_text, _font, textColor);
} /// Inserts the text using the given font and text color, and the current
/// highlight color.
public void InsertTextAsRtf(string _text, Font _font,
RtfColor _textColor) {
InsertTextAsRtf(_text, _font, _textColor, highlightColor);
}

Inserting an Image

When an image is pasted into a RichTextBox (or WordPad or Microsoft Word), the image is embedded in a Windows Metafile (WMF) and the metafile is placed in the document. The InsertImage method does the same thing, but without using the clipboard. According to the RTF Specification v1.6, it is possible to insert bitmaps, JPEGs, GIFs, PNGs, and Enhanced Metafiles directly into an RTF document without first embedding them in a Windows Metafile. However, while this works with Microsoft Word, if images are not embedded in a Windows Metafile, WordPad and RichTextBox simply ignore them.

Metafiles

A Windows Metafile is the metafile format that was originally supported on Windows 1.0 (1985). They have limited capabilities and are supported in the Windows Forms only for backward compatibility. .NET does not directly support the creation of Windows Metafiles, but it can read them. The creation of Enhanced Metafiles is supported, however, and Enhanced Metafiles can be converted to Windows Metafiles using unmanaged code. GDI+ (gdiplus.dll) contains a function called EmfToWmfBits(), which converts an Enhanced Metafile to a Windows Metafile. This function is shown below.

[DllImportAttribute("gdiplus.dll")]
private static extern uint GdipEmfToWmfBits (IntPtr _hEmf,
uint _bufferSize, byte[] _buffer,
int _mappingMode, EmfToWmfBitsFlags _flags);

_hEmf is the handle to the Enhanced Metafile being converted. _bufferSize is the size of the buffer used to store the converted Windows Metafile. _buffer is an array of bytes used to store the converted Windows Metafile. _mappingMode refers to the mapping mode of the image. The mapping modes define the orientation and units used to transform the image, and are provided by the Windows API. MM_ANISOTROPIC is used as the mapping mode in this solution. It allows both axes of the image to be changed independently. _flags indicate the options for converting the metafile.

The image is embedded in an Enhanced Metafile by drawing the the image onto a graphics context created from the metafile. The Enhanced Metafile is then converted to a Windows Metafile. The Enhanced Metafile is created using the constructor overload below.

Metafile(Stream stream, IntPtr referencedHdc);

This creates a new Enhanced Metafile using the device context referencedHdc and stores it in stream. A device context is a structure that contains information that controls the display of text and graphics on a particular device. Metafiles need to be associated with a device context to obtain resolution information. Every Graphics object can provide a handle to its device context. The device context of the RichTextBox is obtained by making a call to its GetGraphics method, and then calling the GetHdc method of the resultant Graphics object.

...

// Memory stream where Metafile will be stored
_stream = new MemoryStream(); // Get a graphics context from the RichTextBox
using(_graphics = this.CreateGraphics()) { // Get the device context from the graphics context
_hdc = _graphics.GetHdc(); // Create a new Enhanced Metafile from the device context
_metaFile = new Metafile(_stream, _hdc); // Release the device context
_graphics.ReleaseHdc(_hdc);
} ...

A Graphics context is now created from the metafile and the image is drawn (embedded) in the file.

...

// Get a graphics context from the Enhanced Metafile
using(_graphics = Graphics.FromImage(_metaFile)) { // Draw the image on the Enhanced Metafile
_graphics.DrawImage(_image, new Rectangle(0, 0,
_image.Width, _image.Height)); } ...

Calling EmfToWmfBits with a null buffer parameter returns the size of the buffer necessary to store the Windows Metafile. This is used to create an array large enough to hold the Windows Metafile.

...

// Get number of bytes
uint _bufferSize = GdipEmfToWmfBits(_hEmf, 0, null,
MM_ANISOTROPIC, EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault); // Create an array to hold the file
byte[] _buffer = new byte[_bufferSize]; ...

Calling EmfToWmfBits with an instantiated buffer copies the metafile into the buffer and returns the number of bytes copied.

...

// Get the file
uint _convertedSize = GdipEmfToWmfBits(_hEmf, _bufferSize,
_buffer, MM_ANISOTROPIC,
EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault); ...

A HEX representation of the image is created from the array and is now ready to be inserted into the RichTextBox.

...

// Append the bits to the RTF string
for(int i = 0; i < _buffer.Length; ++i) {
_rtf.Append(String.Format("{0:X2}", _buffer[i]));
} return _rtf.ToString(); ...

RTF Picture Destination

The minimum control words used to define a picture or image in an RTF document are "{\pict\wmetafile8\picw[N]\pich[N]\picwgoal[N]\pichgoal[N] [BYTES]}" where ...

\pict - The starting picture or image tag
\wmetafile[N] - Indicates that the image type is a Windows Metafile. [N] = 8 specifies that the metafile's axes can be sized independently.
\picw[N] and \pich[N] - Define the size of the image, where[N] is in units of hundreths of millimeters (0.01)mm.
\picwgoal[N] and \pichgoal[N] - Define the target size of the image, where [N] is in units of twips.
[BYTES] - The HEX representation of the image.

The horizontal and vertical resolutions at which the ExRichTextBox is being displayed are necessary for the above calculations to be made. These values are obtained in the default constructor of ExRichTextBox from a Graphics object and stored as xDpi and yDpi respectively. (On most systems, both these values are 96 Dpi, but why assume?)

The metafile's dimensions in (0.01)mm are calculated using the following conversion units and formula. (The example below explains how to find the current width, but the same formula is used to find the height by substituting height and vertical resolution for width and horizontal resolution respectively.)

1 Inch = 2.54 cm
1 Inch = 25.4 mm
1 Inch = 2540 (0.01)mm

[N] = current width of the metafile in hundredths of millimeters (0.01mm)
  = Image Width in Inches * Number of (0.01mm) per inch
  = (Image Width in Pixels / Graphics Context's Horizontal Resolution) * 2540
  = (Image Width in Pixels / Graphics.DpiX) * 2540
...

// Calculate the current width of the image in (0.01)mm
int picw = (int)Math.Round((_image.Width / xDpi) * HMM_PER_INCH); // Calculate the current height of the image in (0.01)mm
int pich = (int)Math.Round((_image.Height / yDpi) * HMM_PER_INCH); ...

Twips are screen-independent units used to ensure that the placement and proportion of screen elements in a screen application are the same on all display systems. The metafile's target dimensions in twips are calculated using the following conversion units and formula. (The example below explains how to find the target width, but the same formula is used to find the height by substituting height and vertical resolution for width and horizontal resolution respectively.)

1 Twip = 1/20 Point
1 Point = 1/72 Inch
1 Twip = 1/1440 Inch

[N] = target width of the metafile in twips
  = Image Width in Inches * Number of twips per inch
  = (Image Width in Pixels / Graphics Context's Horizontal Resolution) * 1440
  = (Image Width in Pixels / Graphics.DpiX) * 1440
...

// Calculate the target width of the image in twips
int picwgoal = (int)Math.Round((_image.Width / xDpi) * TWIPS_PER_INCH); // Calculate the target height of the image in twips
int pichgoal = (int)Math.Round((_image.Height / yDpi) * TWIPS_PER_INCH); ...

After the RTF representation of the image is created the image is inserted into the RTF document similarly to how text is inserted. If any text is selected, the image replaces the selected text. If no text is selected, the image is inserted at the location of the caret.

Using the code

To use the ExRichTextBox simply include the ExRichTextBox project as a reference in your project or compile the .dll and add it to your VS.NET Toolbox. There are two public properties that can be set: TextColor is the color that inserted text will have if no text color is specified when inserting; HighlightColor is the background color of inserted text if no highlight color is specified when inserting. By default, these properties are set to Black and White respectively. Two examples of using the control are included in the project download. The first simulates a chat window. The user can click an emoticon or type ":)" to insert a smiley (The sample only looks for the first occurrence of ":)"). It also illustrates how to insert plain text as RTF. The relevant methods are shown below.

...

// When an emoticon is clicked, insert its image into to RTF
private void cmenu_Emoticons_Click(object _sender,
EventArgs _args) { rtbox_SendMessage.InsertImage(_item.Image); } ... private void btn_SendMessage_Click(object sender,
System.EventArgs e) { // Add fake message owner using insert
rtbox_MessageHistory.AppendTextAsRtf("Local User Said\n\n",
new Font(this.Font, FontStyle.Underline | FontStyle.Bold),
RtfColor.Blue, RtfColor.Yellow); // Just to show it's possible, if the text contains a smiley face [:)]
// insert the smiley image instead. This is not
// a practical way to do this.
int _index;
if ((_index = rtbox_SendMessage.Find(":)")) > -1) {
rtbox_SendMessage.Select(_index, ":)".Length);
rtbox_SendMessage.InsertImage(
new Bitmap(typeof(IMWindow), "Emoticons.Beer.png"));
} // Add the message to the history
rtbox_MessageHistory.AppendRtf(rtbox_SendMessage.Rtf); // Add a newline below the added line, just to add spacing
rtbox_MessageHistory.AppendTextAsRtf("\n"); // History gets the focus
rtbox_MessageHistory.Focus(); // Scroll to bottom so newly added text is seen.
rtbox_MessageHistory.Select(rtbox_MessageHistory.TextLength, 0);
rtbox_MessageHistory.ScrollToCaret(); // Return focus to message text box
rtbox_SendMessage.Focus(); // Add the Rtf Codes to the RtfCode Window
frm_RtfCodes.AppendText(rtbox_SendMessage.Rtf); // Clear the SendMessage box.
rtbox_SendMessage.Text = String.Empty;
} ...

The second sample included is a way to check how the ExRichTextBox handles large images. A user can insert bitmaps, JPEGs, GIFs, Icons, PNGs, and TIFFs, or insert plain text, all from the menu.

Points of Interest

The ExRichTextBox is a good solution for inserting small images, but it takes a full 2.65 seconds to insert a 24bit, 432 X 567 JPEG into the second sample application. That's because the image is being copied to an array of bytes then to a string, then inserted. There should be a way to insert the byte representation of the image at a lower level, skipping the string conversion. However, the author is currently not that familiar with the Win32 API, so this will be an improvement in the near future.

&amp;lt;a href="https://pubads.g.doubleclick.net/gampad/jump?iu=/6839/lqm.codeproject.site/Desktop-Development/Edit-Controls/General&amp;amp;sz=300x250&amp;amp;c=866334"&amp;gt;&amp;lt;img src="https://pubads.g.doubleclick.net/gampad/jump?iu=/6839/lqm.codeproject.site/Desktop-Development/Edit-Controls/General&amp;amp;sz=300x250&amp;amp;c=866334" width="300px" height="250px" target="_blank"/&amp;gt;&amp;lt;/a&amp;gt;

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Insert Plain Text and Images into RichTextBox at Runtime的更多相关文章

  1. 如何撤销 PhpStorm/Clion 等 JetBrains 产品的 “Mark as Plain Text” 操作 ?

    当把某个文件“Mark as Plain Text”时,该文件被当做普通文本,就不会有“代码自动完成提示”功能,如下图所示: 但是呢,右键菜单中貌似没有 相应的撤销 操作, 即使是把它删除,再新建一个 ...

  2. Jade之Plain Text

    Plain Text jade提供了3种得到纯文本的方法. Piped Text 添加纯文本的一个最简单的方法就是在文本最前面加|符号即可. jade: p | It must always be o ...

  3. [Regular Expressions] Find Plain Text Patterns

    The simplest use of Regular Expressions is to find a plain text pattern. In this lesson we'll look a ...

  4. How to return plain text from AWS Lambda & API Gateway

    With limited experience in AWS Lambda & API Gateway, it's struggling to find the correct way to ...

  5. Plain text considered harmful: A cross-domain exploit

    referer:http://balpha.de/2013/02/plain-text-considered-harmful-a-cross-domain-exploit/ Data from aro ...

  6. text/plain && text/html

    text/plain和text/html都是Content-Type; text/plain : 页面以文本形式输出 text/html:  页面以html格式输出

  7. 解决 Xamarin 拖拽Plain Text 于Layout上时 出现 “The layout could not be loaded:java.lang.System.arraycopy([CI[CII)V” 错误

    右键项目属性

  8. UnicodeMath数学公式编码_翻译(Unicode Nearly Plain - Text Encoding of Mathematics Version 3)

    目录 完整目录 1. 简介 2. 编码简单数学表达式 2.1 分数 2.2 上标和下标 2.3 空白(空格)字符使用 3. 编码其他数学表达式 3.1 分隔符 强烈推荐本文简明版UnicodeMath ...

  9. TRichTextBox – A universal RichTextBox which can display animated images and more

    TRichTextBox – A universal RichTextBox which can display animated images and more trestan, 7 Dec 201 ...

随机推荐

  1. 【转】yahoo前端优化军规

    雅虎给出了前端优化的34条法则(包括Yslow规则22条) 详细说明,下载转发 ponytail 的译文(来自帕兰映像). Minimize HTTP Requests 减少http请求 图片.css ...

  2. UWP开发随笔——使用SQLite数据库

    摘要 大多数的app都需要数据存储,在数据存储这方面,强大的windows把app数据分为两种:settings和files,并提供了十分简洁的api,让开发者能够轻松使用.但是在有些场景下,app的 ...

  3. 浅谈Excel开发:五 Excel RTD函数

        上文介绍了Excel中的UDF函数,本文介绍一下同样重要的RTD函数.从Excel 2002开始,Excel引入了一种新的查看和更新实时数据的机制,即real-time data简称RTD函数 ...

  4. P,NP,NP_hard,NP_complete问题定义

    背景:在看李航的<统计学习方法时>提到了NP完全问题,于是摆之. 问题解答:以下是让我豁然开朗的解答的摘抄: 最简单的解释:P:算起来很快的问题NP:算起来不一定快,但对于任何答案我们都可 ...

  5. Atitit.架构设计趋势 设计模式 ---微服务架构  soa

    Atitit.架构设计趋势 设计模式 ---微服务架构  soa 什么是微服务架构?1 .微服务与SOA的关系 :微服务架架构师面向服务架构(SOA)的一种特定实现1 微服务与康威定律2 微服务的一些 ...

  6. Drupal网站开发实践--自定义购物流程

    由于Commerce模块自带的购物流程步骤过多,界面不太美观,所以需要重新设计. 改造后的购物流程分成两部:购物车->结算,就两个页面.购物车页面可以修改商品的数量,删除购物车内商品,查看总金额 ...

  7. Yii2框架RESTful API教程(二) - 格式化响应,授权认证和速率限制

    之前写过一篇Yii2框架RESTful API教程(一) - 快速入门,今天接着来探究一下Yii2 RESTful的格式化响应,授权认证和速率限制三个部分 一.目录结构 先列出需要改动的文件.目录如下 ...

  8. Java Synchronized Blocks

    From http://tutorials.jenkov.com/java-concurrency/synchronized.html By Jakob Jenkov   A Java synchro ...

  9. 序列sequence中的cache问题

    Oracle中序列Sequence的创建语法如下: CREATE SEQUENCE [ schema. ] sequence [ { INCREMENT BY | START WITH } integ ...

  10. 修改NLS_DATE_FORMAT的四种方式

    一. 在用户环境变量中指定(LINUX) 在用户的.bash_profile中增加两句: export NLS_LANG=AMERICAN ---这一句必须指定,否则下一句不生效.export NLS ...