What Is the Best Way to Create and Draw a Barcode?

In general we suggest this procedure for the API calls:

  1. Set all bar code properties; type, text, size mode, module width, orientation, DPI, etc.
  2. Call BCCreate() - afterwards do not change any properties.
  3. For linear (non multi row) barcodes choose a desired height (by yourself!)
  4. Prepare the bounding rectangle: Use a default width and your desired height (step 3). Rotate the rectangle if required (exchange width and height for 90/270°).
  5. Retrieve bar code size: BCGetBarcodeSize() - use the prepared (rotated) bounding rectangle (step 4).
  6. Now set width and height of drawing rectangle by using the size values returned in step 5. Also consider orientation here.
  7. Draw the bar code with this rectangle.

Should I Use a Specific Module Width ?

We suggest to use a custom module width whenever possible - adjusting the narrow bar width gives you more control over the output. It also allows you to comply to specific label requirements and to the printer's output resolution. There may be one exception: For postal bar codes, where the bar code size has to be in an exact range, the bounding rectangle may be sufficient.

Example values for the module width (300 dpi compliant):

  • Linear types: 0.254 mm, 0.339 mm
  • PDF417: 0.254mm (row height set to 0.762 mm)
  • 2D Matrix codes: 0.508 mm

For bitmap output the module width may be adapted to bitmap resolution (e.g. 96 dpi). Here you could use the GetOptimalBitmapSize API call.

I Would Like to Have a Memory Zone, Containing the Whole Pixel Map of the Barcode

Instead of drawing directly to a bitmap or printer DC you can build your own data structure (Pixel map) using TBarCode's Callback functionality. You can pass a custom pointer (your pixel map) to the Callback function and add the current pixel pattern to your structure (in a format as desired).

First set the pointer to your structure or memory block with this function:

BCSetCBData(t_BarCode* pBarCode, LPVOID customData)

This pointer is handled to you in the Callback function:

ERRCODE CALLBACK CustomDrawRow (VOID* customData, t_BarCode* barcode, 
HDC drawDC, HDC targetDC, DOUBLE x, DOUBLE y, DOUBLE width, DOUBLE height);

Now you can store the pattern info (row by row) into your own structure or memory block. After drawing has been finished you have it all in your structure.

How Can I Save a Bitmap To Memory

Below is a code sample how to use BCSaveImageToBuffer:

#include "windowsx.h"

// after BCCreate(..)  

// generate image in buffer
LPBYTE lpBuffer;
eCode = BCSaveImageToBuffer (pBarCode, &lpBuffer, eIMBmp, nWidth, nHeight, 96.0, 96.0);

if (eCode == ErrOk)
{
  // lock buffer before reading
  if (GlobalLockPtr(lpBuffer))
  {
    // retrieve size of buffer
    int nSize = GlobalSize((HGLOBAL)GlobalHandle(lpBuffer));

    // process buffer
    for (int i=0; i< nSize; i++)
    {
      BYTE byte = (static_cast<LPBYTE> (lpBuffer))[i];
      // ...
    }

    // unlock after reading (required)
    GlobalUnlockPtr(lpBuffer);
  }

  // free memory (required)
  GlobalFreePtr(lpBuffer);
}

Alternative API Functions

ERRCODE BCBitmapToMemory (t_BarCode *pBarCode, VOID *pHandle, LPCSTR pszFormat, 
INT *pnSize, LPCRECT pRect)

Writes barcode in an image format to memory block. Does not require global heap memory (=is faster) but does not render the HRT.

How to Encode Binary Data (2D Codes)

Even if you use an escape sequence for binary data the encoder will use code page conversion (example: \x88 leads to a different value in Data Matrix as desired).

Solution:

  • Switch off code page conversion (use encoding mode LowByte)
  • Force binary encoding mode if available (see PDF417 encoding mode, Data Matrix EnforceBinaryEncoding)
Relevant for DP Premium Address and other applications where you encode binary data in a 2D symbol (Data Matrix etc).

Force C40 Mode in Data Matrix

By default the encoding scheme in Data Matrix is selected automatically for you (based upon input data analysis). If you need C40 mode for any reason, you can pre-select it with the following bar code options string:

BCSetOptions (pBarcode, "DataMatrix_EncodingMode=3");

