ravi.joshi53's picture

Printing the text in Hindi language using QuickFont

I wanted to print some text in Hindi language using QuickFont. Basically I have a text in Hindi (say "नमस्ते"), which should be printed. Below is the snippet of code-

QFont font = new QFont("Fonts/Shangrila TextualB.ttf", 30, fontBuilderConfiguration);
font.Print("नमस्ते", QFontAlignment.Centre, new Vector2(RightX / 2, BottomY / 2));

I have downloaded ttf font from here

If i replace the string (which needs to be printed) from Hindi to English, it is printing the text. I am looking for a way so that I can simply use the above code.


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture

I do not believe that QuickFont can do this.

For international text, your best bet would be to use the OS to print text to a bitmap and then upload the bitmap to an OpenGL texture. Example code from TextRendering.cs:

// This code was written for the OpenTK library and has been released
// to the Public Domain.
// It is provided "as is" without express or implied warranty of any kind.
 
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
 
namespace Examples.Tutorial
{
    class TextRendering : GameWindow
    {
        TextRenderer renderer;
        Font serif = new Font(FontFamily.GenericSerif, 24);
        Font sans = new Font(FontFamily.GenericSansSerif, 24);
        Font mono = new Font(FontFamily.GenericMonospace, 24);
 
        /// <summary>
        /// Uses System.Drawing for 2d text rendering.
        /// </summary>
        public class TextRenderer : IDisposable
        {
            Bitmap bmp;
            Graphics gfx;
            int texture;
            Rectangle dirty_region;
            bool disposed;
 
            #region Constructors
 
            /// <summary>
            /// Constructs a new instance.
            /// </summary>
            /// <param name="width">The width of the backing store in pixels.</param>
            /// <param name="height">The height of the backing store in pixels.</param>
            public TextRenderer(int width, int height)
            {
                if (width <= 0)
                    throw new ArgumentOutOfRangeException("width");
                if (height <= 0)
                    throw new ArgumentOutOfRangeException("height ");
                if (GraphicsContext.CurrentContext == null)
                    throw new InvalidOperationException("No GraphicsContext is current on the calling thread.");
 
                bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                gfx = Graphics.FromImage(bmp);
                gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
 
                texture = GL.GenTexture();
                GL.BindTexture(TextureTarget.Texture2D, texture);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
                GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, width, height, 0,
                    PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);
            }
 
            #endregion
 
            #region Public Members
 
            /// <summary>
            /// Clears the backing store to the specified color.
            /// </summary>
            /// <param name="color">A <see cref="System.Drawing.Color"/>.</param>
            public void Clear(Color color)
            {
                gfx.Clear(color);
                dirty_region = new Rectangle(0, 0, bmp.Width, bmp.Height);
            }
 
            /// <summary>
            /// Draws the specified string to the backing store.
            /// </summary>
            /// <param name="text">The <see cref="System.String"/> to draw.</param>
            /// <param name="font">The <see cref="System.Drawing.Font"/> that will be used.</param>
            /// <param name="brush">The <see cref="System.Drawing.Brush"/> that will be used.</param>
            /// <param name="point">The location of the text on the backing store, in 2d pixel coordinates.
            /// The origin (0, 0) lies at the top-left corner of the backing store.</param>
            public void DrawString(string text, Font font, Brush brush, PointF point)
            {
                gfx.DrawString(text, font, brush, point);
 
                SizeF size = gfx.MeasureString(text, font);
                dirty_region = Rectangle.Round(RectangleF.Union(dirty_region, new RectangleF(point, size)));
                dirty_region = Rectangle.Intersect(dirty_region, new Rectangle(0, 0, bmp.Width, bmp.Height));
            }
 
            /// <summary>
            /// Gets a <see cref="System.Int32"/> that represents an OpenGL 2d texture handle.
            /// The texture contains a copy of the backing store. Bind this texture to TextureTarget.Texture2d
            /// in order to render the drawn text on screen.
            /// </summary>
            public int Texture
            {
                get
                {
                    UploadBitmap();
                    return texture;
                }
            }
 
            #endregion
 
            #region Private Members
 
