.

Почти больше года назад я начал свое знакомство с системой ОМС. В то время я устроился на работу в страховую компанию, занимающуюся ОМС. Первостепенной задачей было навести порядок в учете полисов внутри компании.
Первоначально нужно было придумать схему обработки и распределения полисов по отделения в области, которые поступали к нам в компанию из Территориального Фонда Обязательного Медицинского Страхования (ТФОМС). Камнем преткновения было декодирование штрих-кода с полиса ОМС.
Я начал искать информацию в интернете и ТФОМС. Результаты были плачевны, информации с гулькин нос. Прошло время, я разобрался, написал dll для декодирования штрих-кода полиса. Ради праздного интереса стал искать в гугле, может кто-нибудь написал о своем опыте на эту тему. И каково же было мое удивление, когда я обнаружил кучу вопросов и тем на формах - но НИ ОДНОГО НОРМАЛЬНОГО ОТВЕТА.
Информация нужна для того чтоб ей делились, и вот я решил поделиться ей. Не судите строго меня по этой статье. Она получилась большая, но зато я попытался описать все, что знаю по этой теме.
Просьба, при использовании материала данной статью указывать обратную ссылку на сайт.

Первое: Оборудование…

Начнем в первую очередь с оборудования для сканирования штрих-кода полиса. Нам понадобится двухмерный сканер штрих-кодов. Я использую Honeywell Xenon 1900. Сканер отличный, в мануале к сканеру есть штрих-код , который нужно им считать и он начнет эмулировать подключение по com-порту.

декодирование штрих-кода полиса ОМС
Сканер Honeywell Xenon 1900

Так же я пробовал сканер штрих Metrologic MS9520, честно говоря, хорошего результата он мне не дал. Тогда, времени разбирать не было в чем конкретно причина, потому остановил выбор на Xenon 1900. По цене, сканеры не сильно разнятся. Вывод один покупайте Honeywell Xenon 1900. Вложитесь один раз и горя знать не будете.

Более подробно про сканеры читайте здесь.

Второе: Описание штрих-кода…

Структура штрих-код полиса ОМС состоит из 131 байта (символа). Если вы от сканируете просто штрих-код сканером и выведите в блокнот, то там увидите «кракозябру». Почему так происходит?

Дело в том, что данные зашифрованы (сжаты), и сканер видит набор символов, которые Windows просто не может отобразить в блокноте. Рассмотрим, что видит сканер в «сыром виде».

Тип штрих-кода полиса ОМС

Первые 3 байта – это тип штрих-кода. Описание этого как такового в ГОСТе я не встретил. Типов штрих-кодов всего два: «010» и «020», чем отличаются эти два типа мы поговорим ниже.
Единый номер полиса (ЕНП) ОМС
С 4 по 9 символ (байты) закодирован ЕНП. ЕНП раскодируется в следующем порядке:
1. Берем первый символ, получаем код символа из таблицы ASCII (10 системе счисления ).
2. Переводим в 16 систему счисления.
3. Записываем, затем берем следующий символ, повторяем 1 и 2 пункты и полученное число записываем рядом с предыдущим.
4. Так перекодируем все символы с 4 по 9. В результате, получаем огромное число в 16 системе исчисления, которое, если перевести в 10 систему счисления, то получим ЕНП.
НО, как должно быть вы знаете, первые две цифры ЕНП – это код региона. Есть регионы, которые начинаются с нуля. Например, «02» -это называется лидирующий ноль. При данном методе сжатия ЕНП лидирующий ноль теряется, поэтому нужно проверять на выходе, если ЕНП равен 15 символам, нужно добавлять лидирующий ноль.
Код расшифровки ЕНП на языке Delphi выглядит следующим образом.

Procedure Decode_ENP(S:String);   //Функция декодирования ЕНП
var
  kod,i:integer;
  i2:int64;
  d:char;
  a,s3,s2,s1,enp_scan:String;

begin
  s1:=S;
  s2:='';
  for i:=4 to 10 do //строки индексируется с 1
   begin
   s3:=s2;
   a:=copy(s1,i,1);
   d:=a[1];
   kod:=ord(d); // получаем код символа из таблицы аски
   a:=IntTohex(kod,2); //перерводим в 16 СС
   s2:=s3+a;
   end;
  s2:='$'+s2;  //получаем число в 16 СС
  i2:=StrToInt64(s2);    //переводим в 10 СС
  enp_scan:=IntToStr(i2); //Получаем искомый ЕНП
  if (Length(enp_scan)=15) then// проверка для лидирующего нуля.
   begin
   enp_scan:='0'+enp_scan;
   end;
  BarCode.PolicyString :=pchar(enp_scan); //ниже я объясню что это такое..пока просто не обращайте внимание
end;

Вот так декодируется ЕНП. Итого мы разобрали всего с 1 по 10 байт, а их всего 131.

Декодирование Фамилии, Имени, Отчества с штрих-кода полиса ОМС

Помните, выше я писал про два типа штрих кода - “020” и “010”. Так вот они значительно влияют на алгоритмы раскодирования (декодирования в дальнейшем.) Расскажу в общих чертах, потом приведу примеры кода.
Тип «010».
ФИО записано с 11 по 52 символ (байт). Причем сделано это зеркально. Например (кодами символов):
35 56 06 67 6А 8F 5D DF… – так записано в штрих-коде полиса ОМС, отражаем зеркально
DF 5D 8F 6A 67 06 56 35 – декодируем в нормальный вид и получаем:
АНВОНИТНАТСНОК|АНИЛОП|АВЕНЬЛАШ – это ФИО в зеркальном отражении, то есть переписываем с конца в начало и получаем долгожданное Фамилию, Имя, Отчество с полиса ОМС
ШАЛЬНЕВА|ПОЛИНА|КОНСТАНТИНОВНА. В ГОЗНАКе работают жестокие извращенцы
Тип «020».
ФИО записано с 11 по 61 символ (байт). Причем больше ни какой «зеркальной чехарды». Например (кодами символов):
DF 5D 8F 6A 67 06 56 35 – декодируем в нормальный вид и получаем:
ШАЛЬНЕВА|ПОЛИНА|КОНСТАНТИНОВНА.
Как видите, есть различия, которые сильно влияют на весь порядок. Знали бы вы сколько нервов я потратил, пока путем экспериментов и тупого анализа строчек в виде кодов символов, я обнаружил данную закономерность. Ну не будем о грустном.
Немного расскажу про декодирование (раскодирование) самой строки из штрих-кода. Суть метода примерно следующая:
1. Получаем код символа в 8 системе счисления.
2. Берем первые 6 байт и переводим число в 16 систему счисления.
3. 16 числа представляются в виде двух символов, используя их и таблицу соответствий, определяем закодированный символ.
В общих чертах раскодирование происходит по выше описанному алгоритму. (Спасибо за помощь в реализации этой части Михаилу Станину).
Теперь собственно сам код:

