Representación de texto mediante la API de fuentes .NET

Descripción general

Si alguna vez quiso tener la función de representar texto en una imagen, el artículo aquí le enseñará cómo hacerlo con fuentes de cualquier formato, compatibles con la biblioteca de fuentes utilizando la solución API Aspose.Font. La biblioteca le permite convertir fácilmente texto en imágenes, así como agregar texto a cualquier imagen.

Representación de texto

Para insertar texto en una imagen, necesitará usar el método DrawText de la clase RenderingUtils. El siguiente código muestra cómo agregar el texto “Hola mundo” escrito en fuente Arial a una imagen llamada “arial.png”.

 1    var dataDir = @"C:\Temp\";
 2    var fileName = dataDir + "arial.ttf"; //Font file name with full path
 3    var outFile = dataDir + "arial.png";
 4    var fontDefinition = new FontDefinition(FontType.TTF, new FontFileDefinition("ttf", new FileSystemStreamSource(fileName)));
 5    var ttfFont = Font.Open(fontDefinition) as TtfFont;
 6
 7    var stream = Aspose.Font.Renderers.RenderingUtils.DrawText(ttfFont, "Hello world", 18);
 8
 9    var bitmap = new Bitmap(stream);
10    bitmap.Save(outFile);

El resultado de la implementación:

Hola arial

El método DrawText le permite establecer el interlineado y realizar un ajuste automático del texto palabra por palabra.

En el siguiente ejemplo de código, especificamos el tipo de interlineado LineSpacingType.Pixels y lo configuramos en 10, y configuramos el ancho máximo de la imagen en 450.

Todo el texto que no se pueda mostrar correctamente en el rango dado (en nuestro caso es 450) se ajustará en una nueva línea.

El código recortado muestra cómo representar el texto “Hola mundo” en fuente Arial y pasar a la siguiente línea:

 1    var dataDir = @"C:\Temp\";
 2    var fileName = dataDir + "arial.ttf"; //Font file name with full path
 3    var outFile = dataDir + "arial.png";
 4    var fontDefinition = new FontDefinition(FontType.TTF, new FontFileDefinition("ttf", new FileSystemStreamSource(fileName)));
 5    var ttfFont = Font.Open(fontDefinition) as TtfFont;
 6    var lineSpacingType = LineSpacingType.Pixels;
 7
 8    var stream = DrawText(ttfFont, "Hello world", 22, lineSpacingType, 10, 450);
 9
10    var bitmap = new Bitmap(stream);
11
12    bitmap.Save(outFile);

El resultado de la implementación:

Hola ajuste de texto arial

En este ejemplo, viste cómo puedes convertir texto en una imagen con solo una línea de código.

La familia de funciones para el método DrawText() cubre texto estándar o salida de texto multilínea. Pero, en algunos casos, es posible que necesite una salida personalizada del texto, por ejemplo, cuando desee comprimir, estirar, rotar el texto en ángulo o algo más. En este caso, deberá personalizar la salida según sus necesidades.

Representación de texto personalizada

El siguiente ejemplo muestra una forma más avanzada (personalizada) de convertir texto en una imagen.

Para dibujar glifos dentro de Aspose.Font se utiliza uno de los métodos RenderGlyph() de la clase GlyphOutlineRenderer. Todos estos métodos sobrecargados se declaran en la interfaz IGlyphRenderer.

Como parámetro debemos pasar a estos métodos una referencia a la fuente, glyphId o índice de glifo y las coordenadas de salida del glifo. Para transferir el último parámetro, se utiliza una matriz especial representada por el objeto Aspose.Font TransformationMatrix. A continuación mostramos cómo usar objetos del tipo TransformationMatrix para pasar coordenadas de salida de glifos a métodos de la familia RenderGlyph().

Entonces, para dibujar un glifo, necesitamos crear un objeto del tipo GlyphOutlineRenderer. Pero un objeto así no puede dibujar un glifo por sí solo. Requiere funcionalidad externa, que se describe en la interfaz IGlyphOutlinePainter. Para utilizar el objeto GlyphOutlineRenderer se debe proporcionar una implementación de IGlyphOutlinePainter.

A continuación puede ver una implementación simple de esta interfaz. Creemos la clase GlyphOutlinePainter que requiere un objeto de tipo System.Drawing.Drawing2D.GraphicsPath para objetivos de dibujo gráfico.

