找出有限区域内字符的最大像素大小

Finding out the maximum pixel size of characters in a limited area

我正在尝试实现一项功能,以显示适合该区域的最大可能字符像素数。

示例 1: 想象一下尺寸为 100x20 像素的 LED 显示屏。需要显示的字符串是:volutpa commodo diam

手工完成所有操作后,我能够确定没有 splitting/dividing 单词的字符的最大可能像素大小为 8x8 像素。每个字符必须具有相同的像素大小。

如果字符像素大小为8x8 px,则上述字符串将成功显示在LED显示屏上。预期输出:8

示例 2: 想象一下尺寸为 100x20 像素的 LED 显示屏。需要显示的字符串是:dio volutpa diam

如果字符像素大小为9x9 px,则上述字符串将成功显示在LED显示屏上。预期输出:9

示例 3: 想象一下尺寸为 55x25 像素的 LED 显示屏。需要显示的字符串是:dio tuo diam

如果字符像素大小为8x8 px,则上述字符串将成功显示在LED显示屏上。预期输出:8

示例 4: 想象一下尺寸为 20x6 像素的 LED 显示屏。需要显示的一个字符串是:tuo volutpa

如果字符像素大小为2x2 px,则上述字符串将成功显示在LED显示屏上。预期输出:2

注意:字符串中的每个字符(包括space)必须具有相同的像素大小(例如 6x6 像素)以填充整个区域(LED 显示屏)并且字符串中的单词不能是 split/divided.

在此 example 1 中,您可以看到我正在努力实现的 "hand made" 图像。整个布局代表区域大小(100x20 像素),而黑框代表最大可能的字符像素大小(8x8 像素)。如果我使用(9x9 px 或更多)作为字符大小,文本将不适合,如果我使用(7x7 px 或更小),则会有太多空白 space.

在此 example 2 中,您可以看到我正在努力实现的 "hand made" 图像。整个布局代表区域大小(100x20 像素),而黑框代表最大可能的字符像素大小(9x9 像素)。如果我使用(10x10 像素或更多)作为字符大小,文本将不适合,如果我使用(8x8 像素或更小),则会有太多空白 space。如果该行即将结束,我们应该忽略单词末尾的 space。

预计

第 1 行:dio_volutpa

第 2 行:直径

实际:

第 1 行:dio_volutpa_

第 2 行:直径

在此 example 3 中,您可以看到我正在努力实现的 "hand made" 图像。整个布局代表区域大小(55x25 像素),而黑框代表最大可能的字符像素大小(8x8 像素)。如果我使用(9x9 像素或更多)作为字符大小,文本将不适合,如果我使用(7x7 像素或更小),则会有太多空白 space。那里的红框告诉你下一个词没有 space,因此它需要换行或者如果下面没有行 space 则减小它的像素大小。

在 C# 中实现它的最佳方法是什么?

static void Main(string[] args)
    {
        String sentence = "volutpa commodo diam";
        int width = 100; // 100 px
        int height = 20; // 20 px
        int pixelSize = height / 2; // Starting pixel size (10)
        int maxLines = height / pixelSize; // Max. available lines in the area
        int currentLine = 1; // Starting line

        string[] words = sentence.Split(' '); // Splitting words from the sentence. words[1] = volutpa, words[2] = commodo, words[3] = diam

        // Length of the words
        for (int i = 0; i < words.Length; i++)
        {
            Console.WriteLine("Word " + i + " length: " + words[i].Length * pixelSize);
        }

        Console.ReadLine();
    }

我现在已经做了这个,但不知道如何继续。我会很感激一些提示和想法。

这是我根据您更新后的问题得出的最终解决方案。
请阅读代码中的注释。

UPDATE
inside fixtoFitMatrix() 方法 space 将仅在 2 个单词之间被考虑。

更新 2
请阅读代码中的注释1、注释2和注释3。

namespace ConsoleApplication29
{
    class Program
    {
        private static void Main(string[] args)
        {

            Check("volutpa commodo diam", 100, 20);
            Check("dio volutpa diam", 100, 20);
            Check("dio tuo diam", 55, 25);
            Check("tuo volutpa", 20, 6);
            Check("volutpa", 23, 2);
            Check("diam tu diam op comodo", 10, 20);
            Check("volutpas di diam e commodo", 65, 65);
            Check("diamo volutpasoni onedo commodoso", 10, 40);
            Console.ReadLine();
        }

        private static void Check(string txt,int w,int h)
        {
            String sentence = txt;
            int width = w;
            int height = h;

            string[] words = sentence.Split(' '); 

            int maxLines;
            int pixelSize = GetPixelSize(words, height, width,out maxLines);

            Console.WriteLine(sentence);
            // length of the words
            for (int i = 0; i < words.Length; i++)
            {               
                Console.WriteLine("Word " + i + " length: " + words[i].Length * pixelSize );
            }

            Console.WriteLine("pixel size will be " + pixelSize + " lines: " + maxLines );
            Console.WriteLine("--------------------------------------------");
        }

