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: May 11, 2015 @ 1:00 p.m. ET / 10:00 a.m. PT One of the languages that have always been supported with the Intel® RealSense™ SDK (Software Developer Kit) is JavaScript, specifically so that web-enabled apps could be created. Come hear from Intel Expert Bob Duffy as he reviews his own little "space shooting" game where the orientation of your face controls the aiming reticle to help teach developers how to write apps and games in JavaScript that can use facial and gesture …

  • You may not realize the complexity you could be creating when developing mobile apps – many companies don't initially. You could be doubling your IT costs for development and delivery; not to mention, risking sales, productivity and brand satisfaction. Read this IBM-commissioned Forrester Study to understand the key cost drivers of mobile app delivery -- for both customer-facing and enterprise applications. Find out how you could lower costs and increase success with the right strategy and investment.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date