La implementación se ilustra a continuación.

 1    public class GlyphOutlinePainter : IGlyphOutlinePainter
 2    {
 3        private GraphicsPath _path;
 4        private PointF _currentPoint;
 5
 6        public GlyphOutlinePainter(GraphicsPath path)
 7        {
 8            _path = path;
 9        }
10
11        public void MoveTo(MoveTo moveTo)
12        {
13            _path.CloseFigure();
14            _currentPoint.X = (float)moveTo.X;
15            _currentPoint.Y = (float)moveTo.Y;
16        }
17
18        public void LineTo(LineTo lineTo)
19        {
20            float x = (float)lineTo.X;
21            float y = (float)lineTo.Y;
22            _path.AddLine(_currentPoint.X, _currentPoint.Y, x, y);
23            _currentPoint.X = x;
24            _currentPoint.Y = y;
25        }
26
27        public void CurveTo(CurveTo curveTo)
28        {
29            float x3 = (float)curveTo.X3;
30            float y3 = (float)curveTo.Y3;
31
32            _path.AddBezier(
33                _currentPoint.X,
34                _currentPoint.Y,
35                (float)curveTo.X1,
36                (float)curveTo.Y1,
37                (float)curveTo.X2,
38                (float)curveTo.Y2,
39                x3,
40                y3);
41
42            _currentPoint.X = x3;
43            _currentPoint.Y = y3;
44        }
45
46        public void ClosePath()
47        {
48            _path.CloseFigure();
49        }
50    }

Después de la implementación de IGlyphOutlinePainter, podemos usar objetos de su tipo para representar un glifo individual pasándolos al GlyphOutlineRenderer y llamando a los métodos sobrecargados correspondientes de RenderGlyph() familia.

Para representar una cadena de texto, necesitamos obtener el glyphId para cada carácter y luego, usando un objeto de tipo GlyphOutlineRenderer llamar a uno de los métodos de la familia RenderGlyph(), pasando las coordenadas del glifo correspondiente. Echemos un vistazo a un ejemplo de cómo generar una línea de texto usando la biblioteca Aspose.Font. Se creará en forma de método CustomDrawText(), que acepta parámetros: CustomDrawText(texto de cadena, fuente IFont, tamaño de fuente doble, pincel de fondo, pincel de texto, pincel de salida de cadena).

Cree el método CustomDrawText() que dibuja el texto especificado en el objeto System.Drawing.Bitmap y guarda el mapa de bits resultante en el disco.

Esto incluirá los siguientes pasos:

Pasos auxiliares para esta estrategia

La implementación del método CustomDrawText() se muestra a continuación.

 1    public static void CustomDrawText(string text, IFont font, double fontSize, Brush backgroundBrush, Brush textBrush, string outFile)
 2    {
 3        //Get glyph identifiers for every symbol in the text line
 4        GlyphId[] gids = new GlyphId[text.Length];
 5
 6        for (int i = 0; i < text.Length; i++)
 7            gids[i] = font.Encoding.DecodeToGid(text[i]);
 8
 9        // Set common drawing settings
10        double dpi = 300;
11        double resolutionCorrection = dpi / 72; // 72 is font's internal dpi
12
13        // Prepare output bitmap                
14        Bitmap outBitmap = new Bitmap(960, 720);
15
16
17        outBitmap.SetResolution((float)dpi, (float)dpi);
18
19        Graphics outGraphics = Graphics.FromImage(outBitmap);
20        outGraphics.FillRectangle(backgroundBrush, 0, 0, outBitmap.Width, outBitmap.Height);
21        outGraphics.SmoothingMode = SmoothingMode.HighQuality;
22
23        //Declare coordinate variables and a previous gid
24        GlyphId previousGid = null;
25        double glyphXCoordinate = 0;
26        double glyphYCoordinate = fontSize * resolutionCorrection;
27
28        // The loop paints every glyph in gids
29        foreach (GlyphId gid in gids)
30        {
31            // if the font contains the gid
32            if (gid != null)
33            {
34                Glyph glyph = font.GlyphAccessor.GetGlyphById(gid);
35                if (glyph == null)
36                    continue;
37
38                // The path that accepts drawing instructions
39                GraphicsPath path = new GraphicsPath();
40
41                // Create IGlyphOutlinePainter implementation
42                GlyphOutlinePainter outlinePainter = new GlyphOutlinePainter(path);
43
44                // Create the renderer
45                Aspose.Font.Renderers.IGlyphRenderer renderer = new Aspose.Font.Renderers.GlyphOutlineRenderer(outlinePainter);
46
47                // Get common glyph properties
48                double kerning = 0;
49
50                // Get kerning value
51
52                if (previousGid != null)
53                {
54                    kerning = (font.Metrics.GetKerningValue(previousGid, gid) / glyph.SourceResolution) * fontSize * resolutionCorrection;
55                    kerning += FontWidthToImageWith(font.Metrics.GetGlyphWidth(previousGid), glyph.SourceResolution, fontSize);
56                }
57
58                // Glyph positioning - increase glyph X coordinate according to kerning distance
59                glyphXCoordinate += kerning;
60
61                // Glyph placement matrix
62                TransformationMatrix glyphMatrix = new TransformationMatrix(
63                        new double[]
64                                { fontSize * resolutionCorrection,
65                            0,
66                            0,
67                        // negative because of the bitmap coordinate system begins from the top
68                            - fontSize*resolutionCorrection,
69                            glyphXCoordinate,
70                            glyphYCoordinate
71                                });
72
73                // Render the current glyph
74                renderer.RenderGlyph(font, gid, glyphMatrix);
75
76                // Fill the path
77                path.FillMode = FillMode.Winding;
78
79                outGraphics.FillPath(textBrush, path);
80            }
81
82            //Set current gid as previous to get correct kerning for next glyph
83            previousGid = gid;
84        }
85
86        //Save the results
87        outBitmap.Save(outFile);
88    }