The mode parameters are as follows: 0 .. optimal, 1 .. enforce binary, 2 .. prefer ASCII, 3 .. prefer C40.

Useful Links:

  • The API is installed in the Help File ⟶ C:\Program Files\TEC-IT\TBarCode11\Documentation ⟶ TBarCode DLL 11 Developer Reference.chm
  • An online API can be found in the TBarCode Library 11.

How to Use Macro 06 in a Data Matrix

Example: You want to encode the following data into a Data Matrix symbol with 26x26 modules (the data below contains already the escape sequences for the GS, RS and EOT):

[)>\x1e06\x1dY2004010400000XY\x1dP13590636​\x1d12V688438456\x1dLSYYDDD000000000\x1e\x04

Problem

That doesn't fit into the 26x26 matrix. The capacity of the 26x26 symbol is 88 numeric or 64 alphanumeric characters. But here we have a mixture of alphanumeric, some special and non-printable characters (GS, RS, EOT) in the data string. By default, we don't use macro mode, which would also save space.

Alphanumeric characters or a sequence of digits can be encoded more efficiently than an ASCII character in the non-printable range (ASCII 00 - 20) - see also Modes C40, TEXT, Digit pairs and BASE256.

Solution

You can use the Macro 06 mode to save space in the symbol:

BCSet_DM_Format (pBarCode, eDMPr_Macro06)

After enabling the Macro 06, set the barcode data as follows (without header and trailer):

[)>\x1e06\x1d Y2004010400000XY\x1dP13590636​\x1d12V688438456\x1dLSYYDDD000000000 \x1e\x04

Result: In the data stream, a header of [)> + RS + 06 + GS and a trailer of RS + EOT will be inserted automatically by the bar code reader (no need to set this in the encoded data). This will fit into the 26x26 matrix because with Macro 06 the encoder does not need as much space / internal code words as without.

How to Use Custom Drawing (Callback) in VB

TBarCode V6

'callback function
Public Function MyDrawRow ( ByRef pMyData As Long, 
          ByVal pBarCode As UIntPtr, ByVal hDC As IntPtr, 
          ByVal hTargetDC As IntPtr, 
          ByRef pRect As Rectangle) As UInt32
   Dim strTempo As String
   strTempo = TBC6.BCGetMetaData(pBarCode)
   Return Convert.ToUInt32(0)
End Function

'setting the address of the callback function 
Public cb As TBC6.Callback
   cb = AddressOf MyDrawRow
   eCode = TBC6.BCSetFuncDrawRow(hBarcode, cb, pData)

'required declarations 
Declare Ansi Function BCDrawCB Lib "TBarCode6.ocx" ( _
          ByRef hBarcode As UIntPtr, _
          ByVal hDC As IntPtr, _
          ByRef pRect As Rectangle, _
          ByVal func As Callback, _
          ByVal func As Callback, _
          ByVal pData As IntPtr ) As Int32

Declare Ansi Function BCGetMetaData Lib "TBarCode6.ocx" ( _
           ByVal hBarcode As UIntPtr ) As String

Drawing to Bitmap-DC and Scaling to Screen-DC

DrawBarcode (HDC hDC, long xpos, long ypos)
{
    RECT  hRect;
    long  lHRHeight = 0;

    ypos += GetFullHeight();
    hRect.left     = xpos;
    hRect.top      = ypos;
    hRect.right    = hRect.left   + width;
    hRect.bottom   = hRect.top    + height;

    HDC memDC;
    HBITMAP memBMP, oldBMP;
    int width, height;
    RECT draw;

    width = abs(hRect.right - hRect.left);
    height = abs (hRect.bottom - hRect.top);

    draw.left = 0;
    draw.bottom = height;
    draw.top = 0;
    draw.right = width;

    memDC = CreateCompatibleDC(hDC);
    memBMP = CreateCompatibleBitmap(hDC, width, height);

    oldBMP = (HBITMAP) SelectObject(memDC, memBMP);

    if (S_OK = BCDraw(pBarcode, memDC, &draw))
    {
        // scale / copy to target DC      
        BitBlt(hDC, hRect.left, hRect.top, width, height, memDC, 0, 0, SRCCOPY);
        SelectObject(memDC, oldBMP);
    }      
    DeleteObject(memBMP);
    DeleteDC(memDC);
}

