---
title: "Working with the Text Class"
canonical: https://www.graphicsmill.com/docs/gm/working-with-text-class.htm
product: "Graphics Mill"
---

# Working with the Text Class
 
The [Text](https://www.graphicsmill.com/docs/gm/T_Aurigma_GraphicsMill_Drawing_Text.htm.md) class is the central class for drawing text in Graphics Mill. A single **Text** object holds a text string, its formatting, and one or more **text frames** that define where the text goes. Different kinds of frame place the text differently: at a single point, inside a shape, along a curved path, and so on. If the [Text.Frames](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_Text_Frames.htm.md) collection contains more than one frame, the text flows through them one by one: when a frame is full, the rest of the text continues in the next frame.
 
Here is a complete example. It creates a text, gives it a font, places it with a single frame, and draws it:
 
```csharp
using (var bitmap = new Bitmap(400, 120, PixelFormat.Format24bppRgb, RgbColor.White))
using (var graphics = bitmap.GetGraphics())
{
    // A frame tells the text where to go. At least one frame is required.
    var frame = new PointTextFrame()
    {
        Point = new System.Drawing.PointF(20, 75)
    };

    var text = new Text()
    {
        String = "Hello, world!",
        CharStyle = new CharStyle("Arial", 36)
    };

    text.Frames.Add(frame);

    graphics.DrawText(text);

    bitmap.Save(@"Images\Output\HelloWorld.png");
}
```
 ![A minimal text example](https://www.graphicsmill.com/docs/gm/HelloWorld.png) 
Text is always drawn through the [Graphics.DrawText(Text)](https://www.graphicsmill.com/docs/gm/M_Aurigma_GraphicsMill_Drawing_Graphics_DrawText_1_f576d03f.htm.md) method, whatever frames it uses. If you are not familiar with [Graphics](https://www.graphicsmill.com/docs/gm/T_Aurigma_GraphicsMill_Drawing_Graphics.htm.md), read the [Graphics. Drawing Images and Geometric Shapes](https://www.graphicsmill.com/docs/gm/graphics.htm.md) article first.
 
This topic covers the following:
 
- Text Frames
- Text Properties
- Fonts and the Font Registry
- Simplified Text Classes

## Text Frames
  
A text frame is one of the classes derived from [TextFrame](https://www.graphicsmill.com/docs/gm/T_Aurigma_GraphicsMill_Drawing_TextFrame.htm.md). This topic covers the three frames you will use most often:
 
- [PointTextFrame](https://www.graphicsmill.com/docs/gm/T_Aurigma_GraphicsMill_Drawing_PointTextFrame.htm.md) - text starts at a single point and grows without any bound.
- [ShapeTextFrame](https://www.graphicsmill.com/docs/gm/T_Aurigma_GraphicsMill_Drawing_ShapeTextFrame.htm.md) - text is bounded by an arbitrary closed shape.
- [PathTextFrame](https://www.graphicsmill.com/docs/gm/T_Aurigma_GraphicsMill_Drawing_PathTextFrame.htm.md) - text flows along a curve.

 ![Text frame types](https://www.graphicsmill.com/docs/gm/TextFrameTypes.png) 
Add one or more frames to **Text.Frames**. When a frame cannot hold the whole string, the rest of the text is not clipped or dropped. It continues in the next frame of the collection, in the order the frames were added, until either the text or the frames run out. This is what makes multi-column layouts simple to build:
 
```csharp
using (var bitmap = new Bitmap(460, 300, PixelFormat.Format24bppRgb, RgbColor.White))
using (var graphics = bitmap.GetGraphics())
{
    var column1 = new Path();
    column1.DrawRectangle(10, 10, 210, 280);

    var column2 = new Path();
    column2.DrawRectangle(240, 10, 210, 280);

    var firstFrame = new ShapeTextFrame()
    {
        Shape = column1
    };

    var secondFrame = new ShapeTextFrame()
    {
        Shape = column2
    };

    var flowExplanation =
        TextFlowSummary + " " +
        "Once a frame is full, the remaining text does not disappear or get clipped. " +
        "It simply carries on inside the next frame in the collection, in the order " +
        "the frames were added, until either the text or the frames run out. " +
        "This is what makes multi-column layouts straightforward. Define each column " +
        "once as its own frame, then let a single text object fill them in sequence. " +
        "Editing the text later reflows every frame automatically.";

    var text = new Text()
    {
        String = flowExplanation,
        CharStyle = new CharStyle("Arial", 17)
    };

    // Frames are filled in order: the overflow from the first frame continues in the second.
    text.Frames.Add(firstFrame);
    text.Frames.Add(secondFrame);

    graphics.DrawPath(new Pen(RgbColor.Gray, 1), column1);
    graphics.DrawPath(new Pen(RgbColor.Gray, 1), column2);
    graphics.DrawText(text);

    bitmap.Save(@"Images\Output\TextFlowBetweenFrames.png");
}
```
 ![Text flowing across two frames](https://www.graphicsmill.com/docs/gm/TextFlowBetweenFrames.png) 
### Point Text Frame
 
**PointTextFrame** is the simplest frame. It has an anchor [PointTextFrame.Point](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_PointTextFrame_Point.htm.md) and a [PointTextFrame.TextOrientation](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_PointTextFrame_TextOrientation.htm.md) that switches between horizontal and vertical text. The frame has no bounds, so the text is never wrapped or fitted. It grows from the anchor point, and only an explicit line break starts a new line:
 
```csharp
using (var bitmap = new Bitmap(400, 130, PixelFormat.Format24bppRgb, RgbColor.White))
using (var graphics = bitmap.GetGraphics())
{
    var frame = new PointTextFrame()
    {
        Point = new System.Drawing.PointF(30, 60)
    };

    var text = new Text()
    {
        String = "Point text\nwith two lines",
        CharStyle = new CharStyle("Arial", 24)
    };

    text.Frames.Add(frame);

    graphics.DrawEllipse(new Pen(RgbColor.IndianRed, 1), 27, 57, 6, 6);
    graphics.DrawText(text);

    bitmap.Save(@"Images\Output\PointTextFrame.png");
}
```
 ![Point text with two lines](https://www.graphicsmill.com/docs/gm/PointTextFrame.png) 
### Shape Text Frame
 
**ShapeTextFrame** bounds the text by a [ShapeTextFrame.Shape](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_ShapeTextFrame_Shape.htm.md). The shape is any closed [Path](https://www.graphicsmill.com/docs/gm/T_Aurigma_GraphicsMill_Drawing_Path.htm.md), not just a rectangle. This frame has the richest set of properties, because it has to decide how the text and the shape adapt to each other.
 
**Note** 
The samples in this section call a small local helper named **DrawCaption**. It only draws the gray label under each box and is not part of the text API.
 
[ShapeTextFrame.AutoSizeMode](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_ShapeTextFrame_AutoSizeMode.htm.md) resizes the shape to fit the text. [ShapeTextFrame.AutoSizeAnchor](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_ShapeTextFrame_AutoSizeAnchor.htm.md) selects which corner or edge stays in place while the rest moves. The resized outline is available through the frame's **AutoSizedShape** property, but only after the text has been drawn or measured:
 
```csharp
using (var bitmap = new Bitmap(500, 300, PixelFormat.Format24bppRgb, RgbColor.White))
using (var graphics = bitmap.GetGraphics())
{
    var modes = new[]
    {
        AutoSizeMode.Off,
        AutoSizeMode.WidthOnly,
        AutoSizeMode.HeightOnly,
        AutoSizeMode.WidthHeight
    };

    for (int i = 0; i < modes.Length; i++)
    {
        float offsetX = 20 + (i % 2) * 240;
        float offsetY = 20 + (i / 2) * 140;

        var shape = new Path();
        shape.DrawRectangle(offsetX, offsetY, 200, 60);

        var frame = new ShapeTextFrame()
        {
            Shape = shape,
            AutoSizeMode = modes[i]
        };

        var text = new Text()
        {
            String = "Sample text",
            CharStyle = new CharStyle("Arial", 20)
        };

        text.Frames.Add(frame);

        graphics.DrawPath(new Pen(RgbColor.Gray, 1), shape);
        graphics.DrawText(text);

        // The resized outline is available only after the text has been drawn or measured.
        if (frame.AutoSizedShape != null)
            graphics.DrawPath(new Pen(RgbColor.IndianRed, 1), frame.AutoSizedShape);

        DrawCaption(graphics, modes[i].ToString(), new System.Drawing.PointF(offsetX, offsetY + 85));
    }

    bitmap.Save(@"Images\Output\ShapeTextFrameAutoSize.png");
}
```
 ![ShapeTextFrame AutoSizeMode values](https://www.graphicsmill.com/docs/gm/ShapeTextFrameAutoSize.png) 
[ShapeTextFrame.CopyfittingMode](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_ShapeTextFrame_CopyfittingMode.htm.md) does the opposite. The shape stays fixed and the text is adjusted to fit it. There are six modes. The plain modes keep the original glyph proportions, while the `WithScale` modes are allowed to change the aspect ratio of the glyphs. In the sample below each pair of modes uses the same text and the same starting char style, so that the difference between the two modes of a pair is what you actually see:
 
```csharp
using (var bitmap = new Bitmap(500, 540, PixelFormat.Format24bppRgb, RgbColor.White))
using (var graphics = bitmap.GetGraphics())
{
    // Each pair of modes shares the same text and the same initial char style,
    // so that the difference between the two modes is what you actually see.
    const string tooLong = "This paragraph is far longer than the box that has to hold it, " +
        "so with copyfitting off its last lines simply run past the bottom edge.";
    const string tooWide = "Extra wide headline";
    const string tooShort = "Short";

    var samples = new[]
    {
        Tuple.Create(CopyfittingMode.Off, tooLong, 20f),
        Tuple.Create(CopyfittingMode.FitToBox, tooLong, 20f),
        Tuple.Create(CopyfittingMode.FitToWidth, tooWide, 30f),
        Tuple.Create(CopyfittingMode.FitToWidthWithScale, tooWide, 30f),
        Tuple.Create(CopyfittingMode.Fill, tooShort, 11f),
        Tuple.Create(CopyfittingMode.FillWithScale, tooShort, 11f)
    };

    for (int i = 0; i < samples.Length; i++)
    {
        float offsetX = 20 + (i % 2) * 240;
        float offsetY = 20 + (i / 2) * 170;

        var shape = new Path();
        shape.DrawRectangle(offsetX, offsetY, 200, 110);

        var frame = new ShapeTextFrame()
        {
            Shape = shape,
            CopyfittingMode = samples[i].Item1
        };

        var text = new Text()
        {
            String = samples[i].Item2,
            CharStyle = new CharStyle("Arial", samples[i].Item3)
        };

        text.Frames.Add(frame);

        graphics.DrawPath(new Pen(RgbColor.Gray, 1), shape);
        graphics.DrawText(text);
        DrawCaption(graphics, samples[i].Item1.ToString(), new System.Drawing.PointF(offsetX, offsetY + 135));
    }

    bitmap.Save(@"Images\Output\ShapeTextFrameCopyfitting.png");
}
```
 ![ShapeTextFrame CopyfittingMode values](https://www.graphicsmill.com/docs/gm/ShapeTextFrameCopyfitting.png) 
- `Off` and `FitToBox` share text that overflows the box. With `Off` the last lines run past the bottom edge; `FitToBox` makes the whole text fit inside.
- `FitToWidth` and `FitToWidthWithScale` share a headline wider than the box, and both make it fit the width. The first keeps the original glyph proportions, the second may change their aspect ratio.
- `Fill` and `FillWithScale` share a short string, which both modes enlarge to fill the box. Again, the first preserves the glyph proportions and the second may change them.

[ShapeTextFrame.VerticalAlignment](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_ShapeTextFrame_VerticalAlignment.htm.md) positions the text block within the height of the shape:
 
```csharp
using (var bitmap = new Bitmap(640, 290, PixelFormat.Format24bppRgb, RgbColor.White))
using (var graphics = bitmap.GetGraphics())
{
    var alignments = new[]
    {
        VerticalAlignment.Top,
        VerticalAlignment.Center,
        VerticalAlignment.Bottom,
        VerticalAlignment.Justify
    };

    for (int i = 0; i < alignments.Length; i++)
    {
        float offsetX = 20 + i * 155;

        var shape = new Path();
        shape.DrawRectangle(offsetX, 20, 135, 220);

        var frame = new ShapeTextFrame()
        {
            Shape = shape,
            VerticalAlignment = alignments[i]
        };

        var text = new Text()
        {
            String = "One two three four",
            CharStyle = new CharStyle("Arial", 28)
        };

        text.Frames.Add(frame);

        graphics.DrawPath(new Pen(RgbColor.Gray, 1), shape);
        graphics.DrawText(text);
        DrawCaption(graphics, alignments[i].ToString(), new System.Drawing.PointF(offsetX, 262));
    }

    bitmap.Save(@"Images\Output\ShapeTextFrameVerticalAlignment.png");
}
```
 ![ShapeTextFrame VerticalAlignment values](https://www.graphicsmill.com/docs/gm/ShapeTextFrameVerticalAlignment.png) 
[ShapeTextFrame.FirstBaselineOffset](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_ShapeTextFrame_FirstBaselineOffset.htm.md) selects the font metric that positions the first baseline below the top of the frame. [ShapeTextFrame.FirstBaselineMinOffset](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_ShapeTextFrame_FirstBaselineMinOffset.htm.md) sets the smallest allowed distance between the top of the frame and that baseline. The sample below sets it to `0`, so each metric shows its own natural result. The `Fixed` value ignores the font metrics and puts the baseline exactly **ShapeTextFrame.FirstBaselineMinOffset** below the top:
 
```csharp
using (var bitmap = new Bitmap(520, 320, PixelFormat.Format24bppRgb, RgbColor.White))
using (var graphics = bitmap.GetGraphics())
{
    var offsets = new[]
    {
        FirstBaselineOffset.Ascent,
        FirstBaselineOffset.CapHeight,
        FirstBaselineOffset.Leading,
        FirstBaselineOffset.xHeight,
        FirstBaselineOffset.EmBox,
        FirstBaselineOffset.Fixed
    };

    for (int i = 0; i < offsets.Length; i++)
    {
        float offsetX = 20 + (i % 3) * 165;
        float offsetY = 20 + (i / 3) * 145;

        var shape = new Path();
        shape.DrawRectangle(offsetX, offsetY, 145, 90);

        var frame = new ShapeTextFrame()
        {
            Shape = shape,
            FirstBaselineOffset = offsets[i],
            FirstBaselineMinOffset = 0
        };

        var text = new Text()
        {
            String = "Hxg",
            CharStyle = new CharStyle("Arial", 30)
        };

        text.Frames.Add(frame);

        graphics.DrawPath(new Pen(RgbColor.Gray, 1), shape);
        graphics.DrawText(text);
        DrawCaption(graphics, offsets[i].ToString(), new System.Drawing.PointF(offsetX, offsetY + 115));
    }

    bitmap.Save(@"Images\Output\ShapeTextFrameFirstBaseline.png");
}
```
 ![ShapeTextFrame FirstBaselineOffset values](https://www.graphicsmill.com/docs/gm/ShapeTextFrameFirstBaseline.png) 
[ShapeTextFrame.TextOrientation](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_ShapeTextFrame_TextOrientation.htm.md) switches the frame between horizontal and vertical text. In vertical mode the glyphs stack downwards and the lines run from right to left, which is the usual layout for East Asian scripts. Vertical text needs a font that contains the required glyphs, so the sample looks up an installed Korean font instead of assuming one:
 
```csharp
using (var bitmap = new Bitmap(460, 280, PixelFormat.Format24bppRgb, RgbColor.White))
using (var graphics = bitmap.GetGraphics())
{
    // "The weather is clear today" in Korean.
    const string korean = "\uC624\uB298\uC740 \uB0A0\uC528\uAC00 \uB9D1\uC2B5\uB2C8\uB2E4";

    var koreanFont = FindKoreanFont();

    var orientations = new[]
    {
        TextOrientation.Horizontal,
        TextOrientation.Vertical
    };

    for (int i = 0; i < orientations.Length; i++)
    {
        float offsetX = 20 + i * 230;

        var shape = new Path();
        shape.DrawRectangle(offsetX, 20, 210, 200);

        var frame = new ShapeTextFrame()
        {
            Shape = shape,
            TextOrientation = orientations[i]
        };

        var text = new Text()
        {
            String = korean,
            CharStyle = new CharStyle(koreanFont, 26)
        };

        text.Frames.Add(frame);

        graphics.DrawPath(new Pen(RgbColor.Gray, 1), shape);
        graphics.DrawText(text);
        DrawCaption(graphics, orientations[i].ToString(), new System.Drawing.PointF(offsetX, 242));
    }

    bitmap.Save(@"Images\Output\ShapeTextFrameOrientation.png");
}
```
 ![Horizontal and vertical Korean text](https://www.graphicsmill.com/docs/gm/ShapeTextFrameOrientation.png) 
### Path Text Frame
 
**PathTextFrame** flows the text along a [PathTextFrame.Baseline](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_PathTextFrame_Baseline.htm.md) path. Read the [Working with Paths](https://www.graphicsmill.com/docs/gm/working-with-path.htm.md) article if you are not familiar with **Path**. [PathTextFrame.PathAlignment](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_PathTextFrame_PathAlignment.htm.md) selects which part of the glyphs sits on the path:
 
```csharp
using (var bitmap = new Bitmap(500, 260, PixelFormat.Format24bppRgb, RgbColor.White))
using (var graphics = bitmap.GetGraphics())
{
    var baseline = new Path();
    baseline.MoveTo(20, 200);
    baseline.CurveTo(180, 20, 320, 20, 480, 200);

    graphics.DrawPath(new Pen(RgbColor.Gray, 1), baseline);

    var alignments = new[]
    {
        Tuple.Create(PathTextAlignment.Ascender, RgbColor.IndianRed),
        Tuple.Create(PathTextAlignment.Center, RgbColor.SeaGreen),
        Tuple.Create(PathTextAlignment.Baseline, RgbColor.Black),
        Tuple.Create(PathTextAlignment.Descender, RgbColor.SteelBlue)
    };

    // Each label takes its own quarter of the path so the four alignments can be compared side by side.
    for (int i = 0; i < alignments.Length; i++)
    {
        var frame = new PathTextFrame()
        {
            Baseline = baseline,
            PathAlignment = alignments[i].Item1,
            Start = i * 0.25f,
            End = i * 0.25f + 0.25f
        };

        var text = new Text()
        {
            String = alignments[i].Item1.ToString(),
            CharStyle = new CharStyle("Arial", 18),
            Brush = new SolidBrush(alignments[i].Item2)
        };

        text.Frames.Add(frame);

        graphics.DrawText(text);
    }

    bitmap.Save(@"Images\Output\PathTextFrameAlignment.png");
}
```
 ![PathTextFrame PathAlignment values](https://www.graphicsmill.com/docs/gm/PathTextFrameAlignment.png) 
[PathTextFrame.Start](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_PathTextFrame_Start.htm.md) and [PathTextFrame.End](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_PathTextFrame_End.htm.md) limit the text to a part of the path. Both are fractions of the path length, from `0` to `1`. [PathTextFrame.Flip](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_PathTextFrame_Flip.htm.md) mirrors the text to the other side of the path:
 
```csharp
using (var bitmap = new Bitmap(500, 320, PixelFormat.Format24bppRgb, RgbColor.White))
using (var graphics = bitmap.GetGraphics())
{
    // Start and End restrict the text to a portion of the path, given as a fraction of its length.
    var topBaseline = new Path();
    topBaseline.MoveTo(20, 100);
    topBaseline.CurveTo(180, 20, 320, 20, 480, 100);

    var trimmedFrame = new PathTextFrame()
    {
        Baseline = topBaseline,
        Start = 0.25f,
        End = 0.85f
    };

    var trimmedText = new Text()
    {
        String = "This part only",
        CharStyle = new CharStyle("Arial", 20)
    };

    trimmedText.Frames.Add(trimmedFrame);

    graphics.DrawPath(new Pen(RgbColor.Gray, 1), topBaseline);
    graphics.DrawText(trimmedText);
    DrawCaption(graphics, "Start = 0.25, End = 0.85", new System.Drawing.PointF(20, 130));

    // Flip mirrors the text to the other side of the baseline.
    var bottomBaseline = new Path();
    bottomBaseline.MoveTo(20, 260);
    bottomBaseline.CurveTo(180, 340, 320, 340, 480, 260);

    var flippedFrame = new PathTextFrame()
    {
        Baseline = bottomBaseline,
        Flip = true
    };

    var flippedText = new Text()
    {
        String = "Flip = true",
        CharStyle = new CharStyle("Arial", 20)
    };

    flippedText.Frames.Add(flippedFrame);

    graphics.DrawPath(new Pen(RgbColor.Gray, 1), bottomBaseline);
    graphics.DrawText(flippedText);

    bitmap.Save(@"Images\Output\PathTextFrameStartEndFlip.png");
}
```
 ![PathTextFrame Start, End, and Flip](https://www.graphicsmill.com/docs/gm/PathTextFrameStartEndFlip.png) 
Several more properties tune the fit numerically. [PathTextFrame.Spacing](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_PathTextFrame_Spacing.htm.md) adds space between characters. [PathTextFrame.VerticalOffset](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_PathTextFrame_VerticalOffset.htm.md) moves the text away from the path. [PathTextFrame.Stretch](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_PathTextFrame_Stretch.htm.md) stretches glyphs so they follow sharp curves more closely. [PathTextFrame.AutoExtend](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_PathTextFrame_AutoExtend.htm.md) lets the text run past the end of the path instead of stopping there. [PathTextFrame.CopyfittingMode](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_PathTextFrame_CopyfittingMode.htm.md) works as it does for **ShapeTextFrame**, fitting the text to the part of the path between **PathTextFrame.Start** and **PathTextFrame.End**.
 
## Text Properties
  
Besides the frames, a **Text** object needs a [Text.String](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_Text_String.htm.md) and a [Text.CharStyle](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_Text_CharStyle.htm.md). **Text.CharStyle** and [Text.ParagraphStyle](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_Text_ParagraphStyle.htm.md) hold the *default* character and paragraph settings for the whole string. Individual parts of the string can override these defaults with the XML markup syntax written inside the text string itself. The [Formatted Text](https://www.graphicsmill.com/docs/gm/advanced-formatted-text.htm.md) article describes that markup and both style objects in detail.
 
The rest of this section covers the properties that belong to the **Text** object itself. Colors come from [Text.Brush](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_Text_Brush.htm.md) and [Text.Pen](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_Text_Pen.htm.md), and [Text.Transform](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_Text_Transform.htm.md) applies a geometric transform to the result.
 
### Kernings
 
The [Text.Kernings](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_Text_Kernings.htm.md) property tunes the spacing between individual glyph pairs. It takes one value per gap between glyphs, so a string of `N` characters takes `N - 1` values, measured in 1/1000 em. A positive value opens up a pair, a negative value tightens it. This is separate from the tracking that **Text.CharStyle** applies to the whole string:
 
```csharp
using (var bitmap = new Bitmap(500, 140, PixelFormat.Format24bppRgb, RgbColor.White))
using (var graphics = bitmap.GetGraphics())
{
    var frame = new PointTextFrame()
    {
        Point = new System.Drawing.PointF(20, 90)
    };

    var text = new Text()
    {
        String = "Kerning",
        CharStyle = new CharStyle("Arial", 60),

        // One value per gap between glyphs, in 1/1000 em.
        // Positive values open up the pair, negative values tighten it.
        Kernings = new float[] { 250, 120, 0, -60, -120, -180 }
    };

    text.Frames.Add(frame);

    graphics.DrawText(text);

    bitmap.Save(@"Images\Output\TextKernings.png");
}
```
 ![Kernings](https://www.graphicsmill.com/docs/gm/TextKernings.png) 
### Wrapping Paths
 
The [Text.WrappingPaths](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_Text_WrappingPaths.htm.md) collection holds obstacles that the text flows around. They apply to the text as a whole, in every frame. Each **Path** in the collection is one obstacle:
 
```csharp
using (var bitmap = new Bitmap(400, 260, PixelFormat.Format24bppRgb, RgbColor.White))
using (var graphics = bitmap.GetGraphics())
{
    var container = new Path();
    container.DrawRectangle(10, 10, 380, 240);

    var obstacle = new Path();
    obstacle.DrawEllipse(140, 80, 110, 110);

    var frame = new ShapeTextFrame()
    {
        Shape = container
    };

    var text = new Text()
    {
        String = TextFlowSummary,
        CharStyle = new CharStyle("Arial", 24)
    };

    text.Frames.Add(frame);
    text.WrappingPaths.Add(obstacle);

    graphics.FillPath(new SolidBrush(new RgbColor(255, 224, 224)), obstacle);
    graphics.DrawText(text);
    graphics.DrawPath(new Pen(RgbColor.Gray, 1), container);
    graphics.DrawPath(new Pen(RgbColor.IndianRed, 1), obstacle);

    bitmap.Save(@"Images\Output\TextWrappingSinglePath.png");
}
```
 ![Wrapping around a single obstacle](https://www.graphicsmill.com/docs/gm/TextWrappingSinglePath.png) 
Add several paths to wrap the text around several obstacles at once:
 
```csharp
using (var bitmap = new Bitmap(400, 260, PixelFormat.Format24bppRgb, RgbColor.White))
using (var graphics = bitmap.GetGraphics())
{
    var container = new Path();
    container.DrawRectangle(10, 10, 380, 240);

    var obstacle1 = new Path();
    obstacle1.DrawEllipse(30, 30, 100, 100);

    var obstacle2 = new Path();
    obstacle2.DrawEllipse(250, 130, 120, 90);

    var frame = new ShapeTextFrame()
    {
        Shape = container
    };

    var text = new Text()
    {
        String = TextFlowSummary + " " + TextFlowSummary,
        CharStyle = new CharStyle("Arial", 17)
    };

    text.Frames.Add(frame);

    // Every path added here is a separate obstacle.
    text.WrappingPaths.Add(obstacle1);
    text.WrappingPaths.Add(obstacle2);

    graphics.FillPath(new SolidBrush(new RgbColor(255, 224, 224)), obstacle1);
    graphics.FillPath(new SolidBrush(new RgbColor(255, 224, 224)), obstacle2);
    graphics.DrawText(text);
    graphics.DrawPath(new Pen(RgbColor.Gray, 1), container);
    graphics.DrawPath(new Pen(RgbColor.IndianRed, 1), obstacle1);
    graphics.DrawPath(new Pen(RgbColor.IndianRed, 1), obstacle2);

    bitmap.Save(@"Images\Output\TextWrappingMultiplePaths.png");
}
```
 ![Wrapping around several obstacles](https://www.graphicsmill.com/docs/gm/TextWrappingMultiplePaths.png) 
### Effects
 
Set the [Text.Effect](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_Text_Effect.htm.md) property to make the text glow or cast a shadow. The [Effects.Glow](https://www.graphicsmill.com/docs/gm/T_Aurigma_GraphicsMill_Drawing_Effects_Glow.htm.md) and [Effects.Shadow](https://www.graphicsmill.com/docs/gm/T_Aurigma_GraphicsMill_Drawing_Effects_Shadow.htm.md) classes and all their parameters are described in the [Text Effects](https://www.graphicsmill.com/docs/gm/advanced-drawing-text.htm.md) section of the [Drawing Simple Text Objects](https://www.graphicsmill.com/docs/gm/advanced-drawing-text.htm.md) article:
 
```csharp
using (var bitmap = new Bitmap(500, 140, PixelFormat.Format24bppRgb, new RgbColor(60, 60, 70)))
using (var graphics = bitmap.GetGraphics())
{
    var glow = new Aurigma.GraphicsMill.Drawing.Effects.Glow()
    {
        Color = RgbColor.Cyan,
        Size = 8,
        Opacity = 0.9f
    };

    var frame = new PointTextFrame()
    {
        Point = new System.Drawing.PointF(20, 100)
    };

    var text = new Text()
    {
        String = "Glowing text",
        CharStyle = new CharStyle("Arial", 65),
        Brush = new SolidBrush(RgbColor.White),
        Effect = glow
    };

    text.Frames.Add(frame);

    graphics.DrawText(text);

    bitmap.Save(@"Images\Output\TextGlowEffect.png");
}
```
 ![A glowing text effect](https://www.graphicsmill.com/docs/gm/TextGlowEffect.png) 
### Font Metrics
 
Font metrics are the measurements of a font at a particular size. All of them are measured from the baseline, the line on which the characters stand:
 ![Font metrics](https://www.graphicsmill.com/docs/gm/FontMetrics.png) 
- **Ascender** is the distance from the baseline to the top of the tallest glyph.
- **Descender** is the distance from the baseline to the bottom of glyphs like "g" or "y".
- **Height** is the distance between the baselines of two neighboring lines.
- **Underline position** and **underline thickness** define the underline.

A [Font](https://www.graphicsmill.com/docs/gm/T_Aurigma_GraphicsMill_Drawing_Font.htm.md) object provides these values through its [Font.Metrics](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_Font_Metrics.htm.md) property. For a single line of text, [Font.MeasureString(String)](https://www.graphicsmill.com/docs/gm/M_Aurigma_GraphicsMill_Drawing_Font_MeasureString_1_bb3a7a4f.htm.md) returns its width, height, ascender, and descender.
 
### Measuring and Fitting
 
The [Text.GetBlackBox(FontRegistry, Single, Single)](https://www.graphicsmill.com/docs/gm/M_Aurigma_GraphicsMill_Drawing_Text_GetBlackBox_3_185e8a92.htm.md) method returns the black box of the text. This is the smallest rectangle that bounds all the glyphs at their current size and position. [Text.FitTo(RectangleF, FontRegistry, Single, Single)](https://www.graphicsmill.com/docs/gm/M_Aurigma_GraphicsMill_Drawing_Text_FitTo_4_e0d596b2.htm.md) goes further and adjusts the text so that its black box matches a target rectangle. Both methods take a [FontRegistry](https://www.graphicsmill.com/docs/gm/T_Aurigma_GraphicsMill_Drawing_FontRegistry.htm.md) and the target DPI, because font metrics depend on them:
 
```csharp
using (var bitmap = new Bitmap(500, 260, PixelFormat.Format24bppRgb, RgbColor.White))
using (var graphics = bitmap.GetGraphics())
{
    var pen = new Pen(RgbColor.IndianRed, 1);

    var frame = new PointTextFrame()
    {
        Point = new System.Drawing.PointF(20, 80)
    };

    var text = new Text()
    {
        String = "Fit to box",
        CharStyle = new CharStyle("Arial", 60)
    };

    text.Frames.Add(frame);

    // Before: measure the black box of the text at its natural size.
    var blackBox = text.GetBlackBox(graphics.FontRegistry, graphics.DpiX, graphics.DpiY);

    graphics.DrawText(text);
    graphics.DrawRectangle(pen, blackBox);
    DrawCaption(graphics, "GetBlackBox: natural size", new System.Drawing.PointF(20, 105));

    // After: FitTo adjusts the same text so that it matches a target rectangle.
    var targetRect = new System.Drawing.RectangleF(20, 160, 460, 70);
    text.FitTo(targetRect, graphics.FontRegistry, graphics.DpiX, graphics.DpiY);

    graphics.DrawText(text);
    graphics.DrawRectangle(pen, targetRect);
    DrawCaption(graphics, "FitTo: fitted into the rectangle above", new System.Drawing.PointF(20, 245));

    bitmap.Save(@"Images\Output\TextBlackBoxAndFitTo.png");
}
```
 ![GetBlackBox and FitTo](https://www.graphicsmill.com/docs/gm/TextBlackBoxAndFitTo.png)
 
## Fonts and the Font Registry
  
Every char style refers to a font by its postscript name, and **Graphics** resolves that name against its own [Graphics.FontRegistry](https://www.graphicsmill.com/docs/gm/P_Aurigma_GraphicsMill_Drawing_Graphics_FontRegistry.htm.md). If the font is not in that registry, drawing the text or calling **Text.GetBlackBox(FontRegistry, Single, Single)** or **Text.FitTo(RectangleF, FontRegistry, Single, Single)** on it fails. Pass the same registry to these methods that you use for drawing.
 
Font names, aliases, collisions, fallback fonts, and missing fonts are described in the [Working with Font Registry](https://www.graphicsmill.com/docs/gm/working-with-font-registry.htm.md) article.
 
**Important** 
Remember to assign your custom registry to **Graphics.FontRegistry** before drawing. **Graphics** looks up fonts only in its own registry, so a font you added elsewhere stays invisible to it until you do.
 
The following snippet starts from the installed fonts and adds one more from a file:
 
```csharp
using (var bitmap = new Bitmap(500, 140, PixelFormat.Format24bppRgb, RgbColor.White))
using (var graphics = bitmap.GetGraphics())
{
    // Start from the installed system fonts, then add a font from a file.
    // Add(Stream) works the same way when the font comes from a database, an archive, and so on.
    using (var fontRegistry = new CustomFontRegistry())
    {
        fontRegistry.Merge(FontRegistry.Installed);
        var result = fontRegistry.Add(@"C:\Windows\Fonts\comic.ttf")[0];

        // Graphics resolves font names only against its own FontRegistry,
        // so assign the custom registry before drawing.
        graphics.FontRegistry = fontRegistry;

        var frame = new PointTextFrame()
        {
            Point = new System.Drawing.PointF(20, 80)
        };

        var text = new Text()
        {
            String = "Loaded from a file",
            CharStyle = new CharStyle(result.PostscriptName, 34)
        };

        text.Frames.Add(frame);

        graphics.DrawText(text);
    }

    bitmap.Save(@"Images\Output\CustomFontRegistry.png");
}
```
 ![Text drawn with a font loaded from a file](https://www.graphicsmill.com/docs/gm/CustomFontRegistry.png)
 
## Simplified Text Classes
  
Graphics Mill also provides [PlainText](https://www.graphicsmill.com/docs/gm/T_Aurigma_GraphicsMill_Drawing_PlainText.htm.md), [BoundedText](https://www.graphicsmill.com/docs/gm/T_Aurigma_GraphicsMill_Drawing_BoundedText.htm.md), [PathText](https://www.graphicsmill.com/docs/gm/T_Aurigma_GraphicsMill_Drawing_PathText.htm.md), and [DoublePathText](https://www.graphicsmill.com/docs/gm/T_Aurigma_GraphicsMill_Drawing_DoublePathText.htm.md). They are shorthand for the common cases: each one creates a text object with a single frame of the matching kind, without you having to build that frame yourself. They are convenient when a text needs no flow between frames and no frame-level tuning.
 
Use the **Text** class described in this topic when you need several frames, auto-sizing, copyfitting, or the other frame properties. See the [Drawing Simple Text Objects](https://www.graphicsmill.com/docs/gm/advanced-drawing-text.htm.md) article for the simplified classes.
 
## See Also
  
### Reference
 
- [Aurigma.GraphicsMill.Drawing Namespace](https://www.graphicsmill.com/docs/gm/N_Aurigma_GraphicsMill_Drawing.htm.md)
- [Graphics Class](https://www.graphicsmill.com/docs/gm/T_Aurigma_GraphicsMill_Drawing_Graphics.htm.md)
- [Text Class](https://www.graphicsmill.com/docs/gm/T_Aurigma_GraphicsMill_Drawing_Text.htm.md)
- [TextFrame Class](https://www.graphicsmill.com/docs/gm/T_Aurigma_GraphicsMill_Drawing_TextFrame.htm.md)
- [PointTextFrame Class](https://www.graphicsmill.com/docs/gm/T_Aurigma_GraphicsMill_Drawing_PointTextFrame.htm.md)
- [ShapeTextFrame Class](https://www.graphicsmill.com/docs/gm/T_Aurigma_GraphicsMill_Drawing_ShapeTextFrame.htm.md)
- [PathTextFrame Class](https://www.graphicsmill.com/docs/gm/T_Aurigma_GraphicsMill_Drawing_PathTextFrame.htm.md)
- [FontRegistry Class](https://www.graphicsmill.com/docs/gm/T_Aurigma_GraphicsMill_Drawing_FontRegistry.htm.md)
- [CustomFontRegistry Class](https://www.graphicsmill.com/docs/gm/T_Aurigma_GraphicsMill_Drawing_CustomFontRegistry.htm.md)
- [Path Class](https://www.graphicsmill.com/docs/gm/T_Aurigma_GraphicsMill_Drawing_Path.htm.md)

### Manual
 
- [Graphics: Drawing Images and Geometric Shapes](https://www.graphicsmill.com/docs/gm/graphics.htm.md)
- [Formatted Text](https://www.graphicsmill.com/docs/gm/advanced-formatted-text.htm.md)
- [Working with Font Registry](https://www.graphicsmill.com/docs/gm/working-with-font-registry.htm.md)
- [Drawing Simple Text Objects](https://www.graphicsmill.com/docs/gm/advanced-drawing-text.htm.md)
- [Working with Paths](https://www.graphicsmill.com/docs/gm/working-with-path.htm.md)
