- About Graphics Mill
- What's New?
- Breaking Changes in Graphics Mill 12
- Breaking Changes in Graphics Mill 11
- Features
- Supported File Formats
- System Requirements
- Getting Started
- Working with Image Formats
- Transforming Images (Resize, Rotate, Crop)
- Working with Metadata
- Color Management and Color Reduction
- Drawing Text and Graphics
- Color Keying (Green Screen Removal)
- Channels and Pixel Data
- Color and Tone Correction
- Working with Photoshop (PSD) Files
- Image Filters
- Processing Large Images
- Basics of Image Processing
- Troubleshooting
- Class Library Reference
- Licensing
- End User License Agreement
- Copyright Notices
Working with the Text Class
The Text 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 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:
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");
}
Text is always drawn through the Graphics.DrawText(Text) method, whatever frames it uses. If you are not familiar with Graphics, read the Graphics. Drawing Images and Geometric Shapes article first.
This topic covers the following:
Text Frames
A text frame is one of the classes derived from TextFrame. This topic covers the three frames you will use most often:
- PointTextFrame - text starts at a single point and grows without any bound.
- ShapeTextFrame - text is bounded by an arbitrary closed shape.
- PathTextFrame - text flows along a curve.
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:
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");
}
Point Text Frame
PointTextFrame is the simplest frame. It has an anchor PointTextFrame.Point and a PointTextFrame.TextOrientation 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:
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");
}
Shape Text Frame
ShapeTextFrame bounds the text by a ShapeTextFrame.Shape. The shape is any closed Path, 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.
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 resizes the shape to fit the text. ShapeTextFrame.AutoSizeAnchor 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:
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.CopyfittingMode 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:
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");
}
-
OffandFitToBoxshare text that overflows the box. WithOffthe last lines run past the bottom edge;FitToBoxmakes the whole text fit inside. -
FitToWidthandFitToWidthWithScaleshare 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. -
FillandFillWithScaleshare 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 positions the text block within the height of the shape:
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.FirstBaselineOffset selects the font metric
that positions the first baseline below the top of the frame.
ShapeTextFrame.FirstBaselineMinOffset 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:
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.TextOrientation 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:
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");
}
Path Text Frame
PathTextFrame flows the text along a PathTextFrame.Baseline path. Read the Working with Paths article if you are not familiar with Path. PathTextFrame.PathAlignment selects which part of the glyphs sits on the path:
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.Start and
PathTextFrame.End limit the text to a part of the path.
Both are fractions of the path length, from 0 to 1.
PathTextFrame.Flip mirrors the text to the other side of
the path:
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");
}
Several more properties tune the fit numerically. PathTextFrame.Spacing adds space between characters. PathTextFrame.VerticalOffset moves the text away from the path. PathTextFrame.Stretch stretches glyphs so they follow sharp curves more closely. PathTextFrame.AutoExtend lets the text run past the end of the path instead of stopping there. PathTextFrame.CopyfittingMode 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 and a Text.CharStyle. Text.CharStyle and Text.ParagraphStyle 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 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 and Text.Pen, and Text.Transform applies a geometric transform to the result.
Kernings
The Text.Kernings 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:
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");
}
Wrapping Paths
The Text.WrappingPaths 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:
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");
}
Add several paths to wrap the text around several obstacles at once:
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");
}
Effects
Set the Text.Effect property to make the text glow or cast a shadow. The Effects.Glow and Effects.Shadow classes and all their parameters are described in the Text Effects section of the Drawing Simple Text Objects article:
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");
}
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:
- 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 object provides these values through its Font.Metrics property. For a single line of text, Font.MeasureString(String) returns its width, height, ascender, and descender.
Measuring and Fitting
The Text.GetBlackBox(FontRegistry, Single, Single) 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) goes further and adjusts the text so that its black box matches a target rectangle. Both methods take a FontRegistry and the target DPI, because font metrics depend on them:
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");
}
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. 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 article.
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:
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");
}
Simplified Text Classes
Graphics Mill also provides PlainText, BoundedText, PathText, and DoublePathText. 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 article for the simplified classes.
See Also
Reference
- Aurigma.GraphicsMill.Drawing Namespace
- Graphics Class
- Text Class
- TextFrame Class
- PointTextFrame Class
- ShapeTextFrame Class
- PathTextFrame Class
- FontRegistry Class
- CustomFontRegistry Class
- Path Class