EAN13 Barcode Class

This is a lightweight class that prints EAN13 barcodes. It displays captions for the manufacturer and product descriptions as well as the numerical representation of the code.

All initialisation is performed in the following constructors:

CBarcode(CString strCode, CString strText, UINT nNum);
CBarcode(CString strCode, CString strText, CWnd* pWnd);

Parameters

The parameters are self-explanatory:

  • strCode takes a 12-digit numerical string
  • strText takes a newline-separated string that contains both the company and the product captions
  • nNum specifies the number of labels to be printed
  • pWnd takes a pointer to a window into which to draw the image

Under the Bonnet

  • If you are using the printing constructor, the class initialises the default printer on the system, determining the maximum width and height of the printable area based on your defaults in printer settings.
  • The drawing constructor fits the image of the barcode into the client rectangle of the supplied window object.
  • The barcode lines, font size, and margins are all calculated from the above.
  • The code parses the 12-character code into the appropriate EAN13 format.
  • Finally, depending on the constructor, the code either starts the printing process, looping nNum times, or simply draws the image into the client area of the window.

Credits

I outright stole and modified the ConvertToDigitPatterns() function I found on the Net (wtitten in C# by rainman_63). The rest of the code is 'home-grown.'

Usage

  1. Do the inclusion:
    #include "CBarcode.h"
  2. Construct the CBarcode object, e.g.:
    CBarcode bc(L"0123456789123", L"My Company\nThe product", 5);
    or:
    CBarcode bc(L"0123456789123", L"My Company\nThe product",
                GetDlgItem(IDC_SOMEWINDOW));

References

This site gives quite an insight into EAN13 and other barcode structures and standards: http://www.activebarcode.com/codes/ean13.html

EAN13 Barcode Class

The Class Source

#pragma once

class CBarcode
{
   public:
   CBarcode(CString strCode, CString strText, UINT nNum)
   {
      strCode = strCode.Right(12);

      ASSERT(strText.GetLength() > 0);
      ASSERT(nNum > 0);

      if(strCode.GetLength() !=  12)
      {
         AfxMessageBox(L"Invalid code format.",  MB_ICONWARNING);
         return;
      }

      CDC dc;
      CPrintDialog printDlg(FALSE);
      printDlg.GetDefaults();

      if(!printDlg.m_pd.hDevMode)
      {
         AfxMessageBox(L"No printer found.");
         return;
      }

      printDlg.CreatePrinterDC();

      //Attach a printer DC
      dc.Attach(printDlg.GetPrinterDC());

      int nWidth  =  dc.GetDeviceCaps(HORZRES);
      int nHeight =  dc.GetDeviceCaps(VERTRES);

      //Begin a new print job
      dc.StartDoc(AfxGetAppName());

      for(UINT i = 0; i <  nNum; i++)
      {
         dc.StartPage();

         Print(&dc, strCode, strText, nWidth, nHeight);

         dc.EndPage();
      }

       dc.EndDoc();
       dc.Detach();
   }

   CBarcode(CString strCode, CString strText, CWnd* pWnd)
   {
      strCode = strCode.Right(12);

      ASSERT(strText.GetLength() > 0);
      ASSERT(IsWindow(pWnd->m_hWnd));

      if(strCode.GetLength() !=  12)
      {
         AfxMessageBox(L"Invalid code format.",  MB_ICONWARNING);
         return;
      }

      CDC* dc = pWnd->GetDC();
      CRect rc;
      pWnd->GetClientRect(&rc);
      dc->FillSolidRect(rc, RGB(255, 255, 255));
      Print(dc, strCode, strText, rc.Width(), rc.Height());

      pWnd->ReleaseDC(dc);
}

private:
   void Print(CDC* dc, CString strCode, CString strText,
              int nWidth, int nHeight)
   {
      const CString strOddLeft[10] =
        {L"0001101", L"0011001", L"0010011", L"0111101",
          L"0100011", L"0110001", L"0101111", L"0111011",
          L"0110111", L"0001011"};
      const CString strEvenLeft[10] =
         {L"0100111", L"0110011", L"0011011", L"0100001",
          L"0011101", L"0111001", L"0000101", L"0010001",
          L"0001001", L"0010111"};
      const CString strRight[10] =
         {L"1110010", L"1100110", L"1101100", L"1000010",
          L"1011100", L"1001110", L"1010000", L"1000100",
          L"1001000", L"1110100"};
      const CString  strQuiteZone = L"000000000";
      const CString strLeadTail = L"101";
      const CString strSeparator = L"01010";

      int nFontSize = nHeight / 8;
      int nMargin   = nHeight / 15;

      nWidth  -= 2*nMargin;
      nHeight -= 2*nMargin;

      dc->SetMapMode(MM_ANISOTROPIC);
      dc->SetWindowExt(nWidth, nHeight);
      dc->SetWindowOrg(0, 0);
      dc->SetViewportExt(nWidth, nHeight);
      dc->SetViewportOrg(0, 0);

      //    EAN13 Barcode should be a total of 113 modules wide.
      int nLineWidth = nWidth / 113;
      int xStart = nMargin + (nWidth - (nLineWidth * 113)) / 2;
      int xPosition = xStart;

      CFont font;
      font.CreateFont(nFontSize, 0, 0, 0, FW_NORMAL, FALSE,
                      FALSE, 0, EASTEUROPE_CHARSET,
                      OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
                      DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS,
                      L"Arial");
      CFont* pOldFont = dc->SelectObject(&font);
      int nOldBk      = dc->SetBkMode(TRANSPARENT);

      // Calculate the Check  Digit.///////////////////////
      int nSum = 0;
      int nDigit = 0;

      for(int i = 12; i >= 1; i--)
      {
         nDigit = _wtoi(strCode.Mid(i - 1, 1));

         if(i % 2 == 0)
            nSum += nDigit * 3;
         else
            nSum += nDigit * 1;
      }

      CString strCheckSum;
      strCheckSum.Format(L"%i", (10 - (nSum % 10)) %  10);
      strCode += strCheckSum;
      ////////////////////////////////////////////////////

      // Convert the left hand numbers.
      CString strLeftPattern;

      switch(_wtoi(strCode.Left(1)))
      {
         case 0:
            strLeftPattern =
               ConvertToDigitPatterns(strCode.Mid(1, 6), strOddLeft);
            break;
         case 1:
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(0, 1), strOddLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(1, 1), strOddLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(2, 1), strEvenLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(3, 1), strOddLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(4, 1), strEvenLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(5, 1), strEvenLeft);
            break;
         case 2:
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(0, 1), strOddLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(1, 1), strOddLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(2, 1), strEvenLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(3, 1), strEvenLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(4, 1), strOddLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(5, 1), strEvenLeft);
            break;
         case 3:
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(0, 1), strOddLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(1, 1), strOddLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(2, 1), strEvenLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(3, 1), strEvenLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(4, 1), strEvenLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(5, 1), strOddLeft);
            break;
         case 4:
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(0, 1), strOddLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(1, 1), strEvenLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(2, 1), strOddLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(3, 1), strOddLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(4, 1), strEvenLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(5, 1), strEvenLeft);
            break;
         case 5:
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(0, 1), strOddLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(1, 1), strEvenLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(2, 1), strEvenLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(3, 1), strOddLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(4, 1), strOddLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(5, 1), strEvenLeft);
            break;
         case 6:
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(0, 1), strOddLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(1, 1), strEvenLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(2, 1), strEvenLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(3, 1), strEvenLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(4, 1), strOddLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(5, 1), strOddLeft);
            break;
         case 7:
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(0, 1), strOddLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(1, 1), strEvenLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(2, 1), strOddLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(3, 1), strEvenLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(4, 1), strOddLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(5, 1), strEvenLeft);
            break;
         case 8:
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(0, 1), strOddLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(1, 1), strEvenLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(2, 1), strOddLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(3, 1), strEvenLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(4, 1), strEvenLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(5, 1), strOddLeft);
            break;
         case 9:
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(0, 1), strOddLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(1, 1), strEvenLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(2, 1), strEvenLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(3, 1), strOddLeft);
            strLeftPattern +=
               ConvertToDigitPatterns(strCode.Mid(4, 1), strEvenLeft);
            strLeftPattern +=
                ConvertToDigitPatterns(strCode.Mid(5, 1), strOddLeft);
            break;
      }

      // Build the UPC Code.
      CString strEAN13 = strQuiteZone + strLeadTail +
                         strLeftPattern + strSeparator +
                         ConvertToDigitPatterns(strCode.Mid(7),
                                                strRight) +
                         strLeadTail + strQuiteZone;

      // Draw the barcode lines.
      for(int i = 0; i < strEAN13.GetLength(); i++)
      {
         if(strEAN13.Mid(i, 1) == L"1")
         {
            // Save room for the UPC number below the bar code.
            if((i > 12 && i < 55 ) || (i > 57 && i < 101))
               // Draw space  for the number
               dc->FillSolidRect(xPosition, nMargin +
                  (2 * nFontSize), nLineWidth, nHeight -
                  (3 * nFontSize), RGB(0, 0, 0));
            else
                  // Draw a full line.
                  dc->FillSolidRect(xPosition, nMargin +
                     (2 * nFontSize), nLineWidth, nHeight -
                     (2 * nFontSize), RGB(0, 0, 0));
         }

         xPosition += nLineWidth;
      }

      int yPosition = nMargin +  nHeight - nFontSize;

      // Draw 1st digit of the country code.
      dc->DrawText(strCode.Left(1),
         CRect(xStart - dc->GetTextExtent(strCode.Left(1)).cx +
         (7 * nLineWidth), yPosition, xStart + (7 * nLineWidth),
         nHeight + nMargin), DT_CENTER);

      // Draw MFG Number.
      dc->DrawText(strCode.Mid(1, 6), CRect(xStart +
                      (12 * nLineWidth), yPosition, xStart +
                      (55 * nLineWidth), nHeight + nMargin),
                      DT_CENTER);

      // Draw Product ID.
      dc->DrawText(strCode.Mid(7), CRect(xStart + (57 * nLineWidth),
                   yPosition, xStart + (101 * nLineWidth),
                   nHeight + nMargin),  DT_CENTER);

        dc->DrawText(strText, CRect(xStart, nMargin, xStart +
                     (113 * nLineWidth), nMargin + (2 * nFontSize)),
                     DT_CENTER | DT_VCENTER);

      //Restore the DC
      dc->SelectObject(pOldFont);
      nOldBk = dc->SetBkMode(nOldBk);
   }

   CString ConvertToDigitPatterns(CString strInputNumber,
                                  const CString strPatterns[10])
   {
      CString strTemp;
      int nIndex = 0;

      for(int i = 0; i < strInputNumber.GetLength(); i++)
      {
         nIndex = _wtoi(strInputNumber.Mid(i, 1));
         strTemp += strPatterns[nIndex];
      }

      return strTemp;
   }
};


Downloads

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: November 20, 2014 @ 2:00 p.m. ET / 11:00 a.m. PT Are you wanting to target two or more platforms such as iOS, Android, and/or Windows? You are not alone. 90% of enterprises today are targeting two or more platforms. Attend this eSeminar to discover how mobile app developers can rely on one IDE to create applications across platforms and approaches (web, native, and/or hybrid), saving time, money, and effort and introducing apps to market faster. You'll learn the trade-offs for gaining long …

  • Live Event Date: October 29, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Are you interested in building a cognitive application using the power of IBM Watson? Need a platform that provides speed and ease for rapidly deploying this application? Join Chris Madison, Watson Solution Architect, as he walks through the process of building a Watson powered application on IBM Bluemix. Chris will talk about the new Watson Services just released on IBM bluemix, but more importantly he will do a step by step cognitive …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds