Юникод символы на принтере ZPL
У меня есть задача переделать систему печати этикеток с помощью сетевого Zebra GK420T. Мне удалось отправить задания печати ZPL на него совершенно нормально, но я не могу заставить его печатать символы Юникода, такие как буквы кириллицы. Я загрузил шрифт lucida sans unicode в принтер, используя драйверы Seagull Scientific, и для проверки использую следующий код ZPL:
^XA
^LH100,150
^CWT,E:TT0003M_.FNT
^CFT,30,30
^CI28
^FT0,0^FDTesting 1 2 3^FS
^FT0,50^FDДо свидания^FS
^FT0,100^B3^FDAAA001^FS
^XZ
Он напечатает "Тестирование 1 2 3" и штрих-код, но вместо символов кириллицы останется пустое место. Я делаю что-то неправильно, например, не экранируя символы или что-то в этом роде, или это проблема с принтером?
заранее спасибо
РЕДАКТИРОВАТЬ: я попытался использовать шрифт Zebra швейцарский Unicode, и теперь он печатает русские символы в виде вопросительных знаков. Я обновил код выше, чтобы отразить его.
12 ответов
Я только что обнаружил, что вам нужно экранировать символы выше ASCII, сначала поставив ^FH
перед любым ^FD
поля, которые могут содержать символ utf, и вам необходимо добавить префикс шестнадцатеричного кода utf-8 с подчеркиванием
_D0_94
будет печатать как Д. Мой окончательный код ZPL выглядит следующим образом:
^XA
^LH100,150
^CWT,E:TT0003M_.FNT
^CFT,30,30
^CI28
^FT0,0^FH^FDTesting 1 2 3^FS
^FT0,50^FH^FD_D0_94_D0_BE _D1_81_D0_B2_D0_B8_D0_B4_D0_B0_D0_BD_D0_B8_D1_8F^FS
^FT0,100^B3^FDAAA001^FS
^XZ
Мне просто нужно найти способ генерировать escape-последовательности, что должно быть намного проще!
У меня была такая же проблема, вы должны добавить ^FH
(Поле шестнадцатеричного индикатора) перед любым ^FD
(Поле данных), которая содержит специальные символы, в моем случае мне нужны испанские символы, поэтому мне пришлось использовать ^CI28
(Изменить международный шрифт / кодировку)
образец: распечатать Alvaro Jesús Pérez Peñaranda
нам нужно преобразовать эти специальные символы в шестнадцатеричный код UTF 8 и добавить _ перед каждым кодом, вот результат: Alvaro Jes_c3_bas P_c3_a9rez Pe_c3_b1aranda
^XA
^CI28
^FO60,75
^ASN,36,20^FH^FDAlvaro Jes_c3_bas P_c3_a9rez Pe_c3_b1aranda^FS
^XZ
Я использую принтер Zebra ZM400 и использую шрифт TT0003M_.
этот шрифт не печатает казахскую кириллицу.
если вы хотите напечатать кириллица + казахский кириллица + латинский алфавит, используйте ARI000.FNT (шрифт arial)
Я использую следующий метод преобразования символа в шестнадцатеричный код
надеюсь, это поможет
stringConverTextToHex(stringtext)
{
stringnewText="";
char[]charArray=text.ToCharArray();
foreach(charcincharArray)
{
switch(c)
{
case'й':
newText+="_D0_B9";
break;
case'Й':
newText+="_D0_99";
break;
case'ц':
newText+="_D1_86";
break;
case'Ц':
newText+="_D0_A6";
break;
case'у':
newText+="_D1_83";
break;
case'У':
newText+="_D0_A3";
break;
case'к':
newText+="_D0_BA";
break;
case'К':
newText+="_D0_9A";
break;
case'е':
newText+="_D0_B5";
break;
case'Е':
newText+="_D0_95";
break;
case'н':
newText+="_D0_BD";
break;
case'Н':
newText+="_D0_9D";
break;
case'г':
newText+="_D0_B3";
break;
case'Г':
newText+="_D0_93";
break;
case'ш':
newText+="_D1_88";
break;
case'Ш':
newText+="_D0_A8";
break;
case'щ':
newText+="_D1_89";
break;
case'Щ':
newText+="_D0_A9";
break;
case'з':
newText+="_D0_B7";
break;
case'З':
newText+="_D0_97";
break;
case'х':
newText+="_D1_85";
break;
case'Х':
newText+="_D0_A5";
break;
case'ъ':
newText+="_D1_8A";
break;
case'Ъ':
newText+="_D0_AA";
break;
case'ф':
newText+="_D1_84";
break;
case'Ф':
newText+="_D0_A4";
break;
case'ы':
newText+="_D1_8B";
break;
case'Ы':
newText+="_D0_AB";
break;
case'в':
newText+="_D0_B2";
break;
case'В':
newText+="_D0_92";
break;
case'а':
newText+="_D0_B0";
break;
case'А':
newText+="_D0_90";
break;
case'п':
newText+="_D0_BF";
break;
case'П':
newText+="_D0_9F";
break;
case'р':
newText+="_D1_80";
break;
case'Р':
newText+="_D0_A0";
break;
case'о':
newText+="_D0_BE";
break;
case'О':
newText+="_D0_9E";
break;
case'л':
newText+="_D0_BB";
break;
case'Л':
newText+="_D0_9B";
break;
case'д':
newText+="_D0_B4";
break;
case'Д':
newText+="_D0_94";
break;
case'ж':
newText+="_D0_B6";
break;
case'Ж':
newText+="_D0_96";
break;
case'э':
newText+="_D1_8D";
break;
case'Э':
newText+="_D0_AD";
break;
case'я':
newText+="_D1_8F";
break;
case'Я':
newText+="_D0_AF";
break;
case'ч':
newText+="_D1_87";
break;
case'Ч':
newText+="_D0_A7";
break;
case'с':
newText+="_D1_81";
break;
case'С':
newText+="_D0_A1";
break;
case'м':
newText+="_D0_BC";
break;
case'М':
newText+="_D0_9C";
break;
case'и':
newText+="_D0_B8";
break;
case'И':
newText+="_D0_98";
break;
case'т':
newText+="_D1_82";
break;
case'Т':
newText+="_D0_A2";
break;
case'ь':
newText+="_D1_8C";
break;
case'Ь':
newText+="_D0_AC";
break;
case'б':
newText+="_D0_B1";
break;
case'Б':
newText+="_D0_91";
break;
case'ю':
newText+="_D1_8E";
break;
case'Ю':
newText+="_D0_AE";
break;
case'ӑ':
newText+="_D3_91";
break;
case'Ӑ':
newText+="_D3_90";
break;
case'ӓ':
newText+="_D3_93";
break;
case'Ӓ':
newText+="_D3_92";
break;
case'ә':
newText+="_D3_99";
break;
case'Ә':
newText+="_D3_98";
break;
case'ӛ':
newText+="_D3_9B";
break;
case'Ӛ':
newText+="_D3_9A";
break;
case'ӕ':
newText+="_D3_95";
break;
case'Ӕ':
newText+="_D3_94";
break;
case'ґ':
newText+="_D2_91";
break;
case'Ґ':
newText+="_D2_90";
break;
case'ѓ':
newText+="_D1_93";
break;
case'Ѓ':
newText+="_D0_83";
break;
case'ғ':
newText+="_D2_93";
break;
case'Ғ':
newText+="_D2_92";
break;
case'ӷ':
newText+="_D3_B7";
break;
case'Ӷ':
newText+="_D3_B6";
break;
case'ҕ':
newText+="_D2_95";
break;
case'Ҕ':
newText+="_D2_94";
break;
case'ђ':
newText+="_D1_92";
break;
case'Ђ':
newText+="_D0_82";
break;
case'ѐ':
newText+="_D1_90";
break;
case'Ѐ':
newText+="_D0_80";
break;
case'ӗ':
newText+="_D3_97";
break;
case'Ӗ':
newText+="_D3_96";
break;
case'ҽ':
newText+="_D2_BD";
break;
case'Ҽ':
newText+="_D2_BC";
break;
case'ҿ':
newText+="_D2_BF";
break;
case'Ҿ':
newText+="_D2_BE";
break;
case'є':
newText+="_D1_94";
break;
case'Є':
newText+="_D0_84";
break;
case'ӂ':
newText+="_D3_82";
break;
case'Ӂ':
newText+="_D3_81";
break;
case'җ':
newText+="_D2_97";
break;
case'Җ':
newText+="_D2_96";
break;
case'ӝ':
newText+="_D3_9D";
break;
case'Ӝ':
newText+="_D3_9C";
break;
case'ҙ':
newText+="_D2_99";
break;
case'Ҙ':
newText+="_D2_98";
break;
case'ӟ':
newText+="_D3_9F";
break;
case'Ӟ':
newText+="_D3_9E";
break;
case'ӡ':
newText+="_D3_A1";
break;
case'Ӡ':
newText+="_D3_A0";
break;
case'ѕ':
newText+="_D1_95";
break;
case'Ѕ':
newText+="_D0_85";
break;
case'ѝ':
newText+="_D1_9D";
break;
case'Ѝ':
newText+="_D0_8D";
break;
case'ӥ':
newText+="_D3_A5";
break;
case'Ӥ':
newText+="_D3_A4";
break;
case'ӣ':
newText+="_D3_A3";
break;
case'Ӣ':
newText+="_D3_A2";
break;
case'і':
newText+="_D1_96";
break;
case'І':
newText+="_D0_86";
break;
case'ї':
newText+="_D1_97";
break;
case'Ї':
newText+="_D0_87";
break;
case'Ӏ':
newText+="_D3_80";
break;
case'ҋ':
newText+="_D2_8B";
break;
case'Ҋ':
newText+="_D2_8A";
break;
case'ј':
newText+="_D1_98";
break;
case'Ј':
newText+="_D0_88";
break;
case'қ':
newText+="_D2_9B";
break;
case'Қ':
newText+="_D2_9A";
break;
case'ҟ':
newText+="_D2_9F";
break;
case'Ҟ':
newText+="_D2_9E";
break;
case'ҡ':
newText+="_D2_A1";
break;
case'Ҡ':
newText+="_D2_A0";
break;
case'ӄ':
newText+="_D3_84";
break;
case'Ӄ':
newText+="_D3_83";
break;
case'ҝ':
newText+="_D2_9D";
break;
case'Ҝ':
newText+="_D2_9C";
break;
case'ӆ':
newText+="_D3_86";
break;
case'Ӆ':
newText+="_D3_85";
break;
case'љ':
newText+="_D1_99";
break;
case'Љ':
newText+="_D0_89";
break;
case'ӎ':
newText+="_D3_8E";
break;
case'Ӎ':
newText+="_D3_8D";
break;
case'ӊ':
newText+="_D3_8A";
break;
case'Ӊ':
newText+="_D3_89";
break;
case'ң':
newText+="_D2_A3";
break;
case'Ң':
newText+="_D2_A2";
break;
case'ӈ':
newText+="_D3_88";
break;
case'Ӈ':
newText+="_D3_87";
break;
case'ҥ':
newText+="_D2_A5";
break;
case'Ҥ':
newText+="_D2_A4";
break;
case'њ':
newText+="_D1_9A";
break;
case'Њ':
newText+="_D0_8A";
break;
case'ӧ':
newText+="_D3_A7";
break;
case'Ӧ':
newText+="_D3_A6";
break;
case'ө':
newText+="_D3_A9";
break;
case'Ө':
newText+="_D3_A8";
break;
case'ӫ':
newText+="_D3_AB";
break;
case'Ӫ':
newText+="_D3_AA";
break;
case'ҩ':
newText+="_D2_A9";
break;
case'Ҩ':
newText+="_D2_A8";
break;
case'ҧ':
newText+="_D2_A7";
break;
case'Ҧ':
newText+="_D2_A6";
break;
case'ҏ':
newText+="_D2_8F";
break;
case'Ҏ':
newText+="_D2_8E";
break;
case'ҫ':
newText+="_D2_AB";
break;
case'Ҫ':
newText+="_D2_AA";
break;
case'ҭ':
newText+="_D2_AD";
break;
case'Ҭ':
newText+="_D2_AC";
break;
case'ћ':
newText+="_D1_9B";
break;
case'Ћ':
newText+="_D0_8B";
break;
case'ќ':
newText+="_D1_9C";
break;
case'Ќ':
newText+="_D0_8C";
break;
case'ў':
newText+="_D1_9E";
break;
case'Ў':
newText+="_D0_8E";
break;
case'ӳ':
newText+="_D3_B3";
break;
case'Ӳ':
newText+="_D3_B2";
break;
case'ӱ':
newText+="_D3_B1";
break;
case'Ӱ':
newText+="_D3_B0";
break;
case'ӯ':
newText+="_D3_AF";
break;
case'Ӯ':
newText+="_D3_AE";
break;
case'ү':
newText+="_D2_AF";
break;
case'Ү':
newText+="_D2_AE";
break;
case'ұ':
newText+="_D2_B1";
break;
case'Ұ':
newText+="_D2_B0";
break;
case'ҳ':
newText+="_D2_B3";
break;
case'Ҳ':
newText+="_D2_B2";
break;
case'һ':
newText+="_D2_BB";
break;
case'Һ':
newText+="_D2_BA";
break;
case'ҵ':
newText+="_D2_B5";
break;
case'Ҵ':
newText+="_D2_B4";
break;
case'ӵ':
newText+="_D3_B5";
break;
case'Ӵ':
newText+="_D3_B4";
break;
case'ҷ':
newText+="_D2_B7";
break;
case'Ҷ':
newText+="_D2_B6";
break;
case'ӌ':
newText+="_D3_8C";
break;
case'Ӌ':
newText+="_D3_8B";
break;
case'ҹ':
newText+="_D2_B9";
break;
case'Ҹ':
newText+="_D2_B8";
break;
case'џ':
newText+="_D1_9F";
break;
case'Џ':
newText+="_D0_8F";
break;
case'ӹ':
newText+="_D3_B9";
break;
case'Ӹ':
newText+="_D3_B8";
break;
case'ҍ':
newText+="_D2_8D";
break;
case'Ҍ':
newText+="_D2_8C";
break;
case'ӭ':
newText+="_D3_AD";
break;
case'Ӭ':
newText+="_D3_AC";
break;
case'A':
newText+="_41";
break;
case'a':
newText+="_61";
break;
case'B':
newText+="_42";
break;
case'b':
newText+="_62";
break;
case'C':
newText+="_43";
break;
case'c':
newText+="_63";
break;
case'D':
newText+="_44";
break;
case'd':
newText+="_64";
break;
case'E':
newText+="_45";
break;
case'e':
newText+="_65";
break;
case'F':
newText+="_46";
break;
case'f':
newText+="_66";
break;
case'G':
newText+="_47";
break;
case'g':
newText+="_67";
break;
case'H':
newText+="_48";
break;
case'h':
newText+="_68";
break;
case'I':
newText+="_49";
break;
case'i':
newText+="_69";
break;
case'J':
newText+="_4A";
break;
case'j':
newText+="_6A";
break;
case'K':
newText+="_4B";
break;
case'k':
newText+="_6B";
break;
case'L':
newText+="_4C";
break;
case'l':
newText+="_6C";
break;
case'M':
newText+="_4D";
break;
case'm':
newText+="_6D";
break;
case'N':
newText+="_4E";
break;
case'n':
newText+="_6E";
break;
case'O':
newText+="_4F";
break;
case'o':
newText+="_6F";
break;
case'P':
newText+="_50";
break;
case'p':
newText+="_70";
break;
case'R':
newText+="_52";
break;
case'r':
newText+="_72";
break;
case'S':
newText+="_53";
break;
case's':
newText+="_73";
break;
case'T':
newText+="_54";
break;
case't':
newText+="_74";
break;
case'U':
newText+="_55";
break;
case'u':
newText+="_75";
break;
case'V':
newText+="_56";
break;
case'v':
newText+="_76";
break;
case'Y':
newText+="_59";
break;
case'y':
newText+="_79";
break;
case'Z':
newText+="_5A";
break;
case'z':
newText+="_7A";
break;
case'':
newText+="";
break;
default:
newText+=c;
break;
}
}
returnnewText;
}
это пример кода
^SP ^XA ^PON^FS ^FPH^FO102,63,0 ^A@N,60,60,E:ARIOOO_.FNT ^FH^FD_42_75_72_61_6B _D0_A8_D3_99 ^FS ^XZ
Русский и многие другие символы могут быть напечатаны с использованием бесплатного шрифта Zebra swiss unicode. Он уже включен в большинство принтеров как TT0003M_ и поддерживает римский, кириллицу, восточноевропейский, турецкий, арабский, иврит.
Для печати на таких языках, как японский или китайский, которые содержат тысячи символов, вам необходим принтер с не менее 23 МБ свободной памяти и файл шрифтов TrueType, который вы можете загрузить (они называют это загрузкой).
Этот файл можно купить у Zebra (и говорят, что вам нужно 64 МБ), но я также был очень успешным с очень старым файлом TTF, найденным в моей системе Windows 7 в папке Fonts: ARIALUNI.TTF 1.01 (23.275.812 байт), Arial Unicode MS. Он был установлен посредством установки MS Office и, возможно, не лицензирован для этого использования.
Скорее всего, вы также можете использовать другие файлы TTF, но я пробовал только этот.
В то время как ZPL-печать на этом принтере Zebra работала без какого-либо оригинального драйвера (только общий текст), для установки шрифта драйвер был необходим. Если кто-нибудь знает, как отправить файл TTF на принтер без драйвера, оставьте комментарий.
Я установил служебные программы установки Zebra, которые включают в себя загрузчик шрифтов. Нажмите новый, затем добавьте шрифт (должен быть установлен в системе) и проигнорируйте сообщение о том, что включены 226 символов. Также игнорируйте, что если вы настроите тестовую строку с символами Unicode, она не будет отображаться правильно. Вас спрашивают, хотите ли вы скачать сейчас, и это занимает много времени.
Вы можете проверить установку, перечислив содержимое каталога (веб-страница администрирования или распечатка). Там шрифт выглядит как ARI000.TTF в моем случае.
Для печати необходимо отправить текст ZPL в формате UTF-8. Вы можете скопировать этот пример в блокнот и выбрать UTF-8 в диалоговом окне сохранения:
^XA
^LH100,150
^CWT,E:ARI000.FNT
^CFT,30,30
^CI28
^FT0,0^FH^FDyour unicode characters here^FS
^XZ
Затем для тестирования вы можете использовать простую команду копирования, чтобы отправить ее на принтер:
В случае USB вы должны сначала поделиться этим принтером в сети.
затем net use lpt1: \\localhost\sharename
а также copy file.txt lpt1
Мы протестировали многие распространенные японские и китайские символы, и они очень хорошо работают с высоким качеством на принтере ZT230 со вспышкой 32 МБ.
Если вы хотите напечатать русские буквы кириллицы, используя :TT0003M_.FNT
, вы должны сохранить команды в файл с кодировкой UTF-8!
^XA
^LH100,150
^CWT,E:TT0003M_.FNT
^CFT,30,30
^CI28
^FT0,0^FH^FDTesting 1 2 3^FS
^FT0,30^FH^FDДо свидания^FS
^FT0,100^B3^FDAAA001^FS
^XZ
Затем с помощью командной строки вы можете отправить его на порт принтера. Пример: скопируйте C:\Users\xxx\Desktop\test_ru.txt com1
Я надеюсь, что это поможет...
Вы можете заменить символ, который больше одного байта, на шестнадцатеричную строку UTF-8 с подчеркиванием, например, "ћ => _D1_9B". Пример кода ниже;
var zpl_code = "^XA" +
"^LH100,150" +
"^CWT,E:TT0003M_.FNT" +
"^CFT,30,30" +
"^CI28" +
"^FT0,0^FDTesting 1 2 3^FS" +
"^FT0,50^FDДо свидания^FS" +
"^FT0,100^B3^FDAAA001^FS" +
"^XZ";
var unicodeCharacterList = zpl_code.Distinct()
.Select(c => c.ToString())
.Select(c => new { key = c, UTF8Bytes = Encoding.UTF8.GetBytes(c) })
.Where(c => c.UTF8Bytes.Length > 1);
foreach (var character in unicodeCharacterList)
{
var characterHexCode = string.Join("", character.UTF8Bytes.Select(c => "_" + BitConverter.ToString(new byte[] { c }).ToLower()).ToArray());
zpl_code = zpl_code.Replace(character.key, characterHexCode);
}
Этот код устанавливает переменную zpl_code для вывода ниже
^XA
^LH100,150
^CWT,E:TT0003M_.FNT
^CFT,30,30
^CI28
^FT0,0^FDTesting 1 2 3^FS
^FT0,50^FD_d0_94_d0_be _d1_81_d0_b2_d0_b8_d0_b4_d0_b0_d0_bd_d0_b8_d1_8f^FS
^FT0,100^B3^FDAAA001^FS
^XZ
В последних версиях прошивки (начиная с версии v x.16.x) вы можете использовать ^CI33 для кодированной страницы кодированного текста Windows-1251 (и других кодовых страниц) без ^FH. См руководство
Ваше "До свидания" было, вероятно, в cp1251. Закодируйте его в фактическом UTF-8 и попробуйте снова. Пробелы являются хорошим индикатором того, что у вас есть проблема с кодировкой.
Проверено с прошивкой v56.17.112 и ^A@N,,,E:TT0003M_.FNT
Я взял ответ Дисномина и преобразовал что-то в Javascript. Его ответ был на C #
Чтобы запустить его, просто возьмите свой строковый объект и вызовите
variable.zplHexEncode()
где переменная - это ваша строка. По умолчанию это символ _ для escape-символа. Вам все равно придется ставить префиксы
^FD
поля с
^FH
команда. Лично я использую что-то вроде модуля doT, чтобы создать свой ZPL и заполнить поля значениями с экранированными символами. YMMV.
Как уже отмечали другие, обязательно используйте ^CI28
(Изменить международный шрифт / кодировку) и ^FH
(Поле Hexadecimal Indicator) и экранируйте любые не-ascii utf8 символы с подчеркиванием и их шестнадцатеричным значением.
Однако другой ответ включал код для форматирования строки utf8 с использованием гигантского блока switch-case. Вот метод, который я использую для кодирования в utf8, он должен иметь возможность форматировать любой допустимый массив байтов utf8.
Чтобы получить байтовый массив из строки, используйте Encoding.UTF8.GetBytes(content)
,
// From the wikipedia page on utf8 encoding - https://en.wikipedia.org/wiki/UTF-8
private const int _Last1ByteCodePointByte1 = 0x7F;
private const int _First2ByteCodePointByte1 = 0xC0;
private const int _Last2ByteCodePointByte1 = 0xDF;
private const int _Last3ByteCodePointByte1 = 0xEF;
private const int _Last4ByteCodePointByte1 = 0xF7;
private const int _FirstMultiByteCodePointByte2 = 0x80;
private const int _LastMultiByteCodePointByte2 = 0xBF;
private const char _ZplMultiByteEscapeCharacter = '_';
/// <summary>
/// Encodes a sequence of utf8 bytes for printing with the ZPL language, this means escaping multi-byte characters with an underscore ('_') followed by the hex code
/// for each byte in the multi-byte characters.
/// </summary>
/// <param name="utf8Bytes">The bytes that make up the entire string, including bytes that need to be encoded and bytes that can be printed as-is.</param>
/// <returns>A string for printing with the ZPL language. Ie all multi-byte characters escaped with an underscore ('_') followed by the hex code for each byte.</returns>
/// <throws><see cref="ArgumentException"/> when <paramref name="utf8Bytes"/> isn't a valid utf8 encoding of a string.</throws>
/// <remarks>
/// Plan is to figure out how many bytes this character (code point) takes up, and if it's a 1 byte character, just use the character, but otherwise since it's a multi-byte
/// character then use an underscore ('_') followed by the hex encoded byte and each other byte in this code point will also be encoded. If we start the loop but have bytes
/// remaining in the current code point we know to hex encode this byte and continue.
/// </remarks>
private static string EncodeUtf8BytesForZPLIIPrinting(byte[] utf8Bytes)
{
var contentWithMultiByteCharsEscaped = new List<char>();
var multiByteCodePoint = new List<char>();
var remainingBytesInCurrentCodePoint = 0;
string errorMessage = null;
foreach (byte utf8Byte in utf8Bytes)
{
if (remainingBytesInCurrentCodePoint > 0)
{
if (utf8Byte < _FirstMultiByteCodePointByte2 || utf8Byte > _LastMultiByteCodePointByte2)
{
errorMessage = $"The byte {utf8Byte.ToString("X2")} is not a valid as the second or later byte of a multi-byte utf8 character (codepoint).";
break;
}
multiByteCodePoint.Add(_ZplMultiByteEscapeCharacter);
AddHexValuesToListFromByte(multiByteCodePoint, utf8Byte);
remainingBytesInCurrentCodePoint--;
continue; // continue since we've dealt with this byte and don't want to flow on.
}
if (multiByteCodePoint.Any())
{
foreach (char c in multiByteCodePoint) contentWithMultiByteCharsEscaped.Add(c);
multiByteCodePoint.Clear();
// flow on to loop to see what to do with the current byte.
}
if (utf8Byte <= _Last1ByteCodePointByte1)
{
// 1 byte - no escaping
contentWithMultiByteCharsEscaped.Add((char)utf8Byte);
}
else if (utf8Byte >= _First2ByteCodePointByte1 && utf8Byte <= _Last2ByteCodePointByte1)
{
// 2 bytes
multiByteCodePoint.Add(_ZplMultiByteEscapeCharacter);
AddHexValuesToListFromByte(multiByteCodePoint, utf8Byte);
remainingBytesInCurrentCodePoint = 1;
}
else if (utf8Byte <= _Last3ByteCodePointByte1)
{
// 3 bytes
multiByteCodePoint.Add(_ZplMultiByteEscapeCharacter);
AddHexValuesToListFromByte(multiByteCodePoint, utf8Byte);
remainingBytesInCurrentCodePoint = 2;
}
else if (utf8Byte <= _Last4ByteCodePointByte1)
{
// 4 bytes
multiByteCodePoint.Add(_ZplMultiByteEscapeCharacter);
AddHexValuesToListFromByte(multiByteCodePoint, utf8Byte);
remainingBytesInCurrentCodePoint = 3;
}
else
{
errorMessage = $"The byte {utf8Byte.ToString("X2")} is not a valid as the first byte of a utf8 character.";
break;
}
}
// if the last char was multiByte add it now.
if (multiByteCodePoint.Any())
{
foreach (var c in multiByteCodePoint) contentWithMultiByteCharsEscaped.Add(c);
multiByteCodePoint.Clear();
}
if (remainingBytesInCurrentCodePoint != 0 && errorMessage == null)
{
errorMessage = $"The last character didn't have enough bytes to finish the codepoint. It was a multi-byte character that needed {remainingBytesInCurrentCodePoint}" +
$" more byte{(remainingBytesInCurrentCodePoint == 1 ? null : "s")}.";
}
if (errorMessage != null)
{
throw new ArgumentException($"The byte array was not a valid byte array for a utf8 string: {errorMessage}", nameof(utf8Bytes));
}
return new string(contentWithMultiByteCharsEscaped.ToArray());
void AddHexValuesToListFromByte(List<char> list, byte @byte)
{
// A byte is <= 255 so will always fit in a 2-digit hex number, hence the 2 in "X2". The X means hex.
foreach (char c in @byte.ToString("X2"))
{
list.Add(c);
}
}
}
Когда мы используем CP1251 как системную кодировку, это вызывает пустые символы в метках, если мы пишем кириллицу в коде ZPL. Пользователи CP1251 могут сначала принудительно преобразовать "До свидания" в UTF-8 и получить:
Птица
Замените До свидания в коде ZPL на эти странные символы и получите на этикетке "До свидания". Он работает с tt0003m_.fnt с ^CI28, но, IMHO, лучше использовать hex-коды.
Для кириллицы достаточно заменить ^CI28 на ^ CI33.
^XA
^LH100,150
^CWT,E:TT0003M_.FNT
^CFT,30,30
^CI33
^FT0,0^FDTesting 1 2 3^FS
^FT0,50^FDДо свидания^FS
^FT0,100^B3^FDAAA001^FS
^XZ