Шрифт code 128 не читается сканером

Обновлено: 17.05.2024

Однажды в процессе производственной деятельности у меня появилась необходимость генерации штрихкода по стандарту code128. Появилась в виду того, что имевшаяся в эксплуатации функция (хранимая процедура в базе Oracle) генерировала клёвый, полосатый штрихкод, который читался не во всех случаях. Разработчики в своё время оттестировали эту процедуру весьма некачественно, но перерабатывать уже не собирались т.к. проект был давно сдан, а потребности в считывании так и не появились.

Первая мысль — поиск готовых библиотек. Навскидку определили критерии — с pl/sql не связываемся, пусть это будет внешний сервис: возможно кусок на javascript для генерации прямо на страничке, либо обращение за картинкой к ближайшему серверу где имеется php. Беглый поиск в интернете показал что тема истоптана весьма плотно. Есть как наколенные поделки уровня лабораторки по программированию, так и мощные библиотеки для всех вариантов кодирования вплоть до qr-кодов. Варианты с JavaScript пришлось отбросить т.к. они во-первых практически все «обфусканы» (даже непонятно, то ли для сокращения объема, то ли стыдно исходники показать), во-вторых генерируют строку для отображения определенным шрифтом, наличие которого не всегда можно обеспечить на клиентском месте и требует дополнительных обработок для экранирования спецсимволов. Внимательное изучение библиотек и кусков кода на php тоже произвело тягостное впечатление — на первый взгляд всё вроде бы правильно: и классы написаны на все случаи жизни, комментарии в наличии, украшательства типа выбора цвета и рамочек, примеры подготовлены. Начнёшь вникать — хотят либо php самой распоследней версии (на боевых серверах не всегда это получается добыть), либо внутренняя логика не различима совсем, либо штрихкод на выходе получается длиннее ожидаемого. Вот последнее не дало покоя и подтолкнуло к собственной реализации.

Теория гласит, что code128 позволяет закодировать (сюрпрайз!) 128 символов, при этом нам доступно 3 алфавита, между которыми можно переключаться по ходу дела. Наибольший практический интерес представляют алфавит «B» для буквенно-цифровых символов и алфавит «С» который используется для кодирования цифр, но с некоторой оптимизацией — одним штриховым символом можно закодировать 2 исходных символа и получить более короткий штрихкод. Вот эта оптимизация пока не даётся ни одному php-разработчику — максимум что я видел это попытка в начале кодирования определить состав строки и при наличии только цифр переключаться на алфавит «С». В остальных библиотеках это банальная подстановка символов штрихкода по таблице.

Для начала осмотрим приборы и материалы — в начале строки можем задать алфавит для кодирования, перед каждым символом можем переключить алфавит. Также мы на входе ограничены по длине строки - это очень хорошо и важно для нас. Имеем цель — получить штрихкод. Точнее, самый короткий штрихкод.

Разберём пару примеров. Допустим у нас есть последовательность «ABC12DE» попробуем её закодировать разными методами, на примере изображены слева только алфавит B, справа - совместно B и С:


Наша попытка оптимизировать длину кода используя более короткий алфавит потерпела фиаско - мы получили дополнительные символы на переключениях алфавита и в результате штрихкод стал на 1 символ длиннее. Если хорошо подумать, то переключение на алфавит С выгодно при наличии 6 и более цифр подряд. Но есть ведь и граничные случаи — цифры в конце последовательности, в начале, а есть еще вариант с нечетным количеством цифр и тогда надо пристально смотреть когда переключаться на алфавит С — с первой цифры или со второй? В общем вариантов достаточно много, что в итоге у большинства отбивает желание оптимизировать длину кода, а делать всё одним алфавитом.

И вот тут нас озаряет, что работа с рекурсивной функцией избавит нас от рассмотрения всех этих условий и задача станет невероятно простой — функция будет вызывать сама себя с тремя вариантами кодирования текущего символа и возвращать наиболее короткий (итоговый) вариант. Причём длина варианта включает в себя и символ переключения между алфавитами. Причин отказа от захода в ветку алгоритма совсем немного — либо кончился входной поток, либо мы не можем закодировать символ(ы) данным алфавитом (например нет 2-х цифр для алфавита «С»). Так, как входной поток имеет ограничение по длине, то дерево не будет расти бесконечно! По тексту будем реализовывать только алфавит «B» и «C» - проще для понимания и потом объясню остальное :)