            // Uploads the dirty regions of the backing store to the OpenGL texture.
            void UploadBitmap()
            {
                if (dirty_region != RectangleF.Empty)
                {
                    System.Drawing.Imaging.BitmapData data = bmp.LockBits(dirty_region,
                        System.Drawing.Imaging.ImageLockMode.ReadOnly,
                        System.Drawing.Imaging.PixelFormat.Format32bppArgb);
 
                    GL.BindTexture(TextureTarget.Texture2D, texture);
                    GL.TexSubImage2D(TextureTarget.Texture2D, 0,
                        dirty_region.X, dirty_region.Y, dirty_region.Width, dirty_region.Height,
                        PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);
 
                    bmp.UnlockBits(data);
 
                    dirty_region = Rectangle.Empty;
                }
            }
 
            #endregion
 
            #region IDisposable Members
 
            void Dispose(bool manual)
            {
                if (!disposed)
                {
                    if (manual)
                    {
                        bmp.Dispose();
                        gfx.Dispose();
                        if (GraphicsContext.CurrentContext != null)
                            GL.DeleteTexture(texture);
                    }
 
                    disposed = true;
                }
            }
 
            public void Dispose()
            {
                Dispose(true);
                GC.SuppressFinalize(this);
            }
 
            ~TextRenderer()
            {
                Console.WriteLine("[Warning] Resource leaked: {0}.", typeof(TextRenderer));
            }
 
            #endregion
        }
 
        #region Constructor
 
        public TextRendering()
            : base(800, 600)
        {
        }
 
        #endregion
 
        #region OnLoad
 
        protected override void OnLoad(EventArgs e)
        {
            renderer = new TextRenderer(Width, Height);
            PointF position = PointF.Empty;
 
            renderer.Clear(Color.MidnightBlue);
            renderer.DrawString("नमस्ते", serif, Brushes.White, position);
            position.Y += serif.Height;
            renderer.DrawString("नमस्ते", sans, Brushes.White, position);
            position.Y += sans.Height;
            renderer.DrawString("नमस्ते", mono, Brushes.White, position);
            position.Y += mono.Height;
        }
 
        #endregion
 
        #region OnUnload
 
        protected override void OnUnload(EventArgs e)
        {
            renderer.Dispose();
        }
 
        #endregion
 
        #region OnResize
 
        protected override void OnResize(EventArgs e)
        {
            GL.Viewport(ClientRectangle);
 
            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadIdentity();
            GL.Ortho(-1.0, 1.0, -1.0, 1.0, 0.0, 4.0);
        }
 
        #endregion
 
        #region OnUpdateFrame
 
        protected override void OnUpdateFrame(FrameEventArgs e)
        {
            if (Keyboard[OpenTK.Input.Key.Escape])
            {
                this.Exit();
            }
        }
 
        #endregion
 
        #region OnRenderFrame
 
        protected override void OnRenderFrame(FrameEventArgs e)
        {
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
 
            GL.MatrixMode(MatrixMode.Modelview);
            GL.LoadIdentity();
 
            GL.Enable(EnableCap.Texture2D);
            GL.BindTexture(TextureTarget.Texture2D, renderer.Texture);
            GL.Begin(PrimitiveType.Quads);
 
            GL.TexCoord2(0.0f, 1.0f); GL.Vertex2(-1f, -1f);
            GL.TexCoord2(1.0f, 1.0f); GL.Vertex2(1f, -1f);
            GL.TexCoord2(1.0f, 0.0f); GL.Vertex2(1f, 1f);
            GL.TexCoord2(0.0f, 0.0f); GL.Vertex2(-1f, 1f);
 
            GL.End();
 
            SwapBuffers();
        }
 
        #endregion
 
        #region Main
 
        public static void Main()
        {
            using (TextRendering example = new TextRendering())
            {
                example.Run(30.0);
            }
        }
 
        #endregion
    }
}

This is using GDI+ (System.Drawing) to render text, which gives good (but not perfect) results.

ravi.joshi53's picture

Thanks Fiddler...
I need to think over it little more. At this stage I can't work with QuickFont. Thanks for the suggestion. Can you please have a look here also. Still I am not able to resolve it. Thanks a lot for the great help.

ppc's picture

You must add all Hindi characters in fontBuilderConfiguration.charSet

var fontBuilderConfiguration = new QFontBuilderConfiguration();
fontBuilderConfiguration.charSet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890.:,;'\"(!?)+-*/=_{}[]@~#\\<>|^%$£&";
var font = new QFont("Fonts/Shangrila TextualB.ttf", 30, fontBuilderConfiguration);
font.Print("नमस्ते", QFontAlignment.Centre, new Vector2(RightX / 2, BottomY / 2));
ravi.joshi53's picture

Hi ppc,

Great thanks to you. I am adding all characters to it but QFont must be enough intelligent to discover all of the supported Hindi characters from the TTF file.