How Can I Get a Bitmap with Optimal Size?

The function BCGetOptimalBitmapSize () returns the optimal size for a bitmap depending on scale factor and adjusted DPI. Please check out the TBarCode Library (DLL) Reference for details.

How Can I Create a Bitmap With a Specific Module Width?

In the code below you just set the module width in[mm] and the total bar code height in[mm]. Via the optimizeToDPI flag you can add also an optimization to the module width (in fact you get the same result as with BCGetOptimalBitmapSize). The sample code is for linear bar codes, but can be adapted to 2D codes as well.

Call this after BCCreate (..)

double moduleWidthUserMM = 0.26;
double heightUserMM = 22.0;
double dpi = 600;
int widthUserPx  = 1; // dummy value, since the width of the bar code is determined by the module width
int heightUserPx = dpi * heightUserMM / 25.4;  // for bitmaps we need [Pixel]
double width, height;
bool optimizeToDPI = TRUE; // adapt module width to next lower full Pixels => avoid quantization errors
int fontSizePt = (int)(0.51 + (10 * moduleWidthUserMM / 0.339)); // auto font size - works well with EAN / Code-128 / Code 39

// bounding rectangle of barcode -> desired drawing coordinates
RECT rect;
rect.left = 0;
rect.right = widthUserPx;
rect.top = 0;
rect.bottom = heightUserPx;

eCode = BCSetDPI(pBarCode, dpi, dpi);
eCode = BCSetIgnoreDpiFromDC(pBarCode, TRUE);

// Ensure that the width of a bar is a multiple of a single pixel (and at minimum one pixel)
eCode = BCSetOptResolution(pBarCode, optimizeToDPI);

// bar code should adapt to module width
eCode = BCSetSizeMode(pBarCode, e_SizeMode::eSizeMode_CustomModuleWidth);

// set module width in [0.001mm]
// we need a rounding delta of 0.001mm in case of optimize flag
eCode = BCSetModWidthN(pBarCode, moduleWidthUserMM * 1000 + (optimizeToDPI?1:0));

eCode = BCSetFontHeight(pBarCode, fontSizePt);

// Calculate bar code size
// for retrieving the size in [Pixel] we need a screen hDC
HDC hDC = GetDC(NULL);
eCode = BCGetBarcodeSize(pBarCode, &rect, hDC, eMUPixel, &width, &height);
if (hDC)
  DeleteDC(hDC);

// Save bitmap with the given module width and size
eCode = BCSaveImage(pBarCode, "C:\\Temp\\Barcode-600dpi.jpg", eIMJpg, int(width + 0.5), (int)(height + 0.5), dpi, dpi);
Because of the optimize flag enabled, with a given module width of 0.26 mm the resulting module width will be 0.254 mm (6 Pixels @600 dpi).

How Can I Generate a Bitmap Output with Anti-Aliased Font Rendering?

Adjust the Proper DC

Use the following screen DC to create font rendering with anti-aliasing options (as adjusted for the Screen):

HDC dc = CreateDC(TEXT("DISPLAY"),NULL,NULL,NULL);
eCode = BCSaveImageEx(m_pbarCode, dc, file, imageType, 100, widthPx, heightPx, dpi, dpi );

if (dc)
    DeleteDC(dc);

Adjust the Proper Font (LOGFONT)

Use the Windows standard font dialog or the following function to retrieve a pre-initialized LOGFONT structure from Windows GDI:

HFONT hSystemVariableFont = (HFONT ) GetStockObject( ANSI_VAR_FONT );
LOGFONT lfSystemVariableFont;
GetObject ( hSystemVariableFont, sizeof(LOGFONT), &lfSystemVariableFont );

// Make sure that the following flags are set in the LOGFONT structure passed to BCSetLogFont():

lfOutPrecision (e.g. set to 3)
lfClipPrecision (e.g. set to 2)
lfQuality (e.g. set to 1)
lfWeight (e.g. set to 400)

lfFaceName should be set to a True Type font (e.g. “Arial”)

// Calculate the font height as follows:
lfHeight = = -MulDiv( 10 /*PointSize*/, GetDeviceCaps(hDC, LOGPIXELSY), 72);