        private static int GetPixelSize(string[] words, int height, int width,out int maxlines)
        {
            int lines = 1;
            int basepx = GetBasePixelSize(words, height, width,1,ref lines);

            // fix if not each line is fitted to width or the height of the matrix
            int finalpx = fixtoFitMatrix(basepx,words,width,height,lines);
            maxlines = lines;
            return finalpx;
        }

        private static int fixtoFitMatrix(int basepx, string[] words,int width,int height,int lines)
        {
            List<LedLine> ldlines = new List<LedLine>();
            int currentline = 0;
            // set text for each line
            LedLine l = new LedLine() { LineNumber = currentline, LineText = words[0]};
            ldlines.Add(l);
            for (int i = 1;i< words.Length;i++)
            {
                var currentstring = words[i];

                if (ldlines[currentline].Len * basepx + basepx + currentstring.Length * basepx <= width)
                {
                    // add to current line
                    ldlines[currentline].LineText = ldlines[currentline].LineText + currentstring;
                }
                else
                {
                    // it is a new line
                    currentline++;
                    LedLine newl = new LedLine() { LineNumber = currentline, LineText = currentstring };
                    ldlines.Add(newl);
                }
            }
            // px size is also a function of the width
            // for example:
            // on surface of 100X20 volutpa commodo diam will be 8px and dio volutpa diam will be 9px
            // that happens because commodo diam is the length of 12 and 12*9=108 and the width is only 100 so we will need to fix
            //fix will be chcked if the number of lines requeired is not the same in ldlines.count that means that we will need to "shrink" px by 1 every recursive call
            if (ldlines.Count > lines)
            {
                return fixtoFitMatrix(basepx - 1, words, width,height, lines);
            }
            // comment 1: we need to check the height also
            else if (lines * basepx > height)
            {
                return fixtoFitMatrix(basepx - 1, words, width, height, lines);
            }
            return basepx;
        }

        private static int GetBasePixelSize(string[] words, int height,int width,int linesneeded,ref int finalnumberoflines,int specialH = 0)
        {
            int h = (int)Math.Ceiling(((double)height / (double)linesneeded));
            if (specialH > 0)
                h = specialH;

            var lines = linesneeded;
            var accumulate = 0;

            for (int i = 0;i< words.Length;i++)
            {
                accumulate += words[i].Length * h;
                // add space if it is not the last word
                if (i < words.Length - 1)
                {
                    accumulate += h;
                }

                // more line needed - call recursivaly until we get the number of lines needed
                if (accumulate / lines > width)
                {
                    return GetBasePixelSize(words, height, width, linesneeded+1,ref finalnumberoflines,specialH);
                }
            }
            finalnumberoflines = lines;


            // comment 2 - special case - if there is a single word that is larger than all px (int h) we will decrease h, for example on matrix of 10*20 the word 'comodo'
            // can be displayed only when h=1 because if its 2 then 2* 6 = 12
            // we will strat all over again with the new size
            if (words.Any(x => x.Length * h > width))
            {
                string specialword = words.Where(x => x.Length * h > width).FirstOrDefault();
                // decrease h by the equation X = height/word.length, if the result is under 1 its not possible to do that
                h = (int)Math.Floor((double)width/ (double)specialword.Length);
                // comment 3 - if h = 0 exit the method and return 0 - it is not possible with the given conditions 
                // (for example matrix of 10X40 with the sentence 'diamo volutpasoni onedo commodoso' is not possible)
                if (h == 0)
                    return 0;

                finalnumberoflines = 1;
                return GetBasePixelSize(words, height, width, 1, ref finalnumberoflines,h);
            }

            return h;
        }
    }

    public class LedLine
    {
        public int LineNumber { get; set; }
        public string LineText { get; set; }
        public int Len
        {
            get
            {
                return LineText.Length;
            }
        }
    }
}

输出:

volutpa commodo diam
Word 0 length: 56
Word 1 length: 56
Word 2 length: 32
pixel size will be 8 lines: 2
--------------------------------------------
dio volutpa diam
Word 0 length: 27
Word 1 length: 63
Word 2 length: 36
pixel size will be 9 lines: 2
--------------------------------------------
dio tuo diam
Word 0 length: 24
Word 1 length: 24
Word 2 length: 32
pixel size will be 8 lines: 3
--------------------------------------------
tuo volutpa
Word 0 length: 6
Word 1 length: 14
pixel size will be 2 lines: 2
--------------------------------------------
volutpa
Word 0 length: 14
pixel size will be 2 lines: 1
--------------------------------------------
diam tu diam op comodo
Word 0 length: 4
Word 1 length: 2
Word 2 length: 4
Word 3 length: 2
Word 4 length: 6
pixel size will be 1 lines: 3
--------------------------------------------
volutpas di diam e commodo
Word 0 length: 64
Word 1 length: 16
Word 2 length: 32
Word 3 length: 8
Word 4 length: 56
pixel size will be 8 lines: 4
--------------------------------------------
diamo volutpasoni onedo commodoso
Word 0 length: 0
Word 1 length: 0
Word 2 length: 0
Word 3 length: 0
pixel size will be 0 lines: 7
--------------------------------------------