Método de utilidad para convertir el ancho de fuente al ancho de imagen

1    static double FontWidthToImageWith(double width, int fontSourceResulution, double fontSize, double dpi = 300)
2    {
3        double resolutionCorrection = dpi / 72; // 72 is font's internal dpi
4
5        return (width / fontSourceResulution) * fontSize * resolutionCorrection;
6    }

El siguiente fragmento de código muestra cómo representar el texto “Hola mundo” usando el método CustomDrawText().

 1    var dataDir = @"C:\Temp\";
 2    var fileName1 = dataDir + "arial.ttf"; //Font file name with full path
 3    var fileName2 = dataDir + "calibrii.ttf"; //Font file name with full path
 4
 5    var fontDefinition1 = new FontDefinition(FontType.TTF, new FontFileDefinition("ttf", new FileSystemStreamSource(fileName1)));
 6    var ttfFont1 = Font.Open(fontDefinition1) as TtfFont;
 7
 8    var fontDefinition2 = new FontDefinition(FontType.TTF, new FontFileDefinition("ttf", new FileSystemStreamSource(fileName2)));
 9    var ttfFont2 = Font.Open(fontDefinition2) as TtfFont;
10
11    GlyphOutlinePainter.CustomDrawText("Hello world", ttfFont1, 24, Brushes.White, Brushes.Black, dataDir + "Hello_Arial_out.png");
12    GlyphOutlinePainter.CustomDrawText("Hello world", ttfFont2, 24, Brushes.Yellow, Brushes.Blue, dataDir + "Hello_Calibri_out.png");

Implementando el código obtendremos el siguiente resultado:

El resultado de la implementación:

Hola arial Arial

Hola calibri Calibr

Interletraje

Usando el valor de la variable kerning puedes cambiar la distancia entre glifos. Ahora reescribamos el código de la siguiente manera:

1 
2    //Glyph positioning - increase glyph X coordinate according to the kerning distance
3    kerning *= 1.25;
4    glyphXCoordinate += kerning;

Se obtendrá el siguiente resultado:

El resultado de la implementación:

Hola kerning arial kernint Arial

Hola calibri kerning Calibri kerning

Representar texto por coordenadas

Las variables glifoXCoordinate y glifoYCoordinate son responsables de las coordenadas de la salida del texto. Cambiando el código de la siguiente manera:

1    //Declare coordinate variables and the previous gid
2    GlyphId previousGid = null;
3    double glyphXCoordinate = 300;
4    double glyphYCoordinate = 300;

Se obtendrá el siguiente resultado:

El resultado de la implementación:

Hola kerning arial Arial x=300 y=300

Hola calibri kerning Calibri x=300 y=300

Cómo agregar el texto a una imagen.