How to Draw the Barcode with Different DPI in X and Y Axis?

The barcode generator library does not support bitmap export with anisotropic resolution (DPI Y != DPI X). Whenever we have to create our own DC, we create it “isotropic” (DPI Y = DPI X). But there are workarounds as shown below.

Note that the limit with DPI X/Y is only for creating/saving a bitmap with the bitmap functions or when we draw with IgnoreDPIfromDC. For drawing to a printer DC or an arbitrary DC passed from “outside” to the BCDraw(..) or Draw (gfx) function, an anisotropic resolution is supported. In short: It works if the DPI is already set directly in the device context and when we just draw on the given DC (no bitmap export in our library).

Workarounds:

Example - you need DPI X = 1200, DPI Y = 600

A) Anisotropic Device Context

  • Use BCDraw (hDC) with a device context, where DPI X = 1200 and DPI Y = 600 is already preset to these values.
  • Use Draw(gfx) with a graphics object, where the internal DC is preset to DPI X = 1200 and DPI Y = 600.
  • Either don’t call BCSetDPI or use BCSetDPI (pBarcode, -1, -1) ➔ resets the Library DPI to DC default values.
  • Don’t set BCIgnoreDPIFromDC because we need the values from the DC or graphics object.
  • If you need the bar code image in a bitmap file, you have to create it with your own code from the drawn image in memory.

B) Scale the Image

C/C++ Library

First draw to a bitmap DC with 1200 x 1200 dpi (isotropic) and later scale the image in the Y-axis to 50% = 600 dpi to get your anisotropic result.

  • You could use the code from FAQ Drawing to Bitmap-DC and Scaling to Screen-DC as basis.
  • When copying the image, use StretchBlt instead of BitBlt to achieve the scaling of the Y-axis (use an ROP and Stretch Mode, which does not create aliasing or softened edges)
    - https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-stretchblt
    - https://learn.microsoft.com/en-us/windows/win32/gdi/scaling-an-image
  • Let TBarCode draw with a high resolution even on a low resolution screen DC:
    If your Bitmap DC is based upon screen resolution (~ 96 dpi), but you want 1200 dpi or something else, you can use the API function BCSetIgnoreDPIFromDC (pBarcode, TRUE) - set it before BCDraw - in combination with BCSetDPI (pBarCode, 1200, 1200). This draws a high resolution bitmap by internally scaling the barcode drawing coordinates. Note that DPI X and DPI Y must be equal here, the target bitmap DC must be large enough to hold the full picture (take care on width/height). The same works also in .NET with similar API functions.

If you need a BMP/JPG/PNG file from your image in memory, you have to use additional bitmap export code (free libraries and sample code publicly available on the web).

.NET API

If you use our .NET API you can do something similar as with StretchBlt (GDI) with the DrawImage() function. First create a “normal” Barcode bitmap and then stretch it or change the DPI – see sample code (or google for more):

C) Custom Drawing

Use our Callback drawing mechanism. You get all the coordinates – either in Millimeters or in a matrix pattern (row pattern). Then you decide on your own, how you scale the X and Y axis coordinates you receive from the library. You receive coordinates in 1/1000 mm resolution from the library and can convert it to Pixel with your own code (and apply your own DPI to X and Y axis). Then draw to a Bitmap DC (GDI Filled Rectangle) or use a Graphics library, which does the work for you (e.g. NET).

Sample code for Custom Drawing (installed with the SDK):

C:\ProgramData\TEC-IT\TBarCode\11.15\Examples\Visual C++\Custom Drawing
C:\ProgramData\TEC-IT\TBarCode\11.15\Examples\Visual Studio .NET\CustomDrawing

More details:

Callback drawing is available in the native C/C++ DLL and also in the .NET API (see sample above).

Change Barcode Font Style in Delphi

Create a LOGFONT structure and set it with the BCSetLogFont function.

Function BCSetLogFont
(
  const pBarCode:t_BarCode; // IN : Ptr To Barcode-Definition
  lf:LOGFONT  // IN : TLogFont (TFont) structure
):TErrCode; 
external 'TBarCode8.dll';

Here is a sample of a LOGFONT structure. To adjust the font size, you must change the parameter lfHeight in the structure.