const // Таблица соответствия
  Chars: array[0..3, 0..15] of AnsiChar = (
    (' ', '.', '-', '‘', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'А', 'Б'),
    ('В', 'Г', 'Д', 'E', 'Ё', 'Ж', 'З', 'И', 'Й', 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р'),
    ('С', 'Т', 'У', 'Ф', 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ь', 'Ъ', 'Ы', 'Э', 'Ю', 'Я', '*'),
    ('*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '|')
  );
var
 BarCode:TBARCODE;
// Получение символа 8 бит по коду 6 бит
function GetCharByCode(Code: Byte): AnsiChar;
var
  I, J: Byte;
begin
  I := Code div 16;
  J := Code mod 16;
  Result := Chars[I, J];
end;

// Сюда передается уже развернутая как надо строка
// На основе примера 39 C4 1D
//
// 00111001 11000100 00011101
// 39       C4       1D
// 001110 011100 010000 011101
// 0E     1C     10     1D
// То бишь нам надо разбить пачку 8ми битных символов на 6ти битные последовательности
function Decode(S: String): String;
var
  I: Byte;
  C: Byte;
  T: Word;
begin
  C := 0;
  I := 0;
 while (Length(S) > 0) and ((Length(S) > 1) or (I < 1)) do
    begin
      case I of
        0:
          begin
            C := Ord(S[1]) shr 2;
          end;
        1:
          begin
            T := Ord(S[1]) * 256 + Ord(S[2]);
            T := T shl 6;
            C := Byte(T shr 10);
          end;
        2:
          begin
            Delete(S, 1, 1);
            T := Ord(S[1]) * 256 + Ord(S[2]);
            T := T shl 4;
            C := Byte(T shr 10);
          end;
        3:
          begin
            Delete(S, 1, 1);
            C := Byte(Ord(S[1]) shl 2);
            C := Byte(C shr 2);
            Delete(S, 1, 1);
          end;
      end;
      I := (I + 1) mod 4;
      Result := Result + GetCharByCode(C);
    end;
end;

procedure Decode_FIO(S:String);  //Декодирование ФИО
var
fio_scan,stroca_FIO,fio:String;
i:Integer;

begin
if ord(s[2])=2 then
begin
  stroca_FIO:='';
  for i:=11 to 61 do
  begin
    stroca_FIO:=stroca_FIO+S[i];
  end;
  fio_scan:=Decode(stroca_FIO);
  for i:=1 to Length(fio_scan) do
  begin
   if (ord(fio_scan[i])=69) then
   begin
   fio_scan[i]:='Е';
   end;
  end;
  fio_scan:=TRIM(fio_scan);
  BarCode.FirstName:=Copy(fio_scan,1,(pos('|',fio_scan)-1));
  Delete(fio_scan, 1, pos('|',fio_scan));
  BarCode.LastName:=Copy(fio_scan,1,(pos('|',fio_scan)-1));
  Delete(fio_scan, 1, pos('|',fio_scan));
  BarCode.Patronymic:=fio_scan;
end;

if ord(s[2])=1 then
begin
   for i:=52 downto 11 do //Выбирание строчки с ФИО
   begin
    stroca_FIO:=stroca_FIO+S[i];

   end;
   fio:=Decode(stroca_FIO);

   for i:=Length(fio) downto 1 do
   begin
     fio_scan:=fio_scan+fio[i];
   end;
   for i:=1 to Length(fio_scan) do
  begin
   if (ord(fio_scan[i])=69) then
   begin
   fio_scan[i]:='Е';
   end;
  end;
   BarCode.LastName:=Copy(fio_scan,1,(pos('|',fio_scan)-1));
   Delete(fio_scan, 1, pos('|',fio_scan));
   BarCode.FirstName:=Copy(fio_scan,1,(pos('|',fio_scan)-1));
   Delete(fio_scan, 1, pos('|',fio_scan));
   BarCode.Patronymic:=trim(fio_scan);
end;

end;

Получаем пол, дату рождения и (дату окончания полиса – если она есть)

Вследствие того, что в зависимости от типа штрих-кода полиса ОМС, диапазон символов (байт) для ФИО разный, меняется расположение остальных данных. Пол представлен в виде одного символа (байта):
1-Мужской;
2-Женский.
Для типа штрих-кода полиса «010», это 53 символ. В штрих-коде типа «020» пол записан в 62 символе.

procedure Decode_Sex(S:String);   //Функция декодирования Пола

begin
if ord(s[2])=2 then
begin
 if ord(s[62])=1 then
 begin
  BarCode.Sex:='М';
 end;
 if ord(s[62])=2 then
 begin
  BarCode.Sex:='Ж';
 end;
end;
if ord(s[2])=1 then
begin
 if ord(s[53])=1 then
 begin
  BarCode.Sex:='М';
 end;
 if ord(s[53])=2 then
 begin
  BarCode.Sex:='Ж';
 end;
end;
end;

Дата рождения и дата окончания действия полиса кодируется количеством дней от 01.01.1900 г. до даты рождения/окончания полиса. Даты записаны в двух символах, декодирование идет по тому же принципу, что и ЕНП.
Ниже приведу просто пример кода:

procedure Decode_Data(S:String);   //Функция декодирования Даты рождения
var
  kod:integer;
  simvol:char;
  stroca_data:String;
  i_data:Integer;
begin
if ord(s[2])=2 then
begin
  simvol:=S[63];
  kod:=ord(simvol); // получаем код символа из таблицы аски
  stroca_data:=IntTohex(kod,2);//Переводим в 16 СС

  simvol:=S[64];
  kod:=ord(simvol); // получаем код символа из таблицы аски
  stroca_data:=stroca_data+IntTohex(kod,2);

  stroca_data:='$'+stroca_data;  //получаем число в 16 СС
  i_data:=StrToInt64(stroca_data);    //переводим в 10 СС
  BarCode.Data:=DateToStr(i_data+StrToDate('01.01.1900'));
end;
if ord(s[2])=1 then
begin
  simvol:=S[54];
  kod:=ord(simvol); // получаем код символа из таблицы аски
  stroca_data:=IntTohex(kod,2);//Переводим в 16 СС

  simvol:=S[55];
  kod:=ord(simvol); // получаем код символа из таблицы аски
  stroca_data:=stroca_data+IntTohex(kod,2);

  stroca_data:='$'+stroca_data;  //получаем число в 16 СС
  i_data:=StrToInt64(stroca_data);    //переводим в 10 СС
  BarCode.Data:=DateToStr(i_data+StrToDate('01.01.1900')); //Об этом моменте я расскажу в следующей статье
end;
end;

procedure Decode_Data_End(S:String);   //Функция декодирования Даты окончания полиса
var
  kod:integer;
  simvol:char;
  stroca_data:String;
  i_data:Integer;
begin
if ord(s[2])=2 then
begin
  simvol:=S[65];
  kod:=ord(simvol); // получаем код символа из таблицы аски
  stroca_data:=IntTohex(kod,2);//Переводим в 16 СС

  simvol:=S[66];
  kod:=ord(simvol); // получаем код символа из таблицы аски
  stroca_data:=stroca_data+IntTohex(kod,2);

  stroca_data:='$'+stroca_data;  //получаем число в 16 СС
  i_data:=StrToInt64(stroca_data);    //переводим в 10 СС
  BarCode.Data_End:=DateToStr(i_data+StrToDate('01.01.1900'));
end;
if ord(s[2])=1 then
begin
  simvol:=S[56];
  kod:=ord(simvol); // получаем код символа из таблицы аски
  stroca_data:=IntTohex(kod,2);//Переводим в 16 СС

  simvol:=S[57];
  kod:=ord(simvol); // получаем код символа из таблицы аски
  stroca_data:=stroca_data+IntTohex(kod,2);

  stroca_data:='$'+stroca_data;  //получаем число в 16 СС
  i_data:=StrToInt64(stroca_data);    //переводим в 10 СС
  BarCode.Data_End:=DateToStr(i_data+StrToDate('01.01.1900')); //Об этом моменте я расскажу в следующей статье
end;
end;

По структуре штрих-кода я все расписал, остальные символы это ЭЦП – электронно-цифровая подпись полиса. Во всяком случае, так написано в ГОСТе. Про то, как это реализовывается в виде dll я распишу в следующей статье.

Партнер сайта:
Заработок на блогах

P.S. Нравится материал. Длитесь в твитере, лайкайте в контакте и так далее.  Все спасибо))

P.S. Вторая часть статьи о декорировании штрих-кода здесь.Материал про электронные полисы здесь.


26 комментариев

  1. vologd

    Супер! Довольно понятно все сделано, с ходу правда в код не въехал… буду разбираться позже, хотя, если честно, меня больше интересует практическое применение, буду ждать дальнейшей информации. Надо добавить на сайт подписку)

    Ответить
    • admin_shinobi

      Ну в следующей статье через пару дней я планировал выложить сами исходники программы и dll. Чтобы все могли пользоваться. А на две части разбил, потому что по боялся что статья будет сильно большая.

      Ответить
  2. Константин

    Вячеслав, спасибо вам за статью. Интересно было по почитать и вторую часть. Подскажите пожалуйста, а со считыванием данных с электронных полисов (выполненных в виде смарт-карты) вы не сталкивались?

    Ответить
    • admin_shinobi

      Во второй части статьи будут исходники программы и dll на Delphi. Над смарт-картами я работаю в данный момент. Есть некоторые задумки. Планируется написать Delphi и С++.Это все для того что иметь две реализации одна под Windows и под Linux. Так что придется немного потерпеть я работаю..Спасибо за коментарии.

      Ответить
  3. Станислав

    Вячеслав, вопрос к тебе на засыпку — ты пишешь «Дело в том, что данные зашифрованы (сжаты), и сканер видит набор символов которые Windows просто не может отобразить в блокноте. Рассмотрим, что видит сканер в «сыром виде».» — можно узнать, как ты получаешь данные в «сыром виде»? Через получение буфера байт из виртуального COM-порта? Дело в том, что я в своей программе таким же образом считываю данные и все нормально, но есть одно «НО» — некоторые сканеры не умеют эмулировать работу через СОМ-порт, а работают как HID-устройства (т.е. ус-ва ввода, как клавиатура), и в этом случае к ним невозможно подключиться для считывания таких данных на низком уровне… А, учитывая, что в этом 131-байтовом массиве полно байтов со значениями х00-х20 (для которых не существует адекватных скан-кодов клавиш), получить данные полиса ОМС от таких сканеров становится невозможным. А привязывать заказчика к какой-то одной модели сканера штрих-кодов может быть не всегда осуществимо.

    Ответить
    • admin_shinobi

      В данном случае в «сыром» виде я понимал как получение строки из COM-порта. Во второй части я как раз хотел описать один интересный момент. Когда я писал, dll на Delphi XE то выяснилось, что из-за того что Delphi XE работает со строками кодировке UTF-8, а программа работала на языку Delphi 7. Возникали проблемы, неправильной расшифровки. Проблему обходил следующем образом, полученную строку я перегонял в байтовый массив. В dll байтовый массив, уже обратно в строку и дальше все как описано в статье. Вариант такой — То есть можно в принципе такую прокладку попытаться в пихнуть между получение и выводом на экран как клавиатуры.(Но возможно я вас не правильно понял.) Надеюсь я правильно вас понял. А по поводу модели: большинство двухмерных сканер штрих-кодов могу эмулировать com-порт.

      Ответить
  4. Станислав

    Понятно, значит надо добивать поставщика моего сканера, чтобы добыть драйвер виртуального СОМ-порта для девайса (Datalogic Quickscan 6500), поскольку в режиме USB Keyboard корректно считать такой штрих-код невозможно…
    Кстати, а чем Вы получали строку из СОМ-порта? Каким-то сторонним компонентом? Почему не функциями WinAPI, например CreateFile/ReadFile, они как раз в массиве байт возвращают считанные данные — очень удобно потом с ними работать). Заодно уходит проблема с Unicode-строками. Я аналогичную DLL написал на XE5 и именно таким способом. Теперь вот пытаюсь унифицировать под несколько моделей считывателей)

    Ответить
  5. Станислав

    И да, поняли Вы меня не совсем правильно — в режиме USB-клавиатуры сканер возвращает ТОЛЬКО скан-коды нажатых клавиш. В случае обычных штрих-кодов, или даже двумерных pdf417, но содержащих обычные текстовые данные, никаких проблем нет — распознанные символы (цифры и буквы) переводятся в коды соответствующих клавиш, и все довольны и счастливы. Но когда в штрих-коде закодированы «сырые» данные, то сопоставить каждому байту (в диапазоне х00-х1F) нужную клавишу невозможно. Так как, к примеру, байт х08 — это символ клавиши Backspace, которая стирает предыдущий символ, а байт х00 вообще не имеет своего кода (точнее, это код, означающий, что НИКАКАЯ клавиша не нажата).

    P.S. В данный момент у меня на столе 2 сканера — упомянутый выше Datalogic, а также сканер какой-то фирмы VMC (модель Burstscan). Так вот VMC нормально работает через свой виртуальный СОМ-порт, а даталоджик не хочет)). И, т.к. модель старая, драйверов на сайте производителя уже нет, а поддержка ихняя отмазывается какими-то глупыми отписками…

    Ответить
    • admin_shinobi

      Интересное замечание по поводу, USB-клавиатуры. Но как показывает практика, да в принципе и те примеры что подавал Ростовский ТФОМС необходимо использовать схему с СОМ-портом, так в данном случае pdf417 несколько модифицирован. Если бы у нас был стандартный pdf417, мы имели возможность сразу со сканера получить данные в читаемом виде. Например: «СИДОРОВ|ИВАН|ИВАНОВИЧ и т.д.» . Тогда режим USB-клавиатуры не стал бы помехой. В нашем случае мы со сканера должны получить набор байтов, то есть распознанный штрих код. При эмуляции USB-клавиатуры, декодирование набора байт делает сканер. В нашем случае этого не требуется — мы будем делать это сами. Сканеры которые могу отдать предварительно распознанный штрих код (набор байтов), имеют эмуляцию СОМ-порта. Можно попробовать поэкспериментировать с настройками сканера, для получения набора байтов.

      Ответить
    • admin_shinobi

      Ну благодаря вам Станислав, просто ради интереса посмотрел, где и как он модифицирован это тема отдельной статьи. Прочтите если вам интересно. Ссылка на статью в главе про оборудование.

      Ответить

  6. Все очень замечательно описано, давно искал подобную информацию, находил основы, но так и не добрался до результата. Тут все понятно, уже на примерах FIO попробовал, но… проблема в том, что при считывания всех полисов первые значения идут 4f A6… как определить тип штрих кода — “020” или “010” и дальше код выглядит как 4f A6 A6 E1 3F 3A 5f 60… а если перевести номер полиса в HEX то получается 17 A6 E1 3F 3A 9A 60 тем самым отличается 1,2,7 код, в других полисах отличаются другие.

    Ответить
    • admin_shinobi

      Тип штрих-кода я получал, когда просто перегонял символы в байты. То есть, получаете код символа вот и все. Во второй части я приложу исходники, если возникнут проблемы пишите на мыло. Я всегда готов помочь.

      Ответить

      • Со штрих-кодом понятно и не понятно. Скачал драйвера и кучу программ передачи данных через COM-порт. Действительно, код передается правильный, тот, что описан. И переделав примеры расшифровки кода «под себя (я создаю софт на PHP)» получил номер полиса и ФИО, а вот с датами возникли проблемы, уже неделю бьюсь… жду следующую статью BarCode.Data_End:=DateToStr(i_data+StrToDate(‘01.01.1900‘)); //Об этом моменте я расскажу в следующей статье
        Дело в том, что система в Windows/Unix работает с начально датой: 01.01.1970, а код шифруется от 01.01.1900 (а если точнее из НЕХ, то надо еще прибавить 2) и PHP, язык более высокого уровня и в нем нет команд типа StrToDate и DateToStr 🙁 Как то можно иначе перевести число, полученное из НЕХ в формат даты?

        Ответить
  7. admin_shinobi

    Функция StrToDate используется для приведения строки ‘01.01.1900’ в тип данных Date, описанный в Delphi. Следовательно, DateToStr для обратного превращения. «что система в Windows/Unix работает с начально датой: 01.01.1970» — вот это не понимаю к чему тут. Я беру дату 01.01.1900 и просто добавляю количество дней i_data. По поводу функции не уверен, но думаю аналоги есть. Но если все так проблематично, я помогу… Все в ответе на второй комментарий.

    Ответить
  8. Евгений

    очень заинтересовал ваш пост, работаю в системе омс 6 лет. у нас есть готовый комплекс (куча программ) для расшифрования штрихкода. отпишитесь мне на почту.

    Ответить
  9. Андрей

    Здравствуйте. Подскажите пожалуйста. у меня стоит задача перенести штрих код ОМС с бумаги на другой носитель (пластиковые карты).
    я понял что,
    * сканер надо купить 2D.
    *принтер для карт купили
    Вопрос в следующем, как мне проще всего это реализовать, через какую программу и т.д.
    Спасибо заранее.

    Ответить
    • admin_shinobi

      Я встречал программы которые через внешнюю dll генерировали штрих-код. Этим штрих-кодом подписывались документы. В принципе если поискать я думаю можно что-нибудь придумать. Задача ваша интересная…Я бы даже хотел вам помочь в реализации. (Нескромно прозвучит…) P.S. FastReport умеет вроде как тоже генерировать на отчетах штрих-коды))Правда я подробно не разбирался. По идеи схема сканируем->генерируем штрих-код->передаем данные на принтер. Все))

      Ответить
      • Андрей

        Спасибо, буду пробовать. отпишусь потом что да как) Отличный сайт. так держать.

        Ответить
      • Андрей

        Какой сканер посоветуете под сие дело?

        Ответить
        • admin_shinobi

          Honeywell Xenon 1900 — я про него в статье упоминал. В загрузках есть драйвера для него. Я когда начинал работу над своим проектом, нам его посоветовали с головного офиса. Купили пробовали. Работает отлично. Потому как я писал что штрих-код на полисе ОМС модифированный PDF-417, поэтому не всякий 2D-сканер его может «схавать». Поэтому я советую именно этот сканер с ним проблем вообще не было. Сейчас их не знаю наверное штук 10 закупили, как раз для работы со полисами. Если могу посоветовать Metrologic MS9520 -правда с ним не работал, но в конкурентной страховой с полисами им работают. Короче либо первый сканер либо второй. Больше проверенных сканеров я не знаю.

          Ответить
      • Александр

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

        Ответить
        • admin_shinobi

          Честно,я вас не до конца понял….Обычно штрих-код не кодируется а распространяется в открытом виде, а переводом изображения в в строчку занимается сканер. Если вы о штрих-коде омс то строчку лучше перекодировать в виде набора байтов, советую прочитать здесь вторую часть о «Декодирование (расшифровка) штрих-кода полиса ОМС» и еще статью по штрих-коду омс, там я подробно рассмотрел чем он отличается от стандартного штрих-кода. Если вопросы останутся можете написать мне на мыло я помогу.

          Ответить
  10. Константин

    Здравствуйте, Вячеслав. Любопытно было бы взглянуть на мануал, по которому вы разбирали штрих-код. Согласно протоколам, по которым мы реализовали разбор у себя, для типа штрих-кода используется только первый байт. ЕНП начинается со второго байта. Именно байта, не символа. Делфи не мой профильный язык, но насколько я вижу по коду вы читаете для ЕНП 7 символов и из них получаете всегда 14 символов. Затем всегда добавляете 0. Предположу, что полисы, с которыми вам приходится сталкиваться, относятся как раз к региону из первой десятки, поэтому ошибку вы упустили.
    Хочу заметить, что кроме типов 1 и 2, мне попадался еще один тип. Я не нашел для него описаний. Он соответствует по структуре типу 2, но не содержит первого байта типа штрих кода. Т.е. ЕНП начинается с первого байта. Условно назвал его тип 0. Т.к. на данный момент данный тип мне попадался только нулем в первом байте.
    P.S. Возможно, за давностью написания статьи, все ошибки вами уже исправлены. У меня не было цели уличить вас в «кривом коде». Хотелось бы узнать, встречались ли вы еще с какими-либо другими способами шифрования данных полиса, с целью перенять ваш опыт.

    Ответить
    • admin_shinobi

      Ну во-первых, я получаю набор байт и тип штрих-кода во втором байте. Правильно первый всегда ноль. Там же написано тип байт (1)-0, байт (2)-2. Вы попробуйте посмотреть какой у вас будет второй байт. Просто готов поспорить он равен 2. ЕНП я получаю, с 3 по 9 байты. По поводу первого нуля он же лидирующий…Я понимаю просто большое число ЕНП, когда преобразовается лидирующий ноль теряется, в силу того что не принимают системы исчисления этого. Поэтому там добавлена проверка, на случай если код региона будет начинаться с нуля. Все материалы которые приведены в статье, используются до сих пор. А тип штрих-кода «01» очень редко. Я в 90% случаев встречал его на старых полисах 2011-2012 года.

      Ответить
      • Константин

        Я никак не пойму, почему тип штрих-кода у вас во втором байте, если по протоколу на это поле отводится всего 1 байт в начале?
        Давайте посмотрим на описание типа 2: http://www.rostov-tfoms.ru/documents/servisy/informatsionnyj-obmen/pravila-formirovaniya-shtrih-kodov-2.pdf
        Указано, что для Кода типа штрих-кода отводится 1 байт и это поле максимум в 1 символ. Далее идут 8 байт номера.
        Для примера, начало штрих-кода типа 2: 0x02 0x00 0x0a 0x22 0xca
        А вот пример штрих-кода неизвестного типа: 0x00 0x0a 0x46 0xfa 0x18. Данный штрих-код по структуре соответствует типу 2, но без первого байта. К сожалению, не могу сказать один раз этот тип встретился или он периодически попадается, т.к. учет штрих-кодов не ведется.

        Ответить
  11. Андрей

    Ищу специалиста со знаниями в этой области. Хочу предложить работу. Напишите мне. Обсудим.

    Ответить

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *