In the Drawing Simple Text Objects topic, we explored how to draw various types of text and modify properties like font, outline, and fill. We also covered text effects and transformations, lists, and OpenType features. This topic addresses how to format portions of text within a single string, such as applying different font styles to specific parts of the text.
Additionally, this topic covers Measuring Formatted Text and Handling Exceptions.
In Graphics Mill, you can format any type of text. Specifically, any child class of Text supports formatting. For demonstration, we'll use the BoundedText class, but the same principles apply to other text types like PlainText, PathText, DoublePathText, and ArtText.
Text formatting in Graphics Mill uses the <span> and <p> tags with CSS-like style attributes. Here's how it works:
<span> and <p> tags.style attribute.Here's an example:
using (var bitmap = new Bitmap(600, 400, PixelFormat.Format24bppRgb, new RgbColor(255, 255, 255, 255)))
using (var graphics = bitmap.GetGraphics())
{
var brush = new SolidBrush(RgbColor.Black);
var text = @"<p style='first-line-indent:20pt; space-before:30pt; space-after:20pt;'>Lorem ipsum dolor sit <span style='color:red;'>amet</span>," +
@"consectetur adipiscing elit. <span style='bold:true;underline:true;color:rgb(0,0,255)'>Cras</span> elementum quam ac nisi varius gravida. " +
@"Mauris ornare, <span style='font-name:Times New Roman;font-size:60pt;pen-color:green;pen-width:1px;color:yellow;'>dolor</span> et scelerisque " +
@"volutpat, <span style='italic:true;color:gray;'>enim urna commodo odio, <span style='color:green;'>consequat</span> fermentum sem arcu</span>" +
@" sit amet nisl.</p> <p style='first-line-indent:40pt; space-before:60pt; space-after:10pt;'>Aliquam tincidunt id neque in gravida. " +
@"Mauris mollis est vulputate suscipit facilisis.</p>";
var boundedText = new BoundedText(text, graphics.CreateFont("Verdana", 26f), brush)
{
Rectangle = new System.Drawing.RectangleF(20f, 20f, 560f, 360f)
};
graphics.DrawText(boundedText);
bitmap.Save(@"Images\Output\DrawFormattedText.png");
}
This code produces the following image:
You can also use the <br/> tag to insert line breaks.
To display reserved symbols, use the following combinations:
& for & (ampersand)< for < (less than)> for > (greater than)Configure a paragraph's style to control text direction, indentation, and spacing.
| Name | Description | Examples |
|---|---|---|
| direction | Specifies text direction (RTL or LTR). |
style='direction:RTL'
|
| first-line-indent | Indents the first line of the paragraph. |
style='first-line-indent:20pt'
|
| left-indent | Indents the left side of the paragraph. |
style='left-indent:10pt'
|
| right-indent | Indents the right side of the paragraph. |
style='right-indent:10pt'
|
| space-before | Sets space before the paragraph. |
style='space-before:30pt'
|
| space-after | Sets space after the paragraph. |
style='space-after:20pt'
|
| char-style | Sets the paragraph's default character style. This is not a key inside style like the other rows here. It is a separate attribute on the paragraph tag, and its value is itself a style string using the same keys as the Char Style and Color Style tables below. |
<p char-style='bold:true;color:red'>
|
| alignment | Specifies the paragraph alignment (left, center, right, justification, justification-last-left, justification-last-center, justification-last-right). |
style='alignment:center'
|
Customize character style to change the appearance of your text.
| Name | Description | Examples |
|---|---|---|
| font-family | Specifies the font family name. |
style='font-family:Arial'
|
| font-name | Specifies the PostScript font name. If the specified font is not found, the Text.CharStyle font is used. |
style='font-name:LucidaSans'
|
| font-style | Specifies the font style name. |
style='font-style:Narrow Italic'
|
| font-size | Specifies the font size. |
style='font-size:12pt'
|
| bold | Enables bold style. |
style='bold:true'
|
| italic | Enables italic style. |
style='italic:true'
|
| underline | Enables underlining. |
style='underline:true'
|
| leading | Specifies leading. |
style = 'leading:50pt'
|
| tracking | Specifies letter spacing, in thousandths of em. |
style = 'tracking:500'
|
| word-spacing-scale | Specifies word spacing. |
style = 'word-spacing-scale:3'
|
| horz-scale | Specifies horizontal scaling, as a decimal factor where 1 is normal width. Don't use a unit or a percent sign. |
style='horz-scale:1.2' (120% width) |
| vert-scale | Specifies vertical scaling, as a decimal factor where 1 is normal height. Don't use a unit or a percent sign. |
style='vert-scale:1.2' (120% height) |
| strike-through | Enables strike-through style. |
style='strike-through:true'
|
| baseline-shift | Adjusts the vertical position of individual characters relative to the baseline of the text. |
style='baseline-shift:0pt'
|
| sup | Enables superscript. |
style='sup:true'
|
| sup-size | Specifies the superscript size, as a decimal factor of the normal font size. Default is 0.583. |
style='sup-size:0.583'
|
| sup-position | Specifies how far the superscript is raised, as a decimal factor of the normal font size. Default is 0.333. |
style='sup-position:0.333'
|
| sub | Enables subscript. |
style='sub:true'
|
| sub-size | Specifies the subscript size, as a decimal factor of the normal font size. Default is 0.583. |
style='sub-size:0.583'
|
| sub-position | Specifies how far the subscript is lowered, as a decimal factor of the normal font size. Default is 0.333. |
style='sub-position:0.333'
|
Adjust color styles to change the appearance of text and outlines. The color, pen-color, ink-color, and pen-ink-color keys below accept any of these formats: rgb(r,g,b) or rgb(r,g,b,a); cmyk(c,m,y,k) or cmyk(c,m,y,k,a); gray(g) or gray(g,a); lab(l,a,b) or lab(l,a,b,alpha); spot(tint) or spot(tint,a); a plain palette index number; or a named color such as red or crimson.
| Name | Description | Examples |
|---|---|---|
| color | Specifies the text fill color. |
style='color:rgb(0,255,0)'
|
| pen-color | Specifies the text outline color. |
style='pen-color:rgb(0,255,0)'
|
| pen-width | Specifies the text outline width. |
style='pen-width:1px'
|
| ink-name | Specifies the ink name for text fill. |
style='ink-name:black'
|
| ink-solidity | Specifies the ink solidity for text fill, as a decimal factor where 1 is full solidity. Don't use a unit or a percent sign. |
style='ink-solidity:1'
|
| ink-color | Specifies the ink color for text fill. |
style='ink-color:rgb(0,0,0)'
|
| pen-ink-name | Specifies the ink name for text outline. |
style='pen-ink-name:black'
|
| pen-ink-solidity | Specifies the ink solidity for text outline, as a decimal factor where 1 is full solidity. Don't use a unit or a percent sign. |
style='pen-ink-solidity:1'
|
| pen-ink-color | Specifies the ink color for text outline. |
style='pen-ink-color:rgb(0,0,0)'
|
These keys style a list item directly on its <p> or <li> tag. The Lists section below covers a separate, shorter way to write lists using <ol> and <ul> tags - those tags set some of the same underlying properties, but under different attribute names.
| Name | Description | Examples |
|---|---|---|
| list-type | Specifies the type of list (none, bullets, numbers). |
style='list-type:bullets'
|
| level | Specifies the level of the list item. |
style='level:1'
|
| number-format | Specifies the number format for ordered lists (none, number, lower-letter, upper-letter, lower-roman, upper-roman). |
style='number-format:lower-roman'
|
| number-mode | Specifies the numbering mode (continue-from-previous, start-at). |
style='number-mode:start-at'
|
| number-start-at | Specifies the starting number for ordered lists. |
style='number-start-at:3'
|
| bullet-char | Specifies the bullet character for unordered lists, as a # followed by the character's decimal Unicode code point. |
style='bullet-char:#42' (asterisk) |
| bullet-number-pos-alignment | Specifies the alignment of bullet or number position (left, center, right). |
style='bullet-number-pos-alignment:center'
|
| bullet-number-tab-position | Specifies the tab position for bullets or numbers. |
style='bullet-number-tab-position:10pt'
|
| text-indent | Specifies the text indent of list elements. |
style='text-indent:30pt'
|
| level-indent | Specifies the level indent of list elements. |
style='level-indent:50pt'
|
To register a tab stop within a paragraph, add a <tab> element as a direct child of <p> or <li>, at the point in the markup where the stop should be declared. The element's content is a single value in points that sets the stop's horizontal offset from the paragraph's left edge, for example <tab>100pt</tab>; if the element is left empty, the offset defaults to 0. Use the style attribute to configure the stop's alignment, leader, and character-alignment target, as described in the table below.
Each tab stop within a paragraph must have a unique offset - declaring two stops at the same position (or omitting the content of more than one) throws an error when the text is parsed. A <tab> element can't be nested inside another <tab>, and isn't allowed anywhere except directly inside <p> or <li>.
Declaring a <tab> element only registers the stop - it doesn't by itself mark where in the text the layout should jump to it. Place an actual tab character in the text at that point, just as you would with plain text. Here's an example that lays out two right-aligned, dot-leadered columns:
A tab character can run out of stops to advance to. This happens when the paragraph has no <tab> elements, or when all the stops declared before that point are already used. In that case, the text falls back to a default tab stop.
Default tab stops sit on a fixed grid, spaced every 36pt (0.5 inch) from the paragraph's left edge. They are always left-aligned and have no leader.
using (var bitmap = new Bitmap(600, 160, PixelFormat.Format24bppRgb, new RgbColor(255, 255, 255, 255)))
using (var graphics = bitmap.GetGraphics())
{
var brush = new SolidBrush(RgbColor.Black);
// The <tab> element only registers the stop; the "\t" character
// in the span text is what makes the layout actually jump to it.
// Labels of different lengths still line up at the same tab stop.
var text = "<p style='space-after:6pt;'><tab style='alignment:right;leader:#46;'>500pt</tab><span>Opening Keynote\t9:00 AM</span></p>" +
"<p style='space-after:6pt;'><tab style='alignment:right;leader:#46;'>500pt</tab><span>Color Management Deep Dive\t10:30 AM</span></p>" +
"<p style='space-after:6pt;'><tab style='alignment:right;leader:#46;'>500pt</tab><span>Working with Vector PDFs\t1:00 PM</span></p>" +
"<p><tab style='alignment:right;leader:#46;'>500pt</tab><span>Closing Panel\t3:30 PM</span></p>";
var boundedText = new BoundedText(text, graphics.CreateFont("Verdana", 16f), brush)
{
Rectangle = new System.Drawing.RectangleF(20f, 20f, 560f, 120f)
};
graphics.DrawText(boundedText);
bitmap.Save(@"Images\Output\DrawFormattedTab.png");
}
This code produces the following image:
| Name | Description | Examples |
|---|---|---|
| alignment | Specifies the alignment of the tab stop (left, center, right, character). Default is left. |
style='alignment:center'
|
| leader | Specifies the character(s) used to fill the gap before the tab stop, as one or more #-prefixed decimal Unicode code points concatenated together. A single code repeats a single character; multiple codes form a repeating multi-character pattern. |
style='leader:#46' (dot leader); style='leader:#49#50#51' (repeats "123") |
| align-on | Specifies the character to align on for character-aligned tabs (alignment:character), as a # followed by its decimal Unicode code point. |
style='align-on:#46' (period) |
The ot format option allows you to apply OpenType features if your font supports them. To disable features, add ,0 after the feature name. Here's an example of drawing formatted text with superscript, small caps, and fraction features enabled:
using (var bitmap = new Bitmap(400, 130, PixelFormat.Format24bppRgb, RgbColor.White))
using (var graphics = bitmap.GetGraphics())
{
var brush = new SolidBrush(RgbColor.Black);
var text = @"<p>OpenType Regular Text 1234567890</p>" +
@"<p><span style='ot:sups'>OpenType Superscript 1234567890</span></p>" +
@"<p><span style='ot:smcp;ot:c2sc'>OpenType Small Caps 1234567890</span></p>" +
@"<p><span style='ot:frac;ot:lnum'>OpenType Fractions 1 2/3</span></p>";
var boundedText = new BoundedText(text, FontRegistry.Installed.CreateFont("Lyon Text", "Regular", 24, graphics.DpiX, graphics.DpiX), brush)
{
Rectangle = new System.Drawing.RectangleF(10f, 10f, 380f, 110f)
};
graphics.DrawText(boundedText);
bitmap.Save(@"Images\Output\DrawOpenType.png");
}
This code produces the following text:
For the full list of supported OpenType features, refer to the OpenTypeFeatureTag topic.
These keys enable advanced typographic features through OpenType.
| Name | Description | Examples |
|---|---|---|
| ot | Enables OpenType features. To disable a feature, add ,0 after the feature name (e.g., liga,0). To explicitly enable it, use ,1 (e.g., liga,1), or simply omit the value. |
style='ot:liga,0;ot:sups'
|
| all-caps | Enables all caps style. |
style='all-caps:true'
|
| small-caps | Enables small caps style. |
style='small-caps:true'
|
| small-caps-size | Specifies the small caps size, as a decimal factor of the normal font size. This is not a point size. Default is 0.7. |
style='small-caps-size:0.7'
|
| digit-type | Sets the digit type (hindi, arabic, farsi). |
style='digit-type:hindi'
|
Graphics Mill supports numbered and bulleted lists. Use the <ol> tag for numbered lists and the <ul> tag for bulleted lists. Each list item must be tagged with <li>.
The <ol> and <ul> tags are a shorthand: they set the same underlying List Style properties on each <li> they contain, but through their own type and start attributes instead of number-format, bullet-char, and number-start-at. Use <ol>/<ul> for a plain list. Style a <p> or <li> directly with the List Style keys when you need finer control, such as bullet-number-pos-alignment or level-indent.
using (var bitmap = new Bitmap(600, 420, PixelFormat.Format24bppRgb, new RgbColor(255, 255, 255, 255)))
using (var graphics = bitmap.GetGraphics())
{
var brush = new SolidBrush(RgbColor.Black);
var text = @"<ol style='type:upperRoman;'>" +
@"<li>The first level element." +
@"<ul style='type:bullet; text-indent:30pt; level-indent:50pt;'>" +
@"<li>The second level element.</li>" +
@"<li>Lorem ipsum dolor sit amet consectetur adipiscing elit.</li>" +
@"<li>Cras elementum quam ac nisi varius gravida.</li>" +
@"</ul>" +
@"</li>" +
@"<li>The first level element." +
@"<ul style='type:minus;'>" +
@"<li>The second level element.</li>" +
@"<li>Lorem ipsum dolor sit amet consectetur adipiscing elit.</li>" +
@"<li>Cras elementum quam ac nisi varius gravida.</li>" +
@"</ul>" +
@"</li>" +
@"</ol>";
var boundedText = new BoundedText(text, graphics.CreateFont("Verdana", 26f), brush)
{
Rectangle = new System.Drawing.RectangleF(20f, 20f, 600f, 420f)
};
graphics.DrawText(boundedText);
bitmap.Save(@"Images\Output\DrawFormattedList.png");
}
This code produces the following image:
Configure lists using the style attribute. The type parameter can be one of the following:
For numbered lists:
number - Default type with numbers (1, 2, 3, etc.).lowerLetter - Lower-alpha (a, b, c, etc.).upperLetter - Upper-alpha (A, B, C, etc.).lowerRoman - Lower-roman (i, ii, iii, etc.).upperRoman - Upper-roman (I, II, III, etc.).For bulleted lists:
none - Default type without markers.bullet - Circle marker.minus - Minus marker.Use any symbol by specifying its UTF-8 code, for example:
<ul style='type: #9675;'> for circle.<ul style='type: #9632;'> for square.<ul style='type: #9679;'> for disc.To start a numbered list with a specific number, use the start argument of the style attribute. For example, <ol style='start: 3; type: upperRoman;'> starts the list from III.
Measuring text involves determining the dimensions of a rectangle that tightly encloses the text. To measure formatted text, use the Text.GetBlackBox(FontRegistry, Single, Single) method:
using (var bitmap = new Bitmap(160, 160, PixelFormat.Format24bppRgb, RgbColor.White))
using (var graphics = bitmap.GetGraphics())
{
var text = @"<span style='font-size:36pt;color:red;'>Art</span> " +
@"<span style='color:green;'>Round</span> <span style='font-size:36pt;color:blue;'>Text</span>";
using (var roundText = new RoundText(text, graphics.CreateFont("Verdana", 26f), new System.Drawing.PointF(80, 80)))
{
roundText.Bend = 0.9f;
graphics.DrawText(roundText);
graphics.DrawRectangle(
new Pen(RgbColor.Gray, 1f),
roundText.GetBlackBox(graphics.FontRegistry, graphics.DpiX, graphics.DpiY));
bitmap.Save(@"Images\Output\MeasureFormattedText.png");
}
}
This code draws the text and its black box:
The exception classes for formatted text are:
The following code catches the UnknownTagException error because the <article> tag is not supported:
using (var bitmap = new Bitmap(600, 350, PixelFormat.Format24bppRgb, new RgbColor(255, 255, 255, 255)))
using (var graphics = bitmap.GetGraphics())
{
var text = @"<article>Lorem ipsum dolor sit <span style='color:red;'>amet</span></article>";
try
{
var plainText = new PlainText(text, graphics.CreateFont("Verdana", 26f));
graphics.DrawText(plainText);
bitmap.Save(@"Images\Output\DrawFormattedText.png");
}
catch (UnknownTagException e)
{
Debug.WriteLine("The {0} exception message is caught.", e.GetType());
Debug.WriteLine("The unknown tag: " + e.Message + ".");
}
}
The output is:
The Aurigma.GraphicsMill.Drawing.UnknownTagException exception message is caught.
The unknown tag: article.