var
  lf:TLogFont;
begin
  lf.lfHeight := 24;          {char height in pixels    }
  lf.lfWidth := 12;           {char width in pixels     }
  lf.lfEscapement := 0;       {orientation of next char }
  lf.lfOrientation := 0;      {orientation of first char}
  lf.lfWeight := FW_NORMAL;   {normal thickness         }
  lf.lfItalic := 0;           {not italic characters    }
  lf.lfUnderline := 0;        {not underlined characters}
  lf.lfStrikeOut := 0;        {not strikeout characters }
  lf.lfCharSet := OEM_CHARSET;{OEM character set        }
  lf.lfOutPrecision := 0;     {default output precision }
  lf.lfClipPrecision := 0;    {default clipping precision}
  lf.lfQuality := DEFAULT_QUALITY; {default scaling quality}
  lf.lfPitchAndFamily := FF_SCRIPT;{default pitch,
                                    script font family   }
  lstrcpy(lf.lfFaceName,'Arial'+chr(0)); {script typeface}

For more information about LOGFONT visit http://msdn.microsoft.com/en-us/library/ms533931(VS.85).aspx

How Can I Use TBarCode Within Java?

We can offer you TBarCode DLL in combination with a Java wrapper using JNI. The currently supported API implements all common functions of TBarCode DLL and can be extended on demand.

The image output functions relevant for web applications are:

public void saveImage(String sFileName, int nType, int nHeight, int nWidth, int nQual)
      throws TBarCodeException

public InputStream saveImage(int nType, int nHeight, int nWidth, int nQual)
      throws TBarCodeException

You can use them for web applications to stream bar code images to the browser.

If interested, we can email you the TBarCode/Java project for testing. The actual version runs on Windows platforms (Linux/UNIX on request).

How Can I Add a Bearer Bar to ITF-14?

The bearer bar shape and size depend on the printing surface and the application. The possible sizes for module width, bar code height and bearer bar can be found in the GS1 specification Figure 5.3.6-1.

To maintain a minimum quiet zone of 10 times the module width, the left and right quiet zones must be adjusted in the TBarCode API, taking into account the bearer bar size.

Below we show two cases with different dimensions of the bar code and bearer bar:

Top and Bottom Bearer Bars

ITF-14 can be drawn with a top + bottom bearer bar if you use labels (no printing plates). In this case the bearer bar can be smaller, but must be at least 2 times the module width.

BCSetBCType(m_pbarCode, eBC_ITF14);

// #1 print on label

// 203 dpi ➞ Module Width = 0.5005 mm = 4 Pixel per Module
double const dModuleWidth = 0.5004926F; // use exact value

// 300/600/1200 dpi ➞ Module Width = 0.508 mm
// double const dModuleWidth = 0.508F;

BCSetModWidthN(m_pbarCode, dModuleWidth * 1000); // set in 0.001 mm units

double const dModulesBearerBar = 2.0F; // 2 times the module width
BCSetBearerBarType(m_pbarCode, eBearerBar_TopAndBottom);
BCSetBearerBarWidth(m_pbarCode, static_cast<int> (dModulesBearerBar * dModuleWidth * 1000)); // set in 0.001 mm units

RECTD QZRect = { 10, 0, 10, 0 };
BCSetQuietZone(m_pbarCode, &QZRect, eMUModules);

eCode = BCSetText(m_pbarCode, szText, szText.GetLength());

if (eCode == S_OK)
  eCode = BCCreate(m_pbarCode); // create internal bar code structure (MUST)

Rectangular Bearer Bar

For direct carton printing, the bearer bar must be rectangular and of a certain size, in which case the barcode size should also be enlarged.

// #2 print on carton

// for rectangular bearer bar having a width of 4.83 mm

// 203 dpi ➞ Module Width = 1.000 mm = 8 Pixel per Module
double const dModuleWidth = 1.0F;

// 300/600/1200 dpi ➞ Module Width = 1.016 mm
//double const dModuleWidth = 1.016F;

BCSetModWidthN(m_pbarCode, dModuleWidth * 1000); // set in 0.001 mm units

