Textwiedergabe mithilfe der Schriftartenbibliothek | .NET

Überblick

Wenn Sie jemals die Funktion zum Rendern von Text in ein Bild nutzen wollten, erfahren Sie in diesem Artikel, wie Sie dies mit Schriftarten in jedem Format tun können, die von der Schriftartenbibliothek mithilfe der Aspose.Font-API-Lösung unterstützt werden. Mit der Bibliothek können Sie problemlos Text in Bilder umwandeln und jedem Bild Text hinzufügen.

Text rendern

Verwenden Sie die Methode DrawText der Klasse RenderingUtils, um Text in ein Bild zu zeichnen. Das Beispiel rendert „Hello world“ in Verdana und speichert den PNG-Stream als Text.png.

Setzen Sie DataDir auf das Verzeichnis mit TTF/verdana.ttf und TTF/LatoWeb-Regular.ttf und OutputDir auf ein vorhandenes Ausgabeverzeichnis. Die Beispiele verwenden die Namespaces Aspose.Font, Aspose.Font.Sources, Aspose.Font.Renderers, System, System.IO. Im Testprojekt stellt BaseTests die Verzeichnisse und die Lizenzeinrichtung bereit.

 1// Render text to a PNG image
 2
 3string fontPath = Path.Combine(DataDir, "TTF", "verdana.ttf");
 4Font font = Font.Open(new FontDefinition(FontType.TTF, "ttf", new FileSystemStreamSource(fontPath)));
 5string text = "Hello world";
 6string outFile = Path.Combine(OutputDir, "Text.png");
 7using (Stream image = RenderingUtils.DrawText(font, text, 18))
 8{
 9    image.Position = 0;
10    using FileStream output = File.Create(outFile);
11    image.CopyTo(output);
12}
Example-DrawText.cs hosted with ❤ by GitHub

Das Ergebnis der Implementierung:

Hello world in Verdana

Mit der Methode DrawText können Sie den Zeilenabstand festlegen und einen automatischen wortweisen Textumbruch durchführen.

Im folgenden Codebeispiel haben wir den Zeilenabstandstyp LineSpacingType.Pixels angegeben und auf 10 festgelegt, und wir haben die maximale Breite des Bildes auf 450 festgelegt.

Der gesamte Text, der im angegebenen Bereich (in unserem Fall 450) nicht korrekt angezeigt werden kann, wird in eine neue Zeile umgebrochen.

Das Beispiel wiederholt „Hello world“ in Verdana, damit der Text die Breite von 450 Pixeln überschreitet und auf weitere Zeilen umbricht. Das Ergebnis wird als WrappedText.png gespeichert:

 1// Render wrapped text with pixel line spacing
 2
 3string fontPath = Path.Combine(DataDir, "TTF", "verdana.ttf");
 4Font font = Font.Open(new FontDefinition(FontType.TTF, "ttf", new FileSystemStreamSource(fontPath)));
 5string text = "Hello world Hello world Hello world Hello world Hello world Hello world";
 6string outFile = Path.Combine(OutputDir, "WrappedText.png");
 7using (Stream image = RenderingUtils.DrawText(font, text, 22, RenderingUtils.LineSpacingType.Pixels, 10, 450))
 8{
 9    image.Position = 0;
10    using FileStream output = File.Create(outFile);
11    image.CopyTo(output);
12}

Das Ergebnis der Implementierung:

Hello world in Verdana mit Zeilenumbruch

DrawText() liefert einen PNG-Stream. Die Beispiele setzen dessen Position auf den Anfang, kopieren ihn in eine Datei und geben beide Streams frei.

Die Funktionsfamilie für die Methode „DrawText()“ deckt die Ausgabe von Standardtext oder mehrzeiligem Text ab. In einigen Fällen benötigen Sie jedoch möglicherweise eine benutzerdefinierte Ausgabe des Texts, beispielsweise wenn Sie den Text komprimieren, strecken, in einem Winkel drehen oder etwas anderes möchten. In diesem Fall müssen Sie die Ausgabe an Ihre Bedürfnisse anpassen.

