Do jednego ze swoich projektów wymyśliłem, że dorobię obsługę Unicode, a tak naprawdę obsługę dwóch pierwszych zestawów zwanymi "Plane".

Dla plane 0 wszystko działa prawidłowo, natomiast z plane 1 jest problem. Pozostałe "plane" od 2 do 16 mnie nie interesują.

Napisałem prosty program w .NET Framework, który wypisuje na konsoli i na bitmapie kilka znaków z plane 0 i plane 1. Jak widać, na konsoli wypisuje prawidłowo za wyjątkiem tego, że zwykły char obsługuje tylko plane 0 (a że niektóre znaki zajmują większy obszar niż jedna komórka to już inny temat i nie jest to problem), a na bitmapie to już nie tylko nie wypisuje znaków z plane 1 (jak widać, próbowałem kilku sposobów znalezionych w Google), ale również coś psuje w obiekcie typu Graphics przy próbie wypisania dowolnego znaku z plane 1, bo jak się przed każdym znakiem nie utworzy nowego obiektu (linie zaznaczone wykrzyknikami), to na bitmapie nie ma ostatniego znaku.

Jak widać, próbowałem kilka różnych fontów i z każdym jest ten sam problem. Natomiast w aplikacji https://andrzejlisek.github.io/Unicode/unicode.htm dla wszystkich wykorzystanych fontów pokazują się wszystkie znaki.

Ja nie oczekuję kolorowych znaków, tylko chociażby niektóre oryginalne znaki lub jakaś kratka lub kropka będąca zamiennikiem znaku, którego ma w danym foncie.

Co z tym zrobić i jak zmusić program do malowania wszystkich znaków Unicode na bitmapie? Jak to jest, że dla tej samej czcionki, w C# jest problem, a w HTML wszystko działa prawidłowo?

CharTest.png

Konsola.png

Poza tym, dlaczego znak z "plane 1" ma długość 2 znaków, pomimo, że to jest jeden znak? Liczba znaków w napisie, a liczba bajtów to dwie różne sprawy.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TestThr
{
    class MainClass
    {
        public static void Main(string[] args)
        {
            Console.Clear();

            List<string> FontNames = new List<string>();
            FontNames.Add("Noto Mono");
            FontNames.Add("Ubuntu Mono");
            FontNames.Add("Consolas");
            FontNames.Add("Tlwg Mono");
            FontNames.Add("Monospace");
            FontNames.Add("Courier");
            FontNames.Add("Arial");
            FontNames.Add("Times New Roman");
            FontNames.Add("Liberation Mono");

            List<int> Chars = new List<int>();
            Chars.Add(0x37);
            Chars.Add(0x41);

            Chars.Add(0x25CF);
            Chars.Add(0x2592);
            Chars.Add(0xC647);
            Chars.Add(0xFFFD);

            Chars.Add(0x010097);
            Chars.Add(0x010133);
            Chars.Add(0x010718);
            Chars.Add(0x01F6D1);
            Chars.Add(0x01F652);

            Chars.Add(0x35);

            int BmpStep = 60;

            Bitmap BmpX = new Bitmap(FontNames.Count * 4 * BmpStep + BmpStep, Chars.Count * BmpStep + BmpStep, PixelFormat.Format24bppRgb);
            Graphics BmpG = Graphics.FromImage(BmpX);

            string Temp1 = "";
            string Temp2 = "";
            for (int i = 0; i < Chars.Count; i++)
            {
                Console.Write(Chars[i].ToString("X"));

                Console.Write(" [");
                try
                {
                    Console.Write((char)Chars[i]);
                }
                catch
                {
                    Console.Write("ERROR");
                }
                Console.Write("]  [");
                Temp1 = Encoding.UTF32.GetString(new byte[] { (byte)((Chars[i]) & 255), (byte)((Chars[i] >> 8) & 255), (byte)((Chars[i] >> 16) & 255), 0x00 });
                Console.Write(Temp1);
                Console.Write("]" + Temp1.Length);

                Console.Write("  [");
                Temp2 = Char.ConvertFromUtf32(Chars[i]);
                Console.Write(Temp2);
                Console.Write("]" + Temp2.Length + "    ");

                for (int ii = 0; ii < FontNames.Count; ii++)
                {
                    Font Font_ = new Font(FontNames[ii], 20);
                    int BmpPos = BmpStep * 4 * ii;

                    // !!!!!!!!!!!!!!!!
                    BmpG = Graphics.FromImage(BmpX);


                    BmpG.DrawString(Temp1, Font_, Brushes.White, BmpPos + BmpStep * 1, BmpStep * i);

                    // !!!!!!!!!!!!!!!!
                    BmpG = Graphics.FromImage(BmpX);


                    BmpG.DrawString(Temp2, Font_, Brushes.White, BmpPos + BmpStep * 2, BmpStep * i);

                    // !!!!!!!!!!!!!!!!
                    BmpG = Graphics.FromImage(BmpX);


                    TextRenderer.DrawText(BmpG, Temp1, Font_, new Point(BmpPos + BmpStep * 3, BmpStep * i), Color.White);

                    // !!!!!!!!!!!!!!!!
                    BmpG = Graphics.FromImage(BmpX);


                    TextRenderer.DrawText(BmpG, Temp2, Font_, new Point(BmpPos + BmpStep * 4, BmpStep * i), Color.White);
                }




                if (Temp1 == Temp2)
                {
                    Console.Write("OK  ");
                    for (int ii = 0; ii < Temp1.Length; ii++)
                    {
                        Console.Write("[");
                        Console.Write(((int)Temp1[ii]).ToString("X"));
                        Console.Write("]");
                    }
                }

                Console.WriteLine();
            }
            BmpX.Save("CharTest.png", ImageFormat.Png);

            Console.ReadLine();
        }

    }


}