Az EAN-13 ... ah, Wikipedia leírja szépen... minket az alábbi táblázatok érdekelnek elsősorban:
EAN-13 struktúra
====================================
| 1. jegy | 2-6. jegy | 7-13. jegy |
====================================
| 0 | LLLLLL | RRRRRR |
------------------------------------
| 1 | LLGLGG | RRRRRR |
------------------------------------
| 2 | LLGGLG | RRRRRR |
------------------------------------
| 3 | LLGGGL | RRRRRR |
------------------------------------
| 4 | LGLLGG | RRRRRR |
------------------------------------
| 5 | LGGLLG | RRRRRR |
------------------------------------
| 6 | LGGGLL | RRRRRR |
------------------------------------
| 7 | LGLGLG | RRRRRR |
------------------------------------
| 8 | LGLGGL | RRRRRR |
------------------------------------
| 9 | LGGLGL | RRRRRR |
====================================
Számjegyek kódolása:
========================================
| Szám | L-kód | G-kód | R-kód |
----------------------------------------
| 0 | 0001101 | 0100111 | 1110010 |
----------------------------------------
| 1 | 0011001 | 0110011 | 1100110 |
----------------------------------------
| 2 | 0010011 | 0011011 | 1101100 |
----------------------------------------
| 3 | 0111101 | 0100001 | 1000010 |
----------------------------------------
| 4 | 0100011 | 0011101 | 1011100 |
----------------------------------------
| 5 | 0110001 | 0111001 | 1001110 |
----------------------------------------
| 6 | 0101111 | 0000101 | 1010000 |
----------------------------------------
| 7 | 0111011 | 0010001 | 1000100 |
----------------------------------------
| 8 | 0110111 | 0001001 | 1001000 |
----------------------------------------
| 9 | 0001011 | 0010111 | 1110100 |
========================================
Innen már egész egyszerű dolgunk van:
Megnézzük az első számjegyet, ami megmutatja a többi 12 kódolását. A 2-tól a 13. jegyig gyalogolva a 2. táblázatból kikeressük a megfelelő számjegy-kódoláshoz tartozó bitmintát, majd ahol 1-es van, oda húzunk egy vonalat. Hogy a vonalkódolvasót segítsük a 2. jegy elé (az elsőt nem ábrázoljuk vonalakkal) és a 13. jegy után határolóvonalat, a 6. és 7. jegy közé pedig egy elválasztót firkálunk.
A kód:
Qt alatti rajzoláshoz a legújabb ajánlások a QGraphicsView widgetet javasolják, így erre fogok építkezni. Származtatok egy saját BarcodeDrawView osztályt a következőképp:
#ifndef BARCODEDRAWVIEW_H
#define BARCODEDRAWVIEW_H
#include <QGraphicsView>
class BarcodeDrawView : public QGraphicsView
{
public:
BarcodeDrawView(QWidget *parent = 0);
~BarcodeDrawView();
void drawBarcode();
void setNumber(const QString& num);
private:
QGraphicsScene *_scene;
QString *_barcodeNum;
const char *_encodingMask;
void initEncoder();
QBitArray *getBitmaskForDigit(const QChar &num, const char &codeType);
void drawBitPattern(const QBitArray &, int, int);
};
#endif // BARCODEDRAWVIEW_H
Mint látható az osztály 2 darab publikus eljárást tartalmaz. A
setNumber(const QString& num)
eljárás állítja be a
_barcodeNum
változó értékét, majd inicializálja a "kódolót" az
initEncoder()
eljárás meghívásával.
void BarcodeDrawView::setNumber(const QString &barcodeNum)
{
if(barcodeNum.isNull() || barcodeNum.isEmpty())
return;
this->_barcodeNum = new QString(barcodeNum);
initEncoder();
}
Az
initEncoder()
eljárás megvizsgálja a beállított vonalkód-számsor első jegyét majd az
_encodingMask
változóba helyezi a megfelelő kódolási mintát.
void BarcodeDrawView::initEncoder()
{
// The first digit determines the encoding of the other 12 digits,
// so we set up the encoding masks here
QList<QString> encodingMasks;
encodingMasks
<< "LLLLLLRRRRRR" // 0
<< "LLGLGGRRRRRR" // 1
<< "LLGGLGRRRRRR" // 2
<< "LLGGGLRRRRRR" // 3
<< "LGLLGGRRRRRR" // 4
<< "LGGLLGRRRRRR" // 5
<< "LGGGLLRRRRRR" // 6
<< "LGLGLGRRRRRR" // 7
<< "LGLGGLRRRRRR" // 8
<< "LGGLGLRRRRRR"; // 9
int firstDigit = (this->_barcodeNum->at(0)).digitValue();
if(firstDigit < 0 || firstDigit > 9)
return;
QString encodeStr = encodingMasks.at(firstDigit);
QByteArray tmpStr = encodeStr.toAscii();
this->_encodingMask = tmpStr.data();
}
A
drawBarcode()
eljárás meghívásakor az a kódolási mintának megfelelően minden számjegyre előállítja a hozzátartozó bitmintát majd a
_scene
változó által kijelölt QGraphicsScene példánnyal kirajzoltatja azt.
void BarcodeDrawView::drawBarcode()
{
int x = 0;
int height = 100;
QBitArray *bitmaskForDigit; // NOTE!!! QBitArray is zero indexed, e.g. the first bit is at index 0, NOT 1!!!
QBitArray borderBits(3);
QBitArray separatorBits(5);
// The border bars are always represented as '101'
borderBits.toggleBit(0);
borderBits.toggleBit(2);
// The middle separator is always represented as '01010'
separatorBits.toggleBit(1);
separatorBits.toggleBit(3);
int codeLength(12);
drawBitPattern(borderBits, x, height+10);
x += 3;
for( int i=0; i<codeLength; i++ ) {
bitmaskForDigit = getBitmaskForDigit(this->_barcodeNum->at(i+1), this->_encodingMask[i]);
if( i==6 ) {
drawBitPattern(separatorBits, x, height+5);
x += 5;
}
drawBitPattern(*bitmaskForDigit, x, height);
delete bitmaskForDigit;
x += 7;
}
drawBitPattern(borderBits, x, height+10);
update();
}
Mint látható a
drawBarcode
eljárás 2 segédet használ:
void drawBitPattern(const QBitArray &, int, int)
és
QBitArray *getBitmaskForDigit(const QChar &num, const char &codeType)
Utóbbi függvény visszaadja az első paraméterben átadott 1 darab karakternek a második paraméterben átadott kódolás ('L', 'G' vagy 'R') szerinti bitmintáját:
QBitArray *BarcodeDrawView::getBitmaskForDigit(const QChar& digitAsChar, const char &codeType)
{
QBitArray *bitmaskForDigit = new QBitArray(7, false); // Resulting bit mask will be stored here
QBitArray *tmpBitmask = new QBitArray(7, false); // Temporary bit array used by the L code transformations
int currentDigit = digitAsChar.digitValue();
// Always produce the L code first, since both R and G can be derived from it
bitmaskForDigit->setBit(6, true); // The last bit of the L code is always 1
switch(currentDigit) {
case 0:
bitmaskForDigit->toggleBit(3);
bitmaskForDigit->toggleBit(4);
break;
case 1:
bitmaskForDigit->toggleBit(2);
bitmaskForDigit->toggleBit(3);
break;
case 2:
bitmaskForDigit->toggleBit(2);
bitmaskForDigit->toggleBit(5);
break;
case 3:
bitmaskForDigit->toggleBit(1);
bitmaskForDigit->toggleBit(2);
bitmaskForDigit->toggleBit(3);
bitmaskForDigit->toggleBit(4);
break;
case 4:
bitmaskForDigit->toggleBit(1);
bitmaskForDigit->toggleBit(5);
break;
case 5:
bitmaskForDigit->toggleBit(1);
bitmaskForDigit->toggleBit(2);
break;
case 6:
bitmaskForDigit->toggleBit(1);
bitmaskForDigit->toggleBit(3);
bitmaskForDigit->toggleBit(4);
bitmaskForDigit->toggleBit(5);
break;
case 7:
bitmaskForDigit->toggleBit(1);
bitmaskForDigit->toggleBit(2);
bitmaskForDigit->toggleBit(3);
bitmaskForDigit->toggleBit(5);
break;
case 8:
bitmaskForDigit->toggleBit(1);
bitmaskForDigit->toggleBit(2);
bitmaskForDigit->toggleBit(4);
bitmaskForDigit->toggleBit(5);
break;
case 9:
bitmaskForDigit->toggleBit(3);
bitmaskForDigit->toggleBit(5);
break;
default:
break;
}
//The R code is the complement of the L code so
if(codeType == 'R') {
for(int i=0; i<bitmaskForDigit->size(); i++) {
bitmaskForDigit->toggleBit(i);
}
}
else if(codeType == 'G') {
// Produce the R code
for(int i=0; i<bitmaskForDigit->size(); i++) {
bitmaskForDigit->toggleBit(i);
}
//Reverse it to get the G code
for(int i=bitmaskForDigit->size()-1; i>=0; i--) {
tmpBitmask->setBit(i, bitmaskForDigit->at(bitmaskForDigit->size()-i-1));
}
bitmaskForDigit = tmpBitmask;
delete tmpBitmask;
}
return bitmaskForDigit;
}
Aki idáig még nem fordult le a székről kínjában, az ne csüggedjen, már nincs sok hátra! :)
Az EAN-13-ban alkalmazott háromféle kódolásnak van egy nagyszerű tulajdonsága, amit rögtön ki is használunk: az 'L' kódból egyszerű műveletekkel megkapható az 'R' és a 'G' kódolás is, mépedig az alábbiak szerint:
R = ~L
, ahol '~' a komplemensképzés jele
G = inverz(~L) = inverz(R)
.
Tehát, teljesen mindegy, hogy adott számjegynek milyen kódolása kell, először mindig az 'L' szerintit állítjuk elő, majd ebből transzformációkkal előállítjuk a nekünk szükségest. /Itt jegyezném meg, hogy legyen áldott a neve annak, aki a QBitArray-t kitalálta! :D/
A visszaadott
bitmaskForDigit
változó tartalmát átadva a
drawBitPattern(const QBitArray &, int, int)
eljárásnak, az szépen megjeleníti a 2. paraméterében lévő X koordinátán a 3. paraméterében kapott magassággal a megfelelő vonalkód-részletet:
void BarcodeDrawView::drawBitPattern(const QBitArray& bitPattern, int x, int height)
{
QPen pen;
int patternSize = bitPattern.size();
for(int i=0; i<patternSize; i++) {
if(bitPattern.at(i))
{
pen.setColor(Qt::black);
}
else
{
pen.setColor(Qt::white);
}
(this->_scene)->addLine(x, 0, x, height, pen);
x++;
}
}
Ennyi az egész :)
Az osztályt !szépre faragva! kapunk egy újrafelhasználható komponenst, amit szinte bármilyen vonalkód előállítást alkalmazó projektben felhasználhatunk!
MEGJEGYZÉS: Kérem vegyétek figyelembe, hogy közel 2 éve nem fejlesztettem sem C++-ban, sem Qt használatával, így előfordulhatnak ordas nagy baromságok. Az építő jellegű kritikát szívesen fogadom, ha igény van rá, természetesen ennek megfelelően átalakítom eme demonstrációs alkalmazást.
Update:
Megtaláltam a hibát, ami miatt rossz vonalkódot generált a kód. Itt van két kép, az egyik 1px vastag vonallal, a másik 2px vastag vonallal és hozzátartozó x irányú eltolással készült. Nem tudom, hogy az olvasók mennyire érzékenyek a vonalvastagságra...
- f0xhu blogja
- A hozzászóláshoz be kell jelentkezni
- 1142 megtekintés
Hozzászólások
Screenshotot! :)
--
Don't be an Ubuntard!
- A hozzászóláshoz be kell jelentkezni
http://kepfeltoltes.hu/view/100706/barcode_www.kepfeltoltes.hu_.png
--
A gyors gondolat többet ér, mint a gyors mozdulat.
- A hozzászóláshoz be kell jelentkezni
Szép! :)
--
Don't be an Ubuntard!
- A hozzászóláshoz be kell jelentkezni
Nem lehet, hogy valami bug van elbujva benne? A vonalkodolvasom nem ismeri fel...
(mielott valaki belekotne: ez egy speci vonalkodolvaso, kepfelismeres elven mukodik, es mas vonalkodokat szepen leolvas a kepernyorol)
- A hozzászóláshoz be kell jelentkezni
Ezt esetleg nem tudnád tesztelni, kíváncsi lennék az eredményre.
http://hup.hu/node/89765#comment-1065119
KAMI | 神
--
Támogatás | OxygenOffice | Fordításaim és SeaMonkey
- A hozzászóláshoz be kell jelentkezni
Mukodik (csak a weblapon szereplo kepet ellenoriztem, a plugint nem probaltam).
- A hozzászóláshoz be kell jelentkezni
De, a képet bugos kód generálta! :/ Javítottam benne, majd keresek referenciát és ellenőrzöm.
--
A gyors gondolat többet ér, mint a gyors mozdulat.
- A hozzászóláshoz be kell jelentkezni
Most se jo...
Osszehasonlitottam a te vonalkododat a barcodeisland-es keppel, es ugy tunik, hogy a tied "huzatosabb" (nagyobbak az ures helyek). Lehet, hogy csak mas kodolas, mindenesetre az olvasom nem ismeri fel (a barcodeisland-est igen).
- A hozzászóláshoz be kell jelentkezni
:) Nem is lesz. Természetesen ennek is van rögzített mérete és oldalarányai, amit sikerült nem figyelembe vennem...
--
A gyors gondolat többet ér, mint a gyors mozdulat.
- A hozzászóláshoz be kell jelentkezni
Ha gondolod tesztelt az OpenOffice-os kiterjesztéssel, azt már többen tesztelték. Meg a forrás is elérhető...
KAMI | 神
--
Támogatás | OxygenOffice | Fordításaim és SeaMonkey
- A hozzászóláshoz be kell jelentkezni
Oooo, ha az elso szamot nem abrazolod, honnet tudja az olvaso, h milyen kodolast olvasott, vagyis mi volt az elso szam?
--
()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.
- A hozzászóláshoz be kell jelentkezni
Itt szájbarágósan leírják. Kiemelem, hogy én csak a rajzolásra koncentráltam egyelőre, nem ellenőrzöm, hogy a beírt vonalkód valóban helyes-e :)
--
A gyors gondolat többet ér, mint a gyors mozdulat.
- A hozzászóláshoz be kell jelentkezni
http://extensions.services.openoffice.org/node/1845
KAMI | 神
--
Támogatás | OxygenOffice | Fordításaim és SeaMonkey
- A hozzászóláshoz be kell jelentkezni
sima barcode csomag segíthet tesztelni, ps-t ír.
echo 566555016040 | barcode -e "ean13" | ps2pdf - kimenet.pdf
- A hozzászóláshoz be kell jelentkezni