Benutzerdefinierte Textwiedergabe

Die folgenden Beispiele zeichnen Glyphenkonturen mit System.Drawing.Common unter Windows auf einer Zeichenfläche von 960 x 720 Pixeln bei 300 DPI. Importieren Sie zusätzlich die Namespaces Aspose.Font.Glyphs, Aspose.Font.Rendering, Aspose.Font.RenderingPath, System.Drawing, System.Drawing.Drawing2D, System.Drawing.Imaging.

Zum Zeichnen von Glyphen in Aspose.Font wird eine der RenderGlyph()-Methoden der Klasse GlyphOutlineRenderer verwendet. Alle diese überladenen Methoden werden in der Schnittstelle IGlyphRenderer deklariert.

Als Parameter müssen wir diesen Methoden einen Verweis auf die Schriftart, die Glyphen-ID oder den Glyphenindex und die Glyphen-Ausgabekoordinaten übergeben. Zur Übergabe des letzten Parameters wird eine spezielle Matrix verwendet, die durch das Objekt Aspose.Font TransformationMatrix repräsentiert wird.

Im Folgenden zeigen wir, wie Sie Objekte vom Typ TransformationMatrix verwenden, um Glyphen-Ausgabekoordinaten an Methoden der Familie RenderGlyph() zu übergeben.

Um also eine Glyphe zu zeichnen, müssen wir ein Objekt vom Typ GlyphOutlineRenderer erstellen. Ein solches Objekt kann jedoch nicht alleine eine Glyphe zeichnen. Es erfordert externe Funktionalität, die durch die Schnittstelle IGlyphOutlinePainter beschrieben wird. Um das Objekt GlyphOutlineRenderer verwenden zu können, muss eine Implementierung von IGlyphOutlinePainter bereitgestellt werden.

Unten sehen Sie eine einfache Implementierung dieser Schnittstelle. Erstellen wir die Klasse GlyphOutlinePainter, die ein Objekt vom Typ System.Drawing.Drawing2D.GraphicsPath für grafische Zeichnungsziele erfordert.

Die Schnittstellenimplementierung folgt unten. Fügen Sie die später gezeigten Überladungen von CustomDrawText() und die Methode FontWidthToImageWidth() als Mitglieder zu GlyphOutlinePainter hinzu. Im Beispielprojekt stehen diese Methoden in einer zweiten partiellen Deklaration derselben Klasse.

 1// Implement a glyph outline painter
 2
 3public partial class GlyphOutlinePainter : IGlyphOutlinePainter
 4{
 5    private readonly GraphicsPath path;
 6    private PointF currentPoint;
 7
 8    public GlyphOutlinePainter(GraphicsPath path)
 9    {
10        this.path = path;
11    }
12
13    public void MoveTo(MoveTo moveTo)
14    {
15        path.CloseFigure();
16        currentPoint = new PointF((float)moveTo.X, (float)moveTo.Y);
17    }
18
19    public void LineTo(LineTo lineTo)
20    {
21        var next = new PointF((float)lineTo.X, (float)lineTo.Y);
22        path.AddLine(currentPoint, next);
23        currentPoint = next;
24    }
25
26    public void CurveTo(CurveTo curveTo)
27    {
28        var next = new PointF((float)curveTo.X3, (float)curveTo.Y3);
29        path.AddBezier(currentPoint, new PointF((float)curveTo.X1, (float)curveTo.Y1),
30            new PointF((float)curveTo.X2, (float)curveTo.Y2), next);
31        currentPoint = next;
32    }
33
34    public void ClosePath()
35    {
36        path.CloseFigure();
37    }
38}

Nach der IGlyphOutlinePainter-Implementierung können wir Objekte dieses Typs verwenden, um eine einzelne Glyphe zu rendern, indem wir sie an den GlyphOutlineRenderer übergeben und die entsprechenden überladenen Methoden von RenderGlyph() aufrufen Familie.