double dBearerBarWidth = 4.83F;
double dModulesBearerBar = ceil(dBearerBarWidth / dModuleWidth);
BCSetBearerBarType(m_pbarCode, eBearerBar_Rectangle);
BCSetBearerBarWidth(m_pbarCode, static_cast<int> (dBearerBarWidth * 1000)); // set in 0.001 mm units

RECTD QZRect = { 10 + dModulesBearerBar, 0, 10 + dModulesBearerBar, 0 };
BCSetQuietZone(m_pbarCode, &QZRect, eMUModules);

Encoding Kanji Characters in QR Code® Compaction Mode

The following information applies to QR-Code Model 2 as defined in AIM International ITS/97-001 and ISO/IEC 18004:2000. It does not apply to the new QR Code 2005 as introduced in ISO/IEC 18004:2006 (or later).

Data for QR-Code can be treated either as a sequence of Bytes or as a sequence of SHIFT JIS characters.

Beside SHIFT JIS so-called “ECIs” can be used to switch to different Code-Pages - but ECIs are often unsupported by decoder software.

The default character set of QR-Code is Shift JIS. In order to use the QR-Code Kanji Compaction Mode (more efficient), the input for the encoder must be in a specific character set:

TBarCode DLL V7, TBarCode/X Library Version 7

Input must be in Multi Byte Character Set Format SHIFT JIS (not UTF-8, not Unicode!).

  • Single Bytes characters are encoded according to JIS X 0201.
  • Double Byte characters are encoded according to Shift JIS X 0208.

TBarCode DLL V8, TBarCode/X Library Version 8 (and later)

Input must be in Unicode (UTF-16 in Windows Version and UTF-32/UCS-4 in Linux/UNIX Version).

Double Byte characters contained in the Shift JIS X 0208-1990 table can be compacted in QR-Code 13-Bit Mode. To enable the compaction in the TBarCode Library you have to call the function

BCSet_QR_KanjiChineseCompaction (pBarcode, eQRMBCompactionKanji)

Only characters in the range of 0x8140 - 0x9ffc and 0xe040 - 0xeaa4 from the JIS X 0208 table can be compacted. The SHIFT JIS range (High Byte) ED-EE / FA-FC is not supported by QR-Code compaction - these codes will be treated as normal Bytes.

Here are some links to background information about Kanji and Unicode:

How to Encode UTF-8 in a QR-Code

By default TBarCode V9 (and later) will use the following encoding:

Default Encoding QR-Code JIS (AIM ISS QR Code 1997)
  • BCSetTextA treats input data as ANSI ASCII (Latin-1). This character set is converted to SHIFT-JIS to be QR-Code compatible. Some Latin-1 characters may be lost in this conversion.
  • BCSetTextW treats input data as Unicode. This data is converted to SHIFT-JIS, too (characters not part of SHIFT-JIS may be lost).
Default Encoding QR-Code (ISO/IEC 18004:2015)
  • BCSetTextA treats input data as ANSI ASCII (Latin-1). This character set is converted to Latin-1.
  • BCSetTextW treats input data as Unicode. This data is converted to Latin-1 (characters not part of Latin-1 may be lost).

If you want to encode data in UTF-8 format, then use BCSetCodePage (pBarCode, eCodePage_UTF8). For non Latin-1 characters use BCSetTextW with Unicode to be sure that all characters can be encoded without loss.

If you want to encode binary data or your own data “as is” (no conversion applies) use: BCSetEncodingMode (pBarCode, eEncMode_LowByte ) with BCSetTextA().

How To Create a Structured Append QR Code

Example, if you have a base64 string, which you want to encode with several QR-Codes linked together, follow these steps:

  • Divide the base64 string into manageable sub-strings. The upper limit for a sub-string size is around 2,000 characters, but it depends on factors like scanner capabilities, available space, and print resolution. Generate a separate QR Code for each sub-string.
  • Set the Structured-Append Header in each QR Code, specifying the total number of concatenated codes, the current index, and the parity byte. Calculate the parity byte over the entire string, not per individual code. The Structured-Append Header helps the scanner determine how many QR Codes need to be read and whether the data is correct.

Below is a sample C++ function for saving a QR Code with an Append Header:

ERRCODE SaveStructAppendQRCode(LPCSTR path, LPCSTR dataStr, int dataLen, int count, int index, BYTE parity)
{
  ERRCODE eCode = ErrOk;
  t_BarCode* pBarCode = NULL;   // barcode handle
  double const dpi = 300;
  RECT rect = { 0,0,255,255 };

  if (eCode == ErrOk)
    eCode = BCAlloc(&pBarCode);
  if (eCode == ErrOk)
    eCode = BCSetBCType(pBarCode, eBC_QRCode);
  if (eCode == ErrOk)
    eCode = BCSet_QR_Append(pBarCode, count, index, parity);
  if (eCode == ErrOk)
   eCode = BCSetTextA(pBarCode, dataStr, dataLen);
  if (eCode == ErrOk)
    eCode = BCCreate(pBarCode);

  if (eCode == ErrOk)
    eCode = BCSetDPI(pBarCode, dpi, dpi);
  if (eCode == ErrOk)
    eCode = BCSetIgnoreDpiFromDC(pBarCode, TRUE);
  if (eCode == ErrOk)
    eCode = BCSetSizeMode(pBarCode, e_SizeMode::eSizeMode_FitToBoundingRect);
  if (eCode == ErrOk)
    eCode = BCGetOptimalBitmapSize(pBarCode, &rect, 3, 3);

  if (eCode == ErrOk)
    eCode = BCSaveImageA(pBarCode, path, eIMBmp, rect.right, rect.bottom, dpi, dpi);
  // use BCSaveImageEx for color bitmap

  if(pBarCode)
    BCFree(pBarCode);

  return eCode;
}

Next, you create individual QR Codes with Structured Append Headers as shown below:

  ERRCODE eCode = ErrOk;
  const char* base64Str = "Your base64 string goes here...";
  int base64Len = strlen(base64Str);

  if (base64Len > 400)
  {
    BYTE parity = BCCalcStructApp_ParityA(base64Str, base64Len);

    if (eCode == ErrOk)
       eCode = SaveStructAppendQRCode("c:\\temp\\qrcode_3-1.bmp", &base64Str[0], 200, 3, 1, parity);
    if (eCode == ErrOk)
      eCode = SaveStructAppendQRCode("c:\\temp\\qrcode_3-2.bmp", &base64Str[200], 200, 3, 2, parity);
    if (eCode == ErrOk)
      eCode = SaveStructAppendQRCode("c:\\temp\\qrcode_3-3.bmp", &base64Str[400], base64Len - 400, 3, 3, parity);
  }

  if (eCode != ErrOk)
  {
    char szErr[255];
    BCGetErrorText(eCode, szErr, 255);
    printf(szErr);
  }
In the provided code, a loop for dynamically calculating the number of symbols and iterating through the base64 string is omitted for simplicity. Instead, it uses fixed sub-strings of 200 characters each with a total of 3 symbols in the chain. Make sure to adapt this as needed.
  • Adjust the size of the barcode or the size of a matrix point using the ScaleX and ScaleY parameters in the BCGetOptimalBitmapSize(..) function.
  • BCSaveImage(..) generates a monochrome BMP. For a color BMP, use BCSaveImageEx(..) or use the BitmapToFile(..) function.
Note that testing Structured Append QR Codes may require a scanner capable of correctly decoding them. Some apps or hardware scanners may not support Structured Append.

How to Encode Chinese Characters in Han Xin Code?

Han Xin Code provides a special support for encoding Chinese characters with character set GB18030 (using 2 -4 bytes depending on character).

Usage in TBarCode Library:

Using Unicode input:

  • Switch the Codepage to GB18030 with BCSetCodePage
  • Provide the characters in Unicode format* with BCSetTextW
    ∗UTF-16 on Windows, UTF-32 on Linux, but no UTF-8 (!)
  • Unicode input will be converted to GB18030 format for the barcode

Example:

BCSetCodePage(pBarCode, e_CodePage::eCodePage_GB18030);
WCHAR unicode[] = L"数"; /*Unicode U+6570*/
BCSetTextW(pBarCode, unicode, wcslen(unicode));

⇒ Barcode will contain the GB18030 Byte sequence CA FD. A barcode reader should read this as 数.

