All barcode implementations are derived from the abstract glbarcode::Barcode class. The glbarcode::Barcode1dBase subclass of glbarcode::Barcode provides a common framework for the implementation of 1D barcodes. Therefore, creating new 1D barcode types (or symbologies) would be typically accomplished by implementing a subclass of this glbarcode::Barcode1dBase class rather than directly implementing the glbarcode::Barcode class.
Virtual Methods
A 1D barcode subclass must implement the following virtual methods (or callbacks):
- glbarcode::Barcode1dBase::validate() – The validate method is used to test if data is valid for encoding with the intended symbology. This method must only validate data that can be encoded successfully as-is or after processing by the optional glbarcode::Barcode1dBase::preprocess() method.
glbarcode::Barcode1dBase::encode() – The encode method is used to encode data such that it can later be vectorized. The encoded data is usually a list of characters that represent an atomic barcode element. For example, the following is the character encoding used by the Code39 implementation:
Character | Meaning |
N | A narrow bar. |
W | A wide bar. |
n | A narrow space (gap between bars) |
w | A wide space (gap between bars) |
i | Inter-symbol gap |
Other encoding examples can be found in the existing barcode implementations.
- glbarcode::Barcode1dBase::vectorize() – The vectorize method converts the encoded data into a list of Drawing Primitives suitable for rendering. The following protected methods are available to the vectorize implementation to create this list:
A barcode subclass may also need to implement the following virtual methods:
- glbarcode::Barcode1dBase::preprocess() – The preprocess method performs any transformation of the data needed before encoding. This method may be needed to perform a first-pass encoding to translate an extended alphabet into a simpler one. For example, this could be as simple as upshifting lowercase letters into uppercase if the symbology only supports uppercase. It is assumed that the data passed to this method has already been validated with the glbarcode::Barcode1dBase::validate() method.
- glbarcode::Barcode1dBase::prepareText() – The prepareText method performs any transformation of the data needed before it can be displayed.
The following figure illustrates the data flow between these methods, which are called by glbarcode::Barcode1dBase::build():
1D build() data flow
Registering With The Barcode Factory
To be able to register a barcode type with the barcode factory, it must implement a static create method that returns a pointer to a newly allocated barcode:
using namespace glbarcode;
Barcode* BarcodeXxx::create(
void )
{
return new BarcodeXxx();
}
This is used to register the barcode using glbarcode::Factory::registerType:
using namespace glbarcode;
Full Example
As a complete example, the following is the glbarcode++ implementation of a custom barcode type called "mybarcode".
MyBarcode.h:
#ifndef _MyBarcode_h_
#define _MyBarcode_h_
{
public:
private:
bool validate(
const std::string& rawData );
std::string
encode(
const std::string& cookedData );
void vectorize(
const std::string& codedData,
const std::string& displayText,
const std::string& cookedData,
double& w,
double& h );
};
#endif
MyBarcode.cpp:
#include "MyBarcode.h"
#include <cctype>
#include <algorithm>
using namespace glbarcode::Constants;
namespace
{
const std::string alphabet = "0123456789ABCDEF";
const std::string symbols[] = {
"NnNwWnWnN",
"WnNwNnNnW",
"NnWwNnNnW",
"WnWwNnNnN",
"NnNwWnNnW",
"WnNwWnNnN",
"NnWwWnNnN",
"NnNwNnWnW",
"WnNwNnWnN",
"NnWwNnWnN",
"WnNnNwNnW",
"NnWnNwNnW",
"WnWnNwNnN",
"NnNnWwNnW",
"WnNnWwNnN",
"NnWnWwNnN",
};
const std::string frameSymbol = "NwNnWnWnN";
const double N = 2.5;
const double MIN_I = MIN_X;
const double MIN_TEXT_AREA_HEIGHT = 14.0;
const double MIN_TEXT_SIZE = 10.0;
}
{
return new MyBarcode();
}
bool MyBarcode::validate( const std::string& rawData )
{
for ( int i = 0; i < rawData.size(); i++ )
{
char c = toupper( rawData[i] );
if ( alphabet.find(c) == std::string::npos )
{
return false;
}
}
return true;
}
std::string MyBarcode::encode( const std::string& cookedData )
{
std::string code;
code += frameSymbol;
code += "i";
int sum = 0;
for ( int i=0; i < cookedData.size(); i++ )
{
int cValue = alphabet.find( toupper( cookedData[i] ) );
code += symbols[cValue];
code += "i";
sum += cValue;
}
if ( checksum() )
{
code += symbols[sum % 16];
code += "i";
}
code += frameSymbol;
return code;
}
std::string MyBarcode::prepareText( const std::string& rawData )
{
std::string displayText;
for ( int i = 0; i < rawData.size(); i++ )
{
displayText += toupper( rawData[i] );
}
return displayText;
}
void MyBarcode::vectorize( const std::string& codedData,
const std::string& displayText,
const std::string& cookedData,
double& w,
double& h )
{
double dataSize = cookedData.size();
double minL;
if ( !checksum() )
{
minL = (dataSize + 2)*(3*N + 6)*MIN_X + (dataSize + 1)*MIN_I;
}
else
{
minL = (dataSize + 3)*(3*N + 6)*MIN_X + (dataSize + 2)*MIN_I;
}
double scale;
if ( w == 0 )
{
scale = 1.0;
}
else
{
scale = w / (minL + 2*MIN_QUIET);
if ( scale < 1.0 )
{
scale = 1.0;
}
}
double width = minL * scale;
double hTextArea = scale * MIN_TEXT_AREA_HEIGHT;
double textSize = scale * MIN_TEXT_SIZE;
double height = showText() ? h - hTextArea : h;
height = std::max( height, std::max( 0.15*width, MIN_HEIGHT ) );
double xQuiet = std::max( (10 * scale * MIN_X), MIN_QUIET );
double x1 = xQuiet;
for ( int i=0; i < codedData.size(); i++ )
{
double lwidth;
switch ( codedData[i] )
{
case 'i':
x1 += scale * MIN_I;
break;
case 'N':
lwidth = scale*MIN_X;
addLine( x1, 0.0, lwidth, height );
x1 += scale * MIN_X;
break;
case 'W':
lwidth = scale*N*MIN_X;
addLine( x1, 0.0, lwidth, height );
x1 += scale * N * MIN_X;
break;
case 'n':
x1 += scale * MIN_X;
break;
case 'w':
x1 += scale * N * MIN_X;
break;
default:
break;
}
}
if ( showText() )
{
std::string starredText = "*" + displayText + "*";
addText( xQuiet + width/2, height + (hTextArea+0.7*textSize)/2, textSize, starredText );
}
w = width + 2*xQuiet;
h = showText() ? height + hTextArea : height;
}
Now to put it into action.
main.c:
#include "MyBarcode.h"
using namespace glbarcode;
int main( int argc, char **argv )
{
delete bc;
}
This example will produce the following SVG file:
Output of above example 'MyBarcodeExample.svg'