![](http://habrastorage.org/getpro/habr/avatars/4ec/382/39f/4ec38239ffcb92bb65d31a3b2a77329a.jpg)
XNA: Text output in system fonts
XNA assumes the output of text only in advance prepared bitmap fonts. And it is right. Fast, OS independent, predictable text sizes.
In my case, the exact opposite was required. Arbitrary choice of headset and font size, and low performance requirements. The task was quite difficult. There was little information on the Internet and it was extremely fragmented.
Conditions: 2D application, the user at any time should be able to change the headset, style and font size.
The solution is quite simple. Create a bitmap with the desired text, create a texture from it and display it.
We create a bitmap using GDI tools.
Convert Bitmap to Texture
And display the texture
As a result, we get text with torn edges, a complete lack of smoothing.
![](https://habrastorage.org/storage2/0ba/f8b/0c7/0baf8b0c79f9fb9a8eed24db61953141.png)
Converting a bitmap to a texture turned out to be a non-trivial procedure.
The method is found here.
For the correct transfer of the alpha channel, additional actions are required in the TextureFromBitmap method.
First, we draw the data about the colors of the bitmap into the texture, then the information about the alpha channel.
Now we get a satisfactory result.
![](https://habrastorage.org/storage2/c53/58a/0e0/c5358a0e02cb44038faeedc6c434b210.png)
Source code
Problems:
1. Slowly. In no case should you use this method in games, and even more so on mobile devices.
2. Not reliable. The necessary fonts may not be in the system.
3. It is advisable to track how much of the text will be displayed on the screen and trim the invisible text. The maximum texture size is 2048x2048. If the bitmap size is larger, then the texture will be created with the maximum size and then stretched by the video card to the desired size. The text will be blurry.
You can get rid of converting to PNG in TextureFromBitmap using unmanaged code. An example can be seen here .
In my case, the exact opposite was required. Arbitrary choice of headset and font size, and low performance requirements. The task was quite difficult. There was little information on the Internet and it was extremely fragmented.
Conditions: 2D application, the user at any time should be able to change the headset, style and font size.
The solution is quite simple. Create a bitmap with the desired text, create a texture from it and display it.
We create a bitmap using GDI tools.
/// Draw text on bitmap
/// Bitmap with text
private System.Drawing.Bitmap Layout() {
// Get font
var font = new System.Drawing.Font( fontName, fontSize, fontStyle);
// Get text size
var bitmap = new System.Drawing.Bitmap( 1, 1 );
var graphics = System.Drawing.Graphics.FromImage( bitmap );
var textSize = graphics.MeasureString( text, font );
// Draw text on bitmap
bitmap = new System.Drawing.Bitmap( (int) textSize.Width, (int) textSize.Height );
graphics = System.Drawing.Graphics.FromImage( bitmap );
graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
graphics.DrawString( text, font, new System.Drawing.SolidBrush( this.color ), 0f, 0f );
return bitmap;
}
Convert Bitmap to Texture
/// Create texture from bitmap
/// Graphic device
/// Bitmap
/// Texture
private static Texture2D TextureFromBitmap(GraphicsDevice gdev, System.Drawing.Bitmap bmp) {
Stream fs = new MemoryStream();
bmp.Save(fs, System.Drawing.Imaging.ImageFormat.Png);
var tex = Texture2D.FromStream(gdev, fs);
fs.Close();
fs.Dispose();
return tex;
}
And display the texture
public void Draw() {
var spriteBatch = new SpriteBatch( graphicsDevice );
spriteBatch.Begin();
spriteBatch.Draw(
texture,
coordinate,
new Rectangle(0, 0, texture.Width, texture.Height),
Color.White,
0f, new Vector2(0, 0),
1.0f / textureDownsizeRatio,
SpriteEffects.None, 0);
spriteBatch.End();
}
As a result, we get text with torn edges, a complete lack of smoothing.
![](https://habrastorage.org/storage2/0ba/f8b/0c7/0baf8b0c79f9fb9a8eed24db61953141.png)
Converting a bitmap to a texture turned out to be a non-trivial procedure.
The method is found here.
For the correct transfer of the alpha channel, additional actions are required in the TextureFromBitmap method.
First, we draw the data about the colors of the bitmap into the texture, then the information about the alpha channel.
/// Create texture from bitmap
/// Graphic device
/// Bitmap
/// Texture
private static Texture2D TextureFromBitmap(GraphicsDevice gdev, System.Drawing.Bitmap bmp) {
Stream fs = new MemoryStream();
bmp.Save(fs, System.Drawing.Imaging.ImageFormat.Png);
var tex = Texture2D.FromStream(gdev, fs);
fs.Close();
fs.Dispose();
// Setup a render target to hold our final texture which will have premulitplied alpha values
var res = new RenderTarget2D(gdev, tex.Width, tex.Height);
gdev.SetRenderTarget(res);
gdev.Clear(Color.Black);
// Multiply each color by the source alpha, and write in just the color values into the final texture
var blendColor = new BlendState {
ColorWriteChannels = ColorWriteChannels.Red | ColorWriteChannels.Green | ColorWriteChannels.Blue,
AlphaDestinationBlend = Blend.Zero,
ColorDestinationBlend = Blend.Zero,
AlphaSourceBlend = Blend.SourceAlpha,
ColorSourceBlend = Blend.SourceAlpha
};
var spriteBatch = new SpriteBatch(gdev);
spriteBatch.Begin(SpriteSortMode.Immediate, blendColor);
spriteBatch.Draw(tex, tex.Bounds, Color.White);
spriteBatch.End();
// Now copy over the alpha values from the PNG source texture to the final one, without multiplying them
var blendAlpha = new BlendState {
ColorWriteChannels = ColorWriteChannels.Alpha,
AlphaDestinationBlend = Blend.Zero,
ColorDestinationBlend = Blend.Zero,
AlphaSourceBlend = Blend.One,
ColorSourceBlend = Blend.One
};
spriteBatch.Begin(SpriteSortMode.Immediate, blendAlpha);
spriteBatch.Draw(tex, tex.Bounds, Color.White);
spriteBatch.End();
// Release the GPU back to drawing to the screen
gdev.SetRenderTarget(null);
return res;
}
Now we get a satisfactory result.
![](https://habrastorage.org/storage2/c53/58a/0e0/c5358a0e02cb44038faeedc6c434b210.png)
Source code
Problems:
1. Slowly. In no case should you use this method in games, and even more so on mobile devices.
2. Not reliable. The necessary fonts may not be in the system.
3. It is advisable to track how much of the text will be displayed on the screen and trim the invisible text. The maximum texture size is 2048x2048. If the bitmap size is larger, then the texture will be created with the maximum size and then stretched by the video card to the desired size. The text will be blurry.
You can get rid of converting to PNG in TextureFromBitmap using unmanaged code. An example can be seen here .