Using GB18030 input:

  • Disable Codepage conversion with BCSetEncodingMode (pBC, eEncMode_LowByte or eEncMode_ByteStream)
  • Provide the GB18030 characters as Byte sequence with BCSetTextA
  • The Bytes are encoded “as is” without any further conversion.

Example:

BCSetEncodingMode(pBarCode, eEncMode_ByteStream);
unsigned char bytes[] = { 0xCA, 0xFD };  /* GB18030 数 CAFD */
BCSetTextA(pBarCode, (LPCSTR) bytes, sizeof(bytes));

⇒ A barcode reader should read this as 数

More resources:

How is the Bar Width Reduction Applied to a 2D Matrix Code?

In Standard Mode, the bar width reduction is applied to each side at 50% of the desired total reduction. If you want to apply the reduction only to the bottom and right side of the matrix dot, use the Legacy Options as shown below.

Standard Mode (Default)

Default Mode
  • 4 Pixel / module
  • Bar width reduction = 50% → 2 Pixel
  • Options: No legacy option set
  • We reduce 1 Pixel at each side of a dot or a connected line of dots.
Note: If you adjust a BWR of 25% at 4 Pixel module width (⇒ 1 Pixel reduction), the module would be “shaved” ½ Pixel at each side. Because you can draw only full Pixels, this combination cannot be drawn correctly.

Legacy Mode 1

BWR Legacy Mode 1
  • 3 Pixel / module
  • Bar width reduction = 33% → 1 Pixel
  • Options: DRAW_BarWidthReduction_Legacy=1
  • We reduce 1 Pixel at right and bottom of each dot, also of connected dots.

Legacy Mode 2

BWR Legacy Mode 2
  • 4 Pixel / module
  • Bar width reduction = 25% → 1 Pixel
  • Options: DRAW_BarWidthReduction_Legacy=2
  • Connected dots are not reduced.
  • We reduce 1 Pixel at right and bottom of each dot or connected line of dots.

How Can I Improve Speed with Save Image?

To speed up the printing of the barcodes, the following options are suggested:

BCBitmapToMemory

Instead of BCSaveImageToBuffer you can use BCBitmapToMemory which should be faster. For more information see API Reference - BCBitmapToMemoryA .

Note that BitmapToMemory does not support font rendering and also uses a different unit when passing the size. If you receive the error code for insufficient memory (eErr_OutOfMemory), increase the buffer size (use the returned *pnSize value) and call the function again. The size of the created bitmap has an influence on the speed as well (but not that much).

Draw Mode

You can change the draw mode to "compatible", which should result in significantly better performance. For more information see API reference - BCSetDrawModeExt .

However, the "compatible" drawing mode sometimes produces enlarged bars/dots (or the opposite), the deviation is 1 pixel. This draw mode uses the GDI Rectangle function – it depends on the graphics/video driver and also on the printer driver if the bars are drawn correctly. In about 90-95% of the use cases the resolution does not matter (the deviation of 1 pixel can be ignored with a 1200 dpi printer), but with low-resolution bitmaps, 1 pixel is already a lot. For this reason, testing is important.

Set this before you call BCDraw or BCSaveImage:

BCSetDrawModeExt (pBarCode, eDrawMode_Compatible);
The draw mode is also available in the .NET Library (GDIDrawMode).

Multi-Threading

For multithreading you should consider also these hints:

How Can I Improve the Speed For Multi-Threading?

There are Critical Sections in BCInitLibrary, DeInitLibrary, BCLicenseMe and BCInitDLL. These are required for initialization of static arrays or copying data. There are also exclusive resources locked (but only briefly) in BCCreate and BCCheck.

Steps to improve speed:

  • Call BCInitLibrary and BCLicenseMe only one time at the beginning of the process – not for each bar code creation!
  • Per thread: Use the sequence BCAlloc/…/BCCreate/../BCFree for every single bar code creation.
  • Per bar code creation (inside of one thread): If you want to create another bar code with different data but the same bar code properties, there is no need for another BCAlloc/../BCFree sequence (that only costs time). Just change the barcode data with BCSetText, recreate the bar code with BCCreate and then draw it.
  • BCCheck can be omitted, it is not required with this scenario (since barcode data is also checked in BCCreate).
  • The internal memory allocation is more effectively used, if you set barcode data immediately before calling BCCreate(..).