What Is the Best Way to Create and Draw a Bar Code?

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.

Save Image to Buffer

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).

I would like to have a memory zone, who contains 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 to Encode Binary Data (2D Codes)

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

Solution:

  • Switch off codepage 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).

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 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);

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).

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.

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, 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 ()

Only characters in the range of 0x8140 - 0x9ffc and 0xe040 - 0xeaa4 in the JIS X 0208 table can be compacted. Shift JIS would also support the Code Pages (High Byte) ED-EE / FA-FC, but this range 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:

Barcode type set to QR-Code
  • 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).
Barcode type is set to QR-Code 2005
  • 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().