Click here to Skip to main content
14,268,822 members

Reading Barcodes from an Image - III

Rate this:
4.87 (119 votes)
Please Sign up or sign in to vote.
4.87 (119 votes)
19 Oct 2009CPOL
Detects Code39, EAN, and Code128 barcodes in an image.



This project is based on the CodeProject article: Reading Barcodes from an Image - II by qlipoth. I asked and got permission from qlipoth to publish an enhanced version of his code.


My company has a need for reading barcodes from images that also contain text on the same page as the barcode(s). When searching for a solution in C#, I found qlipoth's CodeProject article: Reading Barcodes from an Image - II. His code came a long way towards what I wanted, but I needed a few improvements. In the end, my changes amounted to a significant rewrite that justifies a new CodeProject publication.


This code has several improvements compared to the original code written in 2005:

  1. Validation is added for Code39 barcodes. The code has much less chance of detecting a "barcode" that is not actually present.
  2. Detection speed is improved. The main problem in the original project was that it used Bitmap.RotateFlip, and that function is quite slow.
  3. Added EAN/UPC and Code128 barcode support. The original project could only detect Code39 barcodes.
  4. Fixed some bugs that were reported for qlipoth's project and for the related project Reading Barcodes from an Image published by Benjamin Liedblad in 2004.

Using the code

To open the solution, you'll need Visual Studio 2008. However, I have not used any constructs that are not .NET 1.1 compatible, so the actual code should also be compilable in Visual Studio 2003 or 2005.

To use the code, call FullScanPage or ScanPage with the Windows Bitmap object containing your image. The included TestApp (written in VB.NET) demonstrates the basic use:

Dim barcodes As New System.Collections.ArrayList
BarcodeImaging.FullScanPage(barcodes, Me.PictureBox1.Image, 100)
If barcodes.Count > 0 Then
  ' Found one or more barcodes ...

The numscans parameter in both functions indicates how many bands of pixels should be scanned across or down the image. With a higher number, the code finds more barcodes, but of course, will also run slightly slower. Usually 50 - 100 scans will be OK to find all barcodes on a full page image.

Difference between FullScanPage and ScanPage

FullScanPage always scans horizontally and vertically, and attempts to detect all supported barcode types. If you know that your input material is always scanned in the same orientation, or if you do not need detection of all barcode types, you can make your program run faster by using ScanPage.

public static void ScanPage(ref System.Collections.ArrayList CodesRead, 
       Bitmap bmp, int numscans, ScanDirection direction, BarcodeType types)

With the additional parameters direction and types, you can fine-tune barcode detection:

  • direction: can be ScanDirection.Vertical or ScanDirection.Horizontal. Use Vertical for detecting barcodes with vertical bars, or Horizontal if you expect barcodes that are rotated 90 degrees.
  • types: Pass BarcodeType.All to detect all supported barcode types, or you can specify one or more specific barcode types, like this:
    ScanPage(ref CodesRead, bmp, numscans, ScanDirection.Vertical,
             BarcodeType.Code39 | BarcodeType.Code128);

    Supported types are Code39, EAN, and Code128. The EAN reader will also detect UPC codes.

Points of interest

  • The EAN reader also reads the 2 or 5 digits supplemental barcodes often found on books and periodicals. As shown in the screenshot, a supplemental barcode will be returned as a separate barcode string starting with "S".
  • The Code128 reader has mixed code page support. The serial number in the sample image Code128test-CodeC.png starts as Code C, but the last digit is added as Code B.
  • The code uses a more advanced approach for measuring the "narrow bar width" than qlipoth's and Liedblad's versions. This should allow for better detection rates when reading EAN and Code128. In Code39, we only need to distinguish between narrow and wide bars, but the other barcode types use four different bar widths.
  • I have added the concept of "barcode zones", to allow detection of differently scaled barcodes on the same scan line. In Code128test-CodeC.png, this enables the software to read both the serial number and the UPC code that are printed side-by-side.

    barcode zones


I used the following references while writing this project:

  1. For implementing EAN detection: Wikipedia articles on the European Article Number, EAN-2, and EAN-5.
  2. For implementing Code 128: the character table and checksum calculation as published on, and the barcode generator published by Inc., for testing.


  • October 5, 2009: Original.
  • October 19, 2009: Improved Code39 detection, bugfixes. Added VB.NET translation of the barcode detection class and the COM interface provided by Alessandro Gubbiotti.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Berend Engelbrecht
Software Developer (Senior) Decos Software Engineering BV
Netherlands Netherlands
No Biography provided

Comments and Discussions

GeneralReading Barcodes : some doubt ... Pin
beguroto2-Nov-09 22:17
memberbeguroto2-Nov-09 22:17 
GeneralRe: Reading Barcodes : some doubt ... Pin
Berend Engelbrecht3-Nov-09 6:26
memberBerend Engelbrecht3-Nov-09 6:26 
GeneralBar widths Pin
supercat928-Oct-09 12:22
membersupercat928-Oct-09 12:22 
GeneralRe: Bar widths Pin
Berend Engelbrecht28-Oct-09 13:03
memberBerend Engelbrecht28-Oct-09 13:03 
QuestionPossible to integrate scew angle? Pin
infal23-Oct-09 4:14
memberinfal23-Oct-09 4:14 
AnswerRe: Possible to integrate scew angle? Pin
Berend Engelbrecht23-Oct-09 22:25
memberBerend Engelbrecht23-Oct-09 22:25 
GeneralRe: Possible to integrate scew angle? Pin
infal24-Oct-09 6:54
memberinfal24-Oct-09 6:54 
GeneralRe: Possible to integrate scew angle? [Modified: proposed strategy for detecting skewed/rotated barcodes] Pin
Berend Engelbrecht24-Oct-09 7:05
memberBerend Engelbrecht24-Oct-09 7:05 
Dear Alexander,