También puede mostrar texto en una imagen existente. Para esto, reescribiremos el código de la siguiente manera:

 1 
 2    public static void CustomDrawText(string text, IFont font, double fontSize, Brush backgroundBrush, Brush textBrush, string outFile, Bitmap bitmap, double kerningCoefficient = 1, double coordinateX = 0, double coordinateY = 0)
 3    {
 4        //Get glyph identifiers for every symbol in the text line
 5        GlyphId[] gids = new GlyphId[text.Length];
 6
 7        for (int i = 0; i < text.Length; i++)
 8            gids[i] = font.Encoding.DecodeToGid(text[i]);
 9
10        // Set common drawing settings
11        double dpi = 300;
12        double resolutionCorrection = dpi / 72; // 72 is font's internal dpi
13
14        // Prepare the output bitmap                
15        Bitmap outBitmap = bitmap;
16
17        outBitmap.SetResolution((float)dpi, (float)dpi);
18
19        Graphics outGraphics = Graphics.FromImage(outBitmap);
20        outGraphics.FillRectangle(backgroundBrush, 0, 0, outBitmap.Width, outBitmap.Height);
21        outGraphics.SmoothingMode = SmoothingMode.HighQuality;
22
23        //Declare coordinate variables and the previous gid
24        GlyphId previousGid = null;
25        double glyphXCoordinate = coordinateX;
26        double glyphYCoordinate = coordinateY;
27
28        glyphYCoordinate += fontSize * resolutionCorrection;
29
30        //The loop paints every glyph in gids
31        foreach (GlyphId gid in gids)
32        {
33            // if the font contains the gid
34            if (gid != null)
35            {
36                Glyph glyph = font.GlyphAccessor.GetGlyphById(gid);
37                if (glyph == null)
38                    continue;
39
40                // The path that accepts drawing instructions
41                GraphicsPath path = new GraphicsPath();
42
43                // Create the IGlyphOutlinePainter implementation
44                GlyphOutlinePainter outlinePainter = new GlyphOutlinePainter(path);
45
46                // Create the renderer
47                Aspose.Font.Renderers.IGlyphRenderer renderer = new Aspose.Font.Renderers.GlyphOutlineRenderer(outlinePainter);
48
49                // Get common glyph properties
50                double kerning = 0;
51
52                // Get the kerning value
53
54                if (previousGid != null)
55                {
56                    kerning = (font.Metrics.GetKerningValue(previousGid, gid) / glyph.SourceResolution) * fontSize * resolutionCorrection;
57                    kerning += FontWidthToImageWith(font.Metrics.GetGlyphWidth(previousGid), glyph.SourceResolution, fontSize);
58                }
59
60                // Glyph positioning - increase the glyph X coordinate according to the kerning distance
61                glyphXCoordinate += kerning * kerningCoefficient;
62
63                // Glyph placement matrix
64                TransformationMatrix glyphMatrix = new TransformationMatrix(
65                        new double[]
66                                { fontSize * resolutionCorrection,
67                            0,
68                            0,
69                        // negative because of the bitmap coordinate system begins from the top
70                            - fontSize*resolutionCorrection,
71                            glyphXCoordinate,
72                            glyphYCoordinate
73                                });
74
75                // Render the current glyph
76                renderer.RenderGlyph(font, gid, glyphMatrix);
77
78                // Fill the path
79                path.FillMode = FillMode.Winding;
80
81                outGraphics.FillPath(textBrush, path);
82            }
83
84            //Set the current gid as previous to get the correct kerning for the next glyph
85            previousGid = gid;
86        }
87
88        //Save the results
89        outBitmap.Save(outFile);
90    }

Modifiquemos la forma en que se llama el Método:

 1    var dataDir = @"C:\Temp\";
 2    var fileName1 = dataDir + "arial.ttf"; //Font file name with full path
 3
 4    var fontDefinition1 = new FontDefinition(FontType.TTF, new FontFileDefinition("ttf", new FileSystemStreamSource(fileName1)));
 5    var ttfFont1 = Font.Open(fontDefinition1) as TtfFont;
 6
 7    var bitmap = new Bitmap(960, 720);
 8
 9    GlyphOutlinePainter.CustomDrawText("Hello world", ttfFont1, 17, Brushes.White, Brushes.Black, dataDir + "Hello_Arial_out.png", bitmap);
10
11    var inputImagePath = dataDir + "Hello_Arial_out.png";
12    var bitmapAddText = new Bitmap(inputImagePath);
13
14    GlyphOutlinePainter.CustomDrawText("Hello world", ttfFont1, 17, Brushes.Transparent, Brushes.Gray, dataDir + "Hello_Arial_Shadow_out.png", bitmapAddText, 1, -3);
15
16    GlyphOutlinePainter.CustomDrawText("<= Shadow effect", ttfFont1, 17, Brushes.Transparent, Brushes.Brown, dataDir + "Hello_Arial_Shadow_out.png", bitmapAddText, 1, 400);

El resultado de la implementación:

Hola efecto de sombra arial Efecto de sombra Arial

Salida del texto de arriba a abajo