Сразу набросаем простейший класс который содержит сам текст, такие-же классы для рассмотрения вариантов по алфавиту B и С, длину последовательности. Делаем ему минимальный конструктор — на входе строка для кодирования, режим кодирования, ссылки на потомков. В начале конструктора добавляем проверки, чтобы не прорабатывать данную ветку дерева:

и сразу ловим конкретный косяк — куча "пустых" объектов. И это не смотря на то что мы явно отказались создаваться и вроде как железно возвращаем NULL! В общем сразу надо понять, что в php объект создаётся в любом случае. Полагаю что также и в остальных объектно-ориентированных языках. И все эти условия надо проверять перед созданием объекта. Следовательно правильный конструктор будет выглядеть примерно так:

Не считая того, что мы избавились от пустых объектов, код получился даже немного короче чем прототип. Дальше начнём немного оптимизировать - добавим небольшой трюк: вместо того чтобы делать кучу проверок является ли последовательность символами, цифрами, их количество и т.д. просто смотрим в таблице наличие такого индекса в алфавите. Я уже писал что таблицу можно добыть в любой библиотеке реализующей кодирование code128? В общем напоминаю ещё раз, и готовый кусочек кода, который мне уже нравится, приведен ниже:

$symCode - это алфавиты, которые я загнал в файл tables.php и включаю его через require в начале исходника. Формат простой - символ алфавита => код штрихкода.

Дерево строится, но результата пока не видно. Следующим этапом необходимо определить самую короткую ветку: Первый вариант - заводим в классе счётчик и увеличиваем его при каждом переходе на ветку. Как только достигнем дна (конца исходного текста), на концах дерева будет указан размер финального кода. Второй вариант — конечные веточки ставят себе размер 1, а дальше родитель решает какой из потомков имеет код короче и ставит себе размер на 1 или 2 больше. Почему на 2? Надо учитывать накладные расходы на переключение алфавита. Кстати и в первом варианте это тоже надо учитывать. В итоге в корне дерева будет длина самой короткой последовательности. Чем хорош первый вариант? Получение итоговой последовательности практически мгновенное — возвращаешься «по папе» к корню дерева. Ну и недостаток — чтобы найти самую короткую ветку надо сделать полный обход дерева. Второй вариант — длина самой короткой последовательности известна и находится в одном месте, но получение последовательности чуток посложнее, хотя и не требует полного обхода. Попробуем проработать первый вариант — доделать надо совсем немного, просто родитель после создания потомков должен выбрать самого короткого потомка и сохранить ссылку на конечный элемент ветки. Выразился невероятно коряво, но Вы посмотрите код - там ещё страшнее :)

Итак, худо-бедно мы нашли самый короткий путь (штрихкод). Надо его вывести для начала на экран. Делаем в два этапа: сначала от потомка возвращаемся к родителю. Итоговые символы, включая переключение между алфавитами, пушим (push) в массив. Да, в PHP есть такая функция, и она позволяет нам сделать из массива довольно удобный стэк.

Когда потребуется вывести строку — используем array_pop. Таким образом, мы по прежнему используем данный массив как стэк и легко выводим информацию в обратном порядке. Попутно готовим дополнительную обвязку для нашего штрихкода — старт/стоп/контрольная сумма.

Финал совсем близко - я уже устал писать, Вы устали читать. Предлагаю пробежаться весьма бегло. Само рисование сделано в виде SVG. Для данной задачи весьма удобно — нет необходимости кодировать размеры изображения, они будут задаваться тэгами на страничке. Кроме того, рендеринг и масштабирование осуществляется конечным устройством, что обеспечит необходимое качество в dpi соответствующее устройству вывода.

Появился глобальный массив $barPattern. Искать в файле tables.php рядом с $symCode. Кусочек приведу. Там всё просто - для заданного кода выходного символа чередуются толщины черных и белых штрихов:

Как этим пользоваться? В файл с классом в конец добавим пару строк:

попробовать можно сразу, вставив в html-страничку примерно вот такой тэг:

