Click here to Skip to main content
15,896,063 members
Articles / Web Development / ASP.NET

Truncating a text string in ASP.NET to fit within a given pixel width

Rate me:
Please Sign up or sign in to vote.
4.75/5 (8 votes)
8 Sep 2010CPOL4 min read 43.1K   314   31  
How to truncate a text string in ASP.NET to make it fit within a given width specified in pixels.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;

namespace aspnet_TextTruncator
{
    public static class TextTruncator
    {
        // Private Properties
        //

        private static Dictionary<string, int[]> _fontWidthDic;
        private static Dictionary<string, int[]> FontWidthDic
        {
            get
            {
                if (_fontWidthDic == null)
                {
                    _fontWidthDic = new Dictionary<string, int[]>();
                }
                return _fontWidthDic;
            }
        }

        //
        // Public Methods
        //

        public static string TruncateText(string text, int textMaxWidth, string fontName, int fontSizeInPixels)
        {
            return TruncateText(text, textMaxWidth, fontName, fontSizeInPixels, false);
        }

        public static string TruncateText(string text, int textMaxWidth, string fontName, int fontSizeInPixels, bool isFontBold)
        {
            if (string.IsNullOrEmpty(text))
                return text;

            // Check
            //
            if (textMaxWidth < 1 ||
                string.IsNullOrEmpty(fontName) ||
                fontSizeInPixels < 1)
            {
                throw new ArgumentException();
            }

            int[] fontWidthArray = GetFontWidthArray(fontName, fontSizeInPixels, isFontBold);
            int ellipsisWidth = fontWidthArray['.'] * 3;
            int totalCharCount = text.Length;
            int textWidth = 0;
            int charIndex = 0;
            for (int i = 0; i < totalCharCount; i++)
            {
                textWidth += fontWidthArray[text[i]];
                if (textWidth > textMaxWidth)
                {
                    return text.Substring(0, charIndex) + "...";
                }
                else if (textWidth + ellipsisWidth <= textMaxWidth)
                {
                    charIndex = i;
                }
            }
            return text;
        }

        //
        // Private Methods
        //

        private static int[] GetFontWidthArray(string fontName, int fontSizeInPixels, bool isFontBold)
        {
            string fontEntryName = fontName.ToLower() + "_" + fontSizeInPixels.ToString() + "px" + (isFontBold ? "_bold" : "");
            int[] fontWidthArray;
            if (!FontWidthDic.TryGetValue(fontEntryName, out fontWidthArray))
            {
                fontWidthArray = CreateFontWidthArray(new Font(fontName, fontSizeInPixels, isFontBold ? FontStyle.Bold : FontStyle.Regular, GraphicsUnit.Pixel));
                FontWidthDic[fontEntryName] = fontWidthArray;
            }

            return fontWidthArray;
        }

        private static int[] CreateFontWidthArray(Font font)
        {
            int[] fontWidthArray = new int[256];
            for (int i = 32; i < 256; i++)
            {
                char c = (char)i;
                fontWidthArray[i] = IsIllegalCharacter(c, false) ? 0 : GetCharWidth(c, font);
            }
            return fontWidthArray;
        }

        private static int GetCharWidth(char c, Font font)
        {
            // Note1: For typography related reasons, TextRenderer.MeasureText() doesn't return the correct
            // width of the character in pixels, hence the need to use this hack (with the '<' & '>'
            // characters and the subtraction). Note that <' and '>' were chosen randomly, other characters 
            // can be used.
            //

            // Note2: As the TextRenderer class is intended to be used with Windows Forms Applications, it has a 
            // special use for the ampersand character (used for Mnemonics). Therefore, we need to check for the 
            // ampersand character and replace it with '&&' to escape it (TextRenderer.MeasureText() will treat 
            // it as one ampersand character)
            //

            return
                TextRenderer.MeasureText("<" + (c == '&' ? "&&" : c.ToString()) + ">", font).Width -
                TextRenderer.MeasureText("<>", font).Width;
        }

        private static bool ContainsIllegalCharacters(string text, bool excludeLineBreaks)
        {
            if (!string.IsNullOrEmpty(text))
            {
                foreach (char c in text)
                {
                    if (IsIllegalCharacter(c, excludeLineBreaks))
                        return true;
                }
            }

            return false;
        }

        private static bool IsIllegalCharacter(char c, bool excludeLineBreaks)
        {
            // See the Windows-1252 encoding (we use ISO-8859-1, but all browsers, or at least
            // IE, FF, Opera, Chrome and Safari, interpret ISO-8859-1 as Windows-1252).
            // For more information, see http://en.wikipedia.org/wiki/ISO/IEC_8859-1#ISO-8859-1_and_Windows-1252_confusion
            //

            return
                (c < 32 && (!excludeLineBreaks || c != '\n')) ||
                c > 255 ||
                c == 127 ||
                c == 129 ||
                c == 141 ||
                c == 143 ||
                c == 144 ||
                c == 157;
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Contractor
Egypt Egypt
My name is Waleed Eissa and I'm a software developer from Cairo, Egypt. I spent 7 years developing software for the banking industry, but has changed focus in recent years to Web development. I specialize in Microsoft technologies, esp. ASP.NET and C#, and am passionate about everything web. My main interests are user experience design (UX), performance tuning and scalability.

Website: http://www.waleedeissa.com
Blog: http://waldev.blogspot.com

Comments and Discussions