Para mostrar el texto de arriba a abajo, hagamos los siguientes cambios en el método CustomDrawText().

 1    public static void CustomDrawText(string text, IFont font, double fontSize, Brush backgroundBrush, Brush textBrush, string outFile, Bitmap bitmap, double kerningCoefficient = 1, double coordinateX = 0, double coordinateY = 0, bool topDown = false)
 2    {
 3        //Get glyph identifiers for every symbol in the text line
 4        GlyphId[] gids = new GlyphId[text.Length];
 5
 6        for (int i = 0; i < text.Length; i++)
 7            gids[i] = font.Encoding.DecodeToGid(text[i]);
 8
 9        // Set common drawing settings
10        double dpi = 300;
11        double resolutionCorrection = dpi / 72; // 72 is font's internal dpi
12
13        // Prepare the output bitmap                
14        Bitmap outBitmap = bitmap;
15
16        outBitmap.SetResolution((float)dpi, (float)dpi);
17
18        Graphics outGraphics = Graphics.FromImage(outBitmap);
19        outGraphics.FillRectangle(backgroundBrush, 0, 0, outBitmap.Width, outBitmap.Height);
20        outGraphics.SmoothingMode = SmoothingMode.HighQuality;
21
22        //Declare coordinate variables and the previous gid
23        GlyphId previousGid = null;
24        double glyphXCoordinate = coordinateX;
25        double glyphYCoordinate = coordinateY;
26
27        glyphYCoordinate += fontSize * resolutionCorrection;
28
29        //The loop paints every glyph in gids
30        foreach (GlyphId gid in gids)
31        {
32            // if the font contains the gid
33            if (gid != null)
34            {
35                Glyph glyph = font.GlyphAccessor.GetGlyphById(gid);
36                if (glyph == null)
37                    continue;
38
39                // The path that accepts drawing instructions
40                GraphicsPath path = new GraphicsPath();
41
42                // Create IGlyphOutlinePainter implementation
43                GlyphOutlinePainter outlinePainter = new GlyphOutlinePainter(path);
44
45                // Create the renderer
46                Aspose.Font.Renderers.IGlyphRenderer renderer = new Aspose.Font.Renderers.GlyphOutlineRenderer(outlinePainter);
47
48                // Get common glyph properties
49                double kerning = 0;
50
51                // Get kerning value                        
52                if (previousGid != null && !topDown)
53                {
54                    kerning = (font.Metrics.GetKerningValue(previousGid, gid) / glyph.SourceResolution) * fontSize * resolutionCorrection;
55                    kerning += FontWidthToImageWith(font.Metrics.GetGlyphWidth(previousGid), glyph.SourceResolution, fontSize);
56                }
57
58                if (topDown)
59                {
60                    glyphYCoordinate += fontSize * resolutionCorrection;
61                }
62                else
63                {
64                    // Glyph positioning - increase the glyph X coordinate according to kerning distance                       
65                    glyphXCoordinate += kerning * kerningCoefficient;
66                }
67
68                // Glyph placement matrix
69                TransformationMatrix glyphMatrix = new TransformationMatrix(
70                        new double[]
71                                { fontSize * resolutionCorrection,
72                            0,
73                            0,
74                        // negative because the bitmap coordinate system begins from the top
75                            - fontSize*resolutionCorrection,
76                            glyphXCoordinate,
77                            glyphYCoordinate
78                                });
79
80                // Render the current glyph
81                renderer.RenderGlyph(font, gid, glyphMatrix);
82
83                // Fill the path
84                path.FillMode = FillMode.Winding;
85
86                outGraphics.FillPath(textBrush, path);
87            }
88
89            //Set the current gid as previous to get correct kerning for the next glyph
90            previousGid = gid;
91        }
92
93        //Save the results
94        outBitmap.Save(outFile);
95    }

El código para la llamada al método tendrá el siguiente aspecto:

1    var dataDir = @"C:\Temp\";
2    var fileName1 = dataDir + "arial.ttf"; //Font file name with full path
3    var fontDefinition1 = new FontDefinition(FontType.TTF, new FontFileDefinition("ttf", new FileSystemStreamSource(fileName1)));
4    var ttfFont1 = Font.Open(fontDefinition1) as TtfFont;
5    var bitmap = new Bitmap(960, 720);
6
7    GlyphOutlinePainter.CustomDrawText("Top down", ttfFont1, 18, Brushes.White, Brushes.Black, dataDir + "Hello_Arial_TopDown.png", bitmap, 1, 400, 00, true);

El resultado de la implementación:

Hola arial de arriba a abajo Arial de arriba a abajo

información adicional

1    double dpi; // dots per inch
2    double resolutionCorrection = dpi / 72; // 72 is font's internal dpi
3    // Coordinate variables
4    double glyphXCoordinate; // X
5    double glyphYCoordinate; // Y;
6    // Kerning - horizontal spacing between two letters
7    double kerning = 0;

Have any questions about Aspose.Font?



Subscribe to Aspose Product Updates

Get monthly newsletters & offers directly delivered to your mailbox.