I have fixed my problem with saving multipage tiffs by re-implementing the part that saves multi-page TIFFs in .NET/GDI+. I based my code on this sample by Bob Powell:
Adding frames to a Multi-Frame TIFF[^]
I am happy with the solution, because it not only solved my problem, but also saving is now faster and the output files are more compact when GDI+ is used.

Skew angle calculations
You say "actually it's possible to calculate skew angle by software really fast". Probably true, but I did not find any open source examples of doing that, so I will have to "invent" my own solution. Anything I found was either not freely available or patented, so I can't use it.

Please consider this image, that I use in the explanation of my proposed approach.

The current algorithm is visualized in the yellow "scan bands" and the blue "barcode zone" boundaries. The software scans strokes of the image top-to-bottom (and left-to-right, not shown). For each stroke it looks for large blank spaces and subdivides the scan bands in "barcode zones" by cutting it up through the middle of each large blank space.

A. If we encounter a rotated and/or skewed barcode, there are two angles to consider:
- solid edge angle: this is shown in the leading edge of sample 1. When we travel down the scan band, the start of the black pixels for each scan line will gradually shift in one direction. From that we can fairly easily calculate a skew angle and deskew.
- In a rotated barcode, there will also be a discontinuous edge. When we travel down the scan line, the furthest black pixel will regularly "jump back", where the band cuts through a gap in the barcode. We can still approximate an angle, by determining the average direction and minimum and maximum black pixel coordinate in the scan band.

B. From the solid edge angle, the band can be deskewed by shifting the pixel start point before averaging vertically. This would be enough if skew was the only defect (e.g., second barcode in the image). For a rotated barcode, this will give us a partial barcode.
Deskew can be applied locally, this has the advantage that local defects can be compensated and we do not need a slow image rotation.

C. If one or more partial barcodes is found, rotate the image by the average discontinuous edge angle found, then try again. As this step is inherently slow, it should be optional. Also, note that I propose to use the average angle, meaning that we can only compensate for a global rotation of the full image when using this method.

D. Perhaps step C can be optimized by looking for consecutive scan lines having barcode zones with a similar average angle and finding the bounding rectangle of those. Clone the bounding rectangle to a partial bitmap and only rotate that. Although this method will be more complex than a full image rotation, the advantage would be that less image data is copied and transformed, so the method could be faster than C (provided it is not called for noise data too often).

To configure step B, I would introduce a boolean property UseDeskew.
To configure step C/D, I would introduce a property DetectRotatedBarcodes of type BarcodeType. This can then be used to determine for which barcode type this algorithm must be attempted. Rotation should only be attempted if at least a partial barcode is detected, else the discontinous angle determination will be very unreliable and the software would be come far too slow.



modified on Sunday, October 25, 2009 4:56 AM

GeneralThank you Pin
babakzawari23-Oct-09 3:11
memberbabakzawari23-Oct-09 3:11 
QuestionSupport for rotaded, skewed low resoluted images? Pin
infal22-Oct-09 23:15
memberinfal22-Oct-09 23:15 
AnswerRe: Support for rotaded, skewed low resoluted images? Pin
Berend Engelbrecht22-Oct-09 23:30
memberBerend Engelbrecht22-Oct-09 23:30 
GeneralTIFF support Pin
ndisampson22-Oct-09 18:40
memberndisampson22-Oct-09 18:40 
GeneralRe: TIFF support [modified] Pin
Berend Engelbrecht22-Oct-09 19:18
memberBerend Engelbrecht22-Oct-09 19:18 
GeneralCool but does not allways work... PinPopular
infal22-Oct-09 2:25
memberinfal22-Oct-09 2:25 
GeneralRe: Cool but does not allways work... Pin
Berend Engelbrecht22-Oct-09 2:31
memberBerend Engelbrecht22-Oct-09 2:31 
GeneralRe: Cool but does not allways work... [modified] Pin
infal22-Oct-09 6:36
memberinfal22-Oct-09 6:36 
GeneralCause of problem and bugfix PinPopular
Berend Engelbrecht22-Oct-09 8:45
memberBerend Engelbrecht22-Oct-09 8:45 
GeneralRe: Cause of problem and bugfix Pin
infal22-Oct-09 23:16
memberinfal22-Oct-09 23:16 
GeneralRe: Cause of problem and bugfix Pin
hairy_hats28-Mar-11 1:44
memberhairy_hats28-Mar-11 1:44 
GeneralLooks really cool! Pin
Shane Story7-Oct-09 3:07
memberShane Story7-Oct-09 3:07 
JokeToday Google made a homepage just for me PinPopular
Berend Engelbrecht6-Oct-09 21:41
memberBerend Engelbrecht6-Oct-09 21:41 
GeneralGreat! Pin
EB20025-Oct-09 23:40
memberEB20025-Oct-09 23:40 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Posted 5 Oct 2009


413 bookmarked