Ну и напоследок. Реализованы только алфавиты «B» и «С». Уложился примерно в 100 строчек, не считая таблиц перекодировки. Реализовать алфавит «А» можно аналогичным способом просто дописав конструктор и таблицу с алфавитами, только желательно учесть один хитрый код, позволяющий кратковременно переключиться на один символ другого алфавита. Самому дописать у меня нет ни желания, ни времени, ни прочих мотиваций. (Полу)готовый проект вероятно пополнит кладбище штрихкодировщиков на гитхабе - если у кого есть желание продолжить проект - пишите, не стесняйтесь.

Ответы 16


в ШК GS1-128 (EAN-128) при разделении идентификаторов применения переменной длины (37), (10), (21) и тд кодируется символ FNC1. В режиме эмуляции клавиатуры этот символ не передается. Уважаемая техподдержка, как можно подключить ТСД в RDP в режиме эмуляции COM-порта? На Windows это можно было сделать, но как это реализовать на Android?


Для начала, а присутствую ли они в самом коде? Можно пример вашего баркода?


Символ ¿ не входит в набор Latin1 который используется при формировании баркода. Однако, 6300 отлично распознает это место и подставляет вместо него пробел.






Подскажите, пожалуйста, настройки сканера, при которых пробел подставляется. Интересует вставка пробела в текстовое поле.

В приложении "Scanner" я действительно вижу пробел на экране. Но в текстовое поле в режиме эмуляции клавиатуры (keyboard output mode) данные вставляются без пробела. На фото пример сканирования в текстовое поле почтового клиента на ТСД. Вы можете самостоятельно проверить



В режиме "Keyboard output mode" пробел и в приложении "Scanner" не виден на экране


Да, это "непечатный" символ, через клавиатурный ввод он не может быть передан.


Подскажите каким образом работать со штрих-кодом GS1-128 в 1C по RDP?


К сожалению, единственный вариант тут это написание своего RDP клиента, который будет реализовывать Port Retirection beam и "транслировать" в него события от сканера/RSCore


1. Правильно ли я понимаю, что речь идет не о режиме работы в RDP, а о передаче соответствующих символов, которые кодируются в GS1 согласно спецификации штрих-кода в произвольное приложение?
2. Правильно ли я понимаю, со стандартными приложениями, идущими в комплекте поставки сканеры Urovo v5100 не предназначены для работы с 1D штрих-кодом GS1-128, GS1 databar и тд, в которых кодируются разделители между различными идентификаторами?


1. И о режиме тоже (точнее о поддерживаемых Channels). RDP клиенты для Android не поддерживают Port redirection channel.
2. Нет, не правильно. Терминалы отлично передают всю информацию, содержащуюся в баркоде. Другое дело, что поле ввода не "может" отображать непечатные символы и игнорирует их. По причине отсутствия этих символов на клавиатуре. В поле ввода (и собственно в RDP) значение баркода передается как "нажатие" клавиш


Уточню вопрос: возможно ли в мобильных приложениях 1С, или по RDP в принципе работать корректно со штрих-кодом GS1? Если что, я пробовал в идущий в комплекте поставки приложениях сканировать GS1. Результат очевиден - не работает. Этот штрих-код является стандартом в логистике. Неужели ваши клиенты его не используют?


Нет, не возможно использовать непечтаные символы в штрихкоде. Т.к. стандарт 1С подразумевает передачу данных как строки. Ситуацию с RDP я вам описал выше. Нативные андроид приложения обрабатывают любой штрихкод корректно, т.к. получают его как массив байт.


Вопрос:: если приложение "Scanner" с отключенным режимом "Keyboard output mode" корректно считывает специальные символы и заменяет их на пробел, можно ли как-то добиться, чтобы этот пробел передавался в режим "Keyboard output mode"?

заказчик дал образец кода для пластиковой карты.
DKC_PC520398008
DKC_PC520399009
DKC_PC520391010
DKC_PC520392011

Может уже есть решение типа плагина, который генерирует последовательность кодов из корела?


В текстовик для корела не знаю как, но возможно поможет программа Bartender, в нете есть вылеченная. Умеет на листе размещать карты и генерить для каждой карты свой штрих (в т.ч. 128), может идти по очереди, может с шагом или из файла данные брать. Думаю что с сублимационниками тоже работать будет. Аналог предложенной программы - EASYLABEL, так же есть вылеченная на торентах.

карты печатаем. воспользовались [одной платной прогой за 1500р.
она привязана к кореловскому barcode wizard - делает код один в один.
лицензия только на 1 комп, так что на будущее продолжаю рассматривать возможные варианты

Последний раз редактировалось Виталий_777; 03.02.2012 в 09:07 .. Виталий_777, этот штрих-код не совсем Code128. Это UCC/EAN-128 (GS1-128) т.к. на первом месте после старта идет код FNC1, т.е. стандарт основанный на символике Code128. К тому же код не оптимальный (см. Приложение Е к ГОСТ 30743-2001). Но вполне читаемый ))) Стандарт UCC/EAN-128 пока в оригинале не читал, но там, как понял, куча норм и ограничений для соответствия ему.
ЗЫ: мой скриптик уже его поддерживает)))

Итак у меня получился более-менее приличный скрипт для MS Excel с генерацией штрих-кодов.
Задача передо мной стояла сделать персонализацию штрих-кодами аналогично простой текстовой персонализации. Т.е. в экселе в одной колонке коды, на другую напускаем функцию, а результат сохраняем в текстовый файл (Unicode).
Вроде получилось. Если будут замечены баги - пишите на адрес указанный в скрипте.

Поддерживаются EAN-8, EAN-13 (оба EAN не моего авторства - только модификация под мои шрифты), CODE-39 (без контрольного знака), CODE-128 (B,C), UCC/EAN-128 (точное соответствие стандарту может гарантировать только автор исходной строки для кодирования).

Специально для Виталий_777: функция DRPC128EAN() повторит кореловский штрих-код (Code128 с включенной по умолчанию опцией EAN-128) если количество цифр будет четным (относительно Вашего примера). Если количество цифр нечетно (как у Вас в примере), то мой код будет другой и короче на один символ. И абсолютно читаемый, если 5-м кеглем его не печатать )))

введите сюда описание изображения

Делаю проект для учебы и столкнулся с проблемой. Штрих-коды созданные с помощью шрифта не сканируются (проверял пока только с помощью телефона, но подозреваю, что и со сканером тоже ничего не выйдет). Изначально использовал шрифт Free 3 of 9, но потом проверил и со многими другими - результат тот же. Кодирую 13-значные числа. Один штрих-код получилось частично прочитать (почему-то выдало только первые 4 цифры). Подскажет кто-нибудь, в чем может быть проблема? Или я что-то не так делаю?


Вопрос, ШКИ такой как на картинке? Если да - шрифт. Не видел ШКИ для Crystal хотя использую его. Вы используете какую-то либу для ШКИ (сталкивался с такой), используйте именно тот шрифт который идет с этой либой.

Какой у вас тип ШКИ, стандартный EAN-13? Если у вас EAN13 - то должно быть две короткие спереди и две короткие сзади. EAN13 имеет особенность, если вы не соблюдаете контрольную сумму в последнем числе - то сканер читать такой ШКИ не будет (а смартфон прочтет), надо а)генерировать правильную КС, б)генерировать другой тип ШКИ, например code128 в)перепрограммировать сканер на чтение ШКИ без проверки КС.

Ещё, сканер можно спецом запрограммировать что бы он читал только ШКИ "своего формата", вырезал цифры, добавлял цифры, читал только перых 5 и т п., поэтому если у вас на предприятии действуют какие-то правила на ШКИ - то вам их нужно тоже знать. Если с вас решили поприкаловаться, или если сканер непонятно чей непонятно зачем и т п (телефон ШКИ читает а сканер нет) - то прийдется сбросить сканер.

@nick_n_a спасибо за то, что ответили, либы я никакие не использую, только Crystal Reports со шрифтами из инета. Со своей проблемой я вроде разобрался, дело скорее всего было в шрифте (либо же в его неправильном использовании, не уверен). Воспользовался шрифтом CCode39 и 10-значными кодами, все сканируется на ура (если использовать 11 цифр и больше, то бесполезно, но для меня разницы особой нет). Поэтому вопрос можно считать закрытым.

Читайте также: