Algoritmo per il Code 39

Il Code 39 è un codice a barre che nasce nel 1974 per l’esigenza di avere una catalogazione alfanumerica nella matricola dei prodotti di magazzino ed ancora oggi è molto utilizzato, soprattutto in campo industriale. In questo articolo vedremo di capire gli aspetti teorici di questo tipo di barcode e poi svilupperemo insieme un algoritmo per codificarlo in linguaggio C++, utilizzando le MFC.
Il Code 39 utilizza 43 caratteri alfanumerici, le lettere maiuscole dell’alfabeto, i numeri ed alcuni caratteri speciali come lo spazio, il punto, il trattino, il dollaro, il segno più, lo slash e il simbolo della percentuale. Il carattere speciale asterisco invece serve per iniziare e terminare il codice. C’è anche un carattere di controllo che si ottiene dal modulo 43 della somma dei precedenti valori secondo una tabella che analizzeremo più tardi quando affronteremo la creazione dell’algoritmo di codifica. Per disegnare il codice a barre dobbiamo sapere che, nel Code 39 ogni elemento è composto da 9 elementi, 5 barre e 4 spazi e di questi, 3 sono larghi e 6 stretti. Capirete da questo che l’estensione del disegno è molto più grande rispetto alla codifica EAN, infatti nel mio programma ho dovuto raddoppiare gli spazi necessari.

Il software con il Code 39

Il software Calus con il Code 39

Veniamo quindi a buttar giù un po’ di righe per l’algoritmo in C++ per codificare il Code 39. Come prima funzione che dobbiamo implementare c’è quella per trovare il carattere di controllo, ossia il modulo 43 del totale dei pesi degli altri elementi del codice:

CStringArray arrVal;

arrVal.Add(_T("0"));
arrVal.Add(_T("1"));
arrVal.Add(_T("2"));
...
arrVal.Add(_T("8"));
arrVal.Add(_T("9"));
arrVal.Add(_T("A"));
arrVal.Add(_T("B"));
arrVal.Add(_T("C"));
...
arrVal.Add(_T("Y"));
arrVal.Add(_T("Z"));
arrVal.Add(_T("-"));
arrVal.Add(_T("."));
arrVal.Add(_T(" "));
arrVal.Add(_T("$"));
arrVal.Add(_T("/"));
arrVal.Add(_T("+"));
arrVal.Add(_T("%"));

int iTot = 0;
for (int i = 0; i < strValue.GetLength(); ++i)
{
   for (int j = 0; j < arrVal.GetCount(); ++j)
   {
      if (arrVal.GetAt(j) == strValue.GetAt(i))
      {
	iTot += j;
      }
   }
}

div_t dv = div(iTot, 43);
strValue = arrVal.GetAt(dv.rem);
arrVal.RemoveAll();

return (char)strValue[0];

Nell’array ho inserito i caratteri in ordine al loro peso, quindi la lettera A in posizione 11 ed il simbolo di percentuale il valore 42. Alla fine si prende la somma ottenuta e si fa il modulo 43 di questa cifra, il resto restituito equivale al carattere corrispondente, quello di controllo.
Per il disegno dobbiamo rifarci ad una tabella tra righe piene e vuote che memorizziamo in un array:

CMapStringToString mapDraw;
mapDraw.InitHashTable(44);

mapDraw.SetAt(_T("1"), _T("100100001"));
mapDraw.SetAt(_T("2"), _T("001100001"));
mapDraw.SetAt(_T("3"), _T("101100000"));
mapDraw.SetAt(_T("4"), _T("000110001"));
mapDraw.SetAt(_T("5"), _T("100110000"));
mapDraw.SetAt(_T("6"), _T("001110000"));
mapDraw.SetAt(_T("7"), _T("000100101"));
mapDraw.SetAt(_T("8"), _T("100100100"));
mapDraw.SetAt(_T("9"), _T("001100100"));
mapDraw.SetAt(_T("0"), _T("000110100"));
mapDraw.SetAt(_T("A"), _T("100001001"));
mapDraw.SetAt(_T("B"), _T("001001001"));
mapDraw.SetAt(_T("C"), _T("101001000"));
mapDraw.SetAt(_T("D"), _T("000011001"));
mapDraw.SetAt(_T("E"), _T("100011000"));
mapDraw.SetAt(_T("F"), _T("001011000"));
mapDraw.SetAt(_T("G"), _T("000001101"));
mapDraw.SetAt(_T("H"), _T("100001100"));
mapDraw.SetAt(_T("I"), _T("001001100"));
mapDraw.SetAt(_T("J"), _T("000011100"));
mapDraw.SetAt(_T("K"), _T("100000011"));
mapDraw.SetAt(_T("L"), _T("001000011"));
mapDraw.SetAt(_T("M"), _T("101000010"));
mapDraw.SetAt(_T("N"), _T("000010011"));
mapDraw.SetAt(_T("O"), _T("100010010"));
mapDraw.SetAt(_T("P"), _T("001010010"));
mapDraw.SetAt(_T("Q"), _T("000000111"));
mapDraw.SetAt(_T("R"), _T("100000110"));
mapDraw.SetAt(_T("S"), _T("001000110"));
mapDraw.SetAt(_T("T"), _T("000010110"));
mapDraw.SetAt(_T("U"), _T("110000001"));
mapDraw.SetAt(_T("V"), _T("011000001"));
mapDraw.SetAt(_T("W"), _T("111000000"));
mapDraw.SetAt(_T("X"), _T("010010001"));
mapDraw.SetAt(_T("Y"), _T("110010000"));
mapDraw.SetAt(_T("Z"), _T("011010000"));
mapDraw.SetAt(_T("-"), _T("010000101"));
mapDraw.SetAt(_T("."), _T("110000100"));
mapDraw.SetAt(_T(" "), _T("011000100"));
mapDraw.SetAt(_T("*"), _T("010010100"));
mapDraw.SetAt(_T("$"), _T("010101000"));
mapDraw.SetAt(_T("/"), _T("010100010"));
mapDraw.SetAt(_T("+"), _T("010001010"));
mapDraw.SetAt(_T("%"), _T("000101010"));

Ogni carattere ha nove numeri tra 0 ed 1, in posizioni dispari, il primo indica il disegno di uno linea larga e lo 0 di una linea stretta, per i pari rispettivamente uno spazio largo ed uno stretto. A questo punto è semplice fare il disegno, qui per questioni di lungaggini ho inserito solo l’algoritmo per disegnare il codice a barre, ovviamente ognuno si può inventare la sua procedura:

CString strTemp;
for (int i = 0; i < m_strCodix.GetLength(); ++i)
{
   strTemp = m_strCodix.GetAt(i);
   if (mapDraw.Lookup(strTemp, buffer))
   {
      for (j = 1; j <= 9; ++j)
      {
	if ((j % 2) != 0)
	{
            dc.MoveTo(counter, rectCodix.top);
	    if (buffer.Mid(j - 1, 1) == _T("1"))
	    {
		dc.LineTo(counter, rectCodix.bottom);
		counter++;
		dc.MoveTo(counter, rectCodix.top);
		dc.LineTo(counter, rectCodix.bottom);
		counter++;
		dc.MoveTo(counter, rectCodix.top);
		dc.LineTo(counter, rectCodix.bottom);
	     }
	     else
		dc.LineTo(counter, rectCodix.bottom);

	     counter++;
	}
	else
	{
	    if (buffer.Mid(j - 1, 1) == _T("1"))
		counter += 3;
	    else
		counter++;
	}
    }
}

La procedura è semplice, basta infatti iterare il valore alfanumerico del codice a barre e trovare il valore corrispondente nella map, a quel punto sapremo le linee e gli spazi che dobbiamo inserire. Ovviamente non dimenticate di inserire l’asterisco iniziale e finale.
Il codice a barre Code 39 è molto semplice da implementare, conoscendo gli aspetti teorici. Questo tipo di barcode ha il vantaggio dei simboli alfanumerici ( poi magari lo amplieremo con altri caratteri, come le lettere minuscole dell’alfabeto ), ma presenta il problema della grandezza del disegno del codice, infatti si ha bisogno di molto più spazio orizzontale per disegnarlo rispetto agli altri.

Informazioni su Giampaolo Rossi

Sviluppatore di software gestionale da oltre 28 anni.
Questa voce è stata pubblicata in Programmazione, VC/C++. Contrassegna il permalink.