среда, 14 апреля 2010 г.

Генерация штрихкода собственными силами

Штрихкоды используются повсеместно и их часто приходится генерировать программно. Но не всегда у нас есть редакторы для этих целей или мы не хотим платить за них.
Оказывается существует шрифт ean13, позволяющий генерировать штрихкоды. Но напрямую его использовать нельзя, необходимо сместись символы по алгоритму, чтобы получить необходимое нам изображение.

Здесь я приведу рабочий код, с минимальным описанием. Функция преобразует уже готовые штрихкоды, с рассчитанными контрольными суммами (Как считать контрольную сумму, можно прочитать тамже). Код на Oracle PL/Sql.

Ean13 и UPC-A
Отличие штрихкода UPC-A от EAN13 в одном первом символе. В UPC-A он всегда = 0
CREATE OR REPLACE FUNCTION FNC_GET_BARCODE_EAN13 ( sFBarCode IN VARCHAR2)
  RETURN  VARCHAR2 IS retBarCode VARCHAR2(15);
  lcnt INTEGER := 3;
  tableA BOOLEAN := FALSE;
  first CHAR(1);
  sBarCode VARCHAR2(15);
BEGIN
   sBarCode := sFBarCode;--внутренний буфер
   IF(length(sBarCode) = 12) THEN
    sBarCode := '0' || sBarCode;
   ELSIF(length(sBarCode) <> 13) THEN
    raise_application_error(-20010, 'Штрих код EAN13 должен содержать 13 символов');
    return '';
   END IF;
   
   retBarCode := SUBSTR(sBarCode, 1, 1);
   first := retBarCode;
   retBarCode := retBarCode || chr(65+SUBSTR(sBarCode, 2, 1));
   
   -- первая половина штрихкода
   FOR lcnt IN 3..7 LOOP
    tableA := FALSE;
    
    if (lcnt=3) and ((first=0) or (first=1) or (first=2) or (first=3)) THEN tableA:=TRUE; END IF;
    if (lcnt=4) and ((first=0) or (first=4) or (first=7) or (first=8)) THEN tableA:=TRUE; END IF;
    if (lcnt=5) and ((first=0) or (first=1) or (first=4) or (first=5) or (first=9)) THEN tableA:=TRUE; END IF;
    if (lcnt=6) and ((first=0) or (first=2) or (first=5) or (first=6) or (first=7)) THEN tableA:=TRUE; END IF;
    if (lcnt=7) and ((first=0) or (first=3) or (first=6) or (first=8) or (first=9)) THEN tableA:=TRUE; END IF;
    
    If tableA = TRUE THEN 
        retBarCode := retBarCode || chr(65+SUBSTR(sBarCode, lcnt, 1));
    ELSE 
        retBarCode := retBarCode || Chr(75+SUBSTR(sBarCode, lcnt, 1));
    END IF;
    
    tableA := FALSE;
  END LOOP;
  
  --разделитель середины штрихкода
  retBarCode := retBarCode || '*';
  
  --вторая половина штрихкода
  lcnt:=8;
  FOR lcnt IN 8..13 LOOP
    retBarCode := retBarCode || Chr(97+SUBSTR(sBarCode, lcnt, 1));
  END LOOP;
  
  --конец
  retBarCode := retBarCode || '+';
   
  RETURN retBarCode;
EXCEPTION
   WHEN OTHERS THEN
      RETURN '';
END;


EAN8
EAN8 имеет более простой механизм реализации, без смещений по таблице.
CREATE OR REPLACE FUNCTION FNC_GET_BARCODE_EAN8 ( sBarCode IN VARCHAR2)
  RETURN  VARCHAR2 IS retBarCode VARCHAR2(11);
  lcnt INTEGER := 3;
BEGIN
  if(length(sBarCode) <> 8) THEN
   raise_application_error(-20010, 'Штрих код EAN8 должен содержать 8 символов');
   return '';
  END IF;
   
  retBarCode := ':';
   
  -- первая половина штрихкода
  FOR lcnt IN 1..4 LOOP
    retBarCode := retBarCode || chr(65+SUBSTR(sBarCode, lcnt, 1));
  END LOOP;
  
  --разделитель середины штрихкода
  retBarCode := retBarCode || '*';
  
  --вторая половина штрихкода
  FOR lcnt IN 5..8 LOOP
    retBarCode := retBarCode || Chr(97+SUBSTR(sBarCode, lcnt, 1));
  END LOOP;
  
  --конец
  retBarCode := retBarCode || '+';
   
  RETURN retBarCode;
EXCEPTION
   WHEN OTHERS THEN
      RETURN '';
END;


Объединение предыдущих двух функций (В зависимости от переданной строки)
CREATE OR REPLACE FUNCTION FNC_GET_BARCODE_EAN ( sBarCode IN VARCHAR2)
  RETURN  VARCHAR2 IS retBarCode VARCHAR2(15);
BEGIN
  --Объединение EAN8 и EAN13
  IF(length(sBarCode) = 8) THEN
    retBarCode := FNC_GET_BARCODE_EAN8(sBarCode);
  ELSE
    retBarCode := FNC_GET_BARCODE_EAN13(sBarCode);
  END IF;
  RETURN retBarCode;
  
EXCEPTION
   WHEN OTHERS THEN
      RETURN '';
END;


Пример использования
select
FNC_GET_BARCODE_EAN('35967101') AS ean8,
FNC_GET_BARCODE_EAN('4607024381199') AS ean13,
FNC_GET_BARCODE_EAN('607024381199') AS upc
 from DUAL;


Полученную строку (после работы функции FNC_GET_BARCODE_EAN) можно выводить шрифотом ean13 и получить работающий штрихкод.