Um eine Textzeichenfolge zu rendern, müssen wir die glyphId für jedes Zeichen abrufen und dann mit einem Objekt vom Typ GlyphOutlineRenderer eine der Methoden der Familie RenderGlyph() aufrufen. Übergabe der Koordinaten des entsprechenden Glyphen. Schauen wir uns ein Beispiel für die Ausgabe einer Textzeile mithilfe der Aspose.Font-Bibliothek an. Es wird in Form der Methode CustomDrawText() erstellt, die Parameter akzeptiert: CustomDrawText(String Text, IFont Font, Double FontSize, Brush BackgroundBrush, Brush TextBrush, String OutFile).

Erstellen Sie die Methode CustomDrawText(), die den angegebenen Text in das Objekt System.Drawing.Bitmap zeichnet und die resultierende Bitmap auf der Disc speichert.

Dies umfasst die folgenden Schritte:

Hilfsschritte für diese Strategie

Die erste Überladung erstellt eine Bitmap und gibt sie frei. Die zweite nimmt eine Bitmap entgegen, die dem aufrufenden Code gehört, und unterstützt Abstände, Koordinaten, Überlagerungen und vertikale Ausgabe. Fügen Sie beide Überladungen zu GlyphOutlinePainter hinzu:

 1// Render text with spacing, coordinates, overlays and vertical layout
 2
 3public static void CustomDrawText(string text, IFont font, double fontSize,
 4    Brush backgroundBrush, Brush textBrush, string outFile)
 5{
 6    using var bitmap = new Bitmap(960, 720);
 7    CustomDrawText(text, font, fontSize, backgroundBrush, textBrush, outFile, bitmap);
 8}
 9
10public static void CustomDrawText(string text, IFont font, double fontSize,
11    Brush backgroundBrush, Brush textBrush, string outFile, Bitmap bitmap,
12    double kerningCoefficient = 1, double coordinateX = 0, double coordinateY = 0, bool topDown = false)
13{
14    const double dpi = 300;
15    double scale = fontSize * dpi / 72;
16    bitmap.SetResolution((float)dpi, (float)dpi);
17    using (Graphics graphics = Graphics.FromImage(bitmap))
18    {
19        // A transparent background preserves an existing image for overlays.
20        graphics.FillRectangle(backgroundBrush, 0, 0, bitmap.Width, bitmap.Height);
21        graphics.SmoothingMode = SmoothingMode.HighQuality;
22        GlyphId? previousGid = null;
23        double glyphXCoordinate = coordinateX;
24        double glyphYCoordinate = coordinateY + scale;
25
26        foreach (char character in text)
27        {
28            GlyphId gid = font.Encoding.DecodeToGid(character);
29            if (gid == null) continue;
30            Glyph glyph = font.GlyphAccessor.GetGlyphById(gid);
31            if (glyph == null) continue;
32
33            if (previousGid != null)
34            {
35                if (topDown)
36                    glyphYCoordinate += scale;
37                else
38                {
39                    double advance = FontWidthToImageWidth(font.Metrics.GetGlyphWidth(previousGid),
40                        glyph.SourceResolution, fontSize, dpi);
41                    double kerning = font.Metrics.GetKerningValue(previousGid, gid)
42                        / (double)glyph.SourceResolution * scale;
43                    // Like the source example, the coefficient scales the whole advance.
44                    glyphXCoordinate += (advance + kerning) * kerningCoefficient;
45                }
46            }
47
48            using var path = new GraphicsPath();
49            var painter = new GlyphOutlinePainter(path);
50            var renderer = new GlyphOutlineRenderer(painter);
51            var matrix = new TransformationMatrix(new double[]
52            {
53                scale, 0, 0, -scale, glyphXCoordinate, glyphYCoordinate
54            });
55            renderer.RenderGlyph(font, gid, matrix);
56            path.FillMode = FillMode.Winding;
57            graphics.FillPath(textBrush, path);
58            previousGid = gid;
59        }
60    }
61    // The caller owns the supplied bitmap and may reuse it for another overlay.
62    bitmap.Save(outFile, ImageFormat.Png);
63}

Fügen Sie dieser Klasse die Hilfsmethode zur Umrechnung der Breite von Schrifteinheiten in Pixel hinzu:

1// Convert font units to image pixels
2
3private static double FontWidthToImageWidth(double width, int fontSourceResolution,
4    double fontSize, double dpi = 300)
5{
6    return width / fontSourceResolution * fontSize * dpi / 72;
7}

Das Beispiel rendert „Hello world“ in Verdana schwarz auf Weiß und in Lato blau auf Gelb. Die Ergebnisse werden als Custom_Verdana.png und Custom_Lato.png gespeichert:

 1// Render two fonts with a custom glyph painter
 2
 3string verdanaPath = Path.Combine(DataDir, "TTF", "verdana.ttf");
 4string latoPath = Path.Combine(DataDir, "TTF", "LatoWeb-Regular.ttf");
 5Font verdana = Font.Open(new FontDefinition(FontType.TTF, "ttf", new FileSystemStreamSource(verdanaPath)));
 6Font lato = Font.Open(new FontDefinition(FontType.TTF, "ttf", new FileSystemStreamSource(latoPath)));
 7string verdanaOutput = Path.Combine(OutputDir, "Custom_Verdana.png");
 8string latoOutput = Path.Combine(OutputDir, "Custom_Lato.png");
 9GlyphOutlinePainter.CustomDrawText("Hello world", verdana, 24, Brushes.White, Brushes.Black, verdanaOutput);
10GlyphOutlinePainter.CustomDrawText("Hello world", lato, 24, Brushes.Yellow, Brushes.Blue, latoOutput);

Das Ergebnis der Implementierung:

Benutzerdefiniertes Text-Rendering in Verdana Verdana

Benutzerdefiniertes Text-Rendering in Lato Lato

Kerning

Die Hilfsmethode liest das Paar-Kerning aus der Schrift. kerningCoefficient: 1.25 vergrößert den gesamten horizontalen Vorschub (Breite der vorherigen Glyphe plus Paar-Kerning) um 25 %. Das Beispiel verwendet Verdana und speichert IncreasedSpacing.png:

1// Increase the horizontal glyph advance
2
3string fontPath = Path.Combine(DataDir, "TTF", "verdana.ttf");
4Font font = Font.Open(new FontDefinition(FontType.TTF, "ttf", new FileSystemStreamSource(fontPath)));
5string outFile = Path.Combine(OutputDir, "IncreasedSpacing.png");
6using var bitmap = new Bitmap(960, 720);
7GlyphOutlinePainter.CustomDrawText("Hello world", font, 18, Brushes.White, Brushes.Black,
8    outFile, bitmap, kerningCoefficient: 1.25);

Das Ergebnis der Implementierung:

Verdana mit einem Abstandsfaktor von 1.25 Verdana mit einem Abstandsfaktor von 1.25

Text anhand von Koordinaten rendern

Positionieren Sie den Text mit coordinateX und coordinateY. Für die erste Grundlinie addiert die Methode fontSize * 300 / 72 Pixel zu coordinateY. Bei 18 Punkt setzen coordinateX: 300 und coordinateY: 225 die erste Grundlinie auf (300, 300). Das Ergebnis wird als PositionedText.png gespeichert:

1// Position text at explicit coordinates
2
3string fontPath = Path.Combine(DataDir, "TTF", "verdana.ttf");
4Font font = Font.Open(new FontDefinition(FontType.TTF, "ttf", new FileSystemStreamSource(fontPath)));
5string outFile = Path.Combine(OutputDir, "PositionedText.png");
6using var bitmap = new Bitmap(960, 720);
7// At 18 points and 300 DPI the 75-pixel baseline offset makes the baseline Y=300.
8GlyphOutlinePainter.CustomDrawText("Hello world", font, 18, Brushes.White, Brushes.Black,
9    outFile, bitmap, coordinateX: 300, coordinateY: 225);

Das Ergebnis der Implementierung:

Verdana, erste Grundlinie bei X=300 und Y=300 Verdana, erste Grundlinie bei X=300 und Y=300

So fügen Sie den Text zu einem Bild hinzu

Um Text auf ein vorhandenes Bild zu zeichnen, übergeben Sie der gemeinsamen Hilfsmethode eine Bitmap und einen transparenten Hintergrundpinsel. Der transparente Pinsel erhält die vorhandenen Pixel.

Die oben gezeigte Bitmap-Überladung von CustomDrawText() unterstützt diesen Fall bereits. Sie zeichnet auf die übergebene Bitmap und speichert sie als PNG; die Bitmap bleibt im Besitz des aufrufenden Codes.

Das Beispiel erstellt zuerst OverlayBase.png in OutputDir, öffnet dieses Bild und fügt einen grauen Schatten sowie eine braune Beschriftung hinzu. Es speichert Shadow.png und ShadowAnnotated.png getrennt; ein externes Eingabebild ist nicht erforderlich:

 1// Add a shadow and annotation to an existing image
 2
 3string fontPath = Path.Combine(DataDir, "TTF", "verdana.ttf");
 4Font font = Font.Open(new FontDefinition(FontType.TTF, "ttf", new FileSystemStreamSource(fontPath)));
 5string inputImagePath = Path.Combine(OutputDir, "OverlayBase.png");
 6GlyphOutlinePainter.CustomDrawText("Hello world", font, 17, Brushes.White, Brushes.Black, inputImagePath);
 7using var bitmap = new Bitmap(inputImagePath);
 8string shadowFile = Path.Combine(OutputDir, "Shadow.png");
 9GlyphOutlinePainter.CustomDrawText("Hello world", font, 17, Brushes.Transparent, Brushes.Gray,
10    shadowFile, bitmap, coordinateX: -3);
11string annotatedFile = Path.Combine(OutputDir, "ShadowAnnotated.png");
12GlyphOutlinePainter.CustomDrawText("<= Shadow effect", font, 17, Brushes.Transparent, Brushes.Brown,
13    annotatedFile, bitmap, coordinateX: 400);

Das Ergebnis der Implementierung:

Verdana mit Schatten Verdana mit Schatten

Verdana mit Schatten und Beschriftung. Die Beschriftung wird am rechten Rand der 960 Pixel breiten Zeichenfläche abgeschnitten. Verdana mit Schatten und Beschriftung. Die Beschriftung wird am rechten Rand der 960 Pixel breiten Zeichenfläche abgeschnitten.

Ausgabe des Textes von oben nach unten

Dieselbe Überladung unterstützt mit topDown: true die vertikale Ausgabe. Sie setzt die erste Glyphe auf die erste Grundlinie und verschiebt jede weitere Glyphe um fontSize * 300 / 72 Pixel nach unten.

Das Beispiel rendert „Top down“ in Verdana bei X=400 und speichert TopDown.png. Bei coordinateY gleich null und 18 Punkt liegt die erste Grundlinie bei Y=75 Pixeln:

1// Render text vertically from top to bottom
2
3string fontPath = Path.Combine(DataDir, "TTF", "verdana.ttf");
4Font font = Font.Open(new FontDefinition(FontType.TTF, "ttf", new FileSystemStreamSource(fontPath)));
5string outFile = Path.Combine(OutputDir, "TopDown.png");
6using var bitmap = new Bitmap(960, 720);
7GlyphOutlinePainter.CustomDrawText("Top down", font, 18, Brushes.White, Brushes.Black,
8    outFile, bitmap, coordinateX: 400, topDown: true);
Example-RenderTopDown.cs hosted with ❤ by GitHub

Das Ergebnis der Implementierung:

Verdana, von oben nach unten Verdana, von oben nach unten

Weitere Informationen

Die Hilfsmethode verwendet 300 DPI. scale = fontSize * dpi / 72 rechnet die Schriftgröße von Punkt in Pixel um. glyphXCoordinate und glyphYCoordinate bestimmen die Position der Glyphengrundlinie. Bei horizontaler Ausgabe umfasst der nächste Vorschub die Breite der vorherigen Glyphe und das Paar-Kerning der Schrift; kerningCoefficient skaliert deren Summe.