Introduction

This is a simple library that lets you do one thing very easily: generate an Image for a Code128 barcode, with a single line of code. This image is suitable for print or display in a WinForms application, or even in ASP.NET.

Background

Support for other barcode symbologies can be easily found because they're easy to create. Basic Code39 barcodes, for example, can be produced using nothing but a simple font, and it seems like you can't hardly swing a cat without hitting a Code39 font or imageset for download.

However, Code39 has deficiencies. The naive font-derived output doesn't afford any error checking. In their standard configuration, most scanners can only recognize 43 different symbols (configuration changes may fix this, but you may not have that luxury with your users' choice of hardware configuration). And Code39 is fairly verbose, requiring a large amount of space for a given message.

Code128, on the other hand, has out-of-the-box support for all 128 low-order ASCII characters. It has built-in error detection at the character and message level, and is extremely terse. Unfortunately, producing a reasonable encoding in this symbology is an "active" process. You must analyze the message for the optimal encoding strategy, and you must calculate a checksum for the entire message.

In my case, it was an absolute necessity to encode control characters. My application's design demanded that the user be able to trigger certain menu shortcut keys by scanning a barcode on a page. But since I've got no control over the scanners that my users are employing, the Code39EXT symbology wasn't a good candidate.

A search yielded several Code128 controls, but these had two important deficiencies. First, they were controls. That would be fine if I just wanted to produce a barcode on the page, but I wanted to use them as images in a grid, so I needed a means of obtaining a raw GDI+ Image object. Second, they were fairly expensive -- enough that a license covering all of our developers would cost more than my time to roll my own.

Using the code

Basic usage

As promised, producing the barcode Image is as simple as a single line of code. Of course, you'll still need code lines necessary to put that Image where it needs to go.

Here's a chunk from the sample application. In it, I respond to a button click by generating a barcode based on some input text, and putting the result into a PictureBox control:

(That's the GenCode128 namespace, in a static class called Code128Rendering). Since this is a static class, you don't even need to worry about instantiating an object.

There are three parameters:

string InputData

The message to be encoded

int BarWeight

The baseline width of the bars in the output. Usually, 1 or 2 is good.

bool AddQuietZone

If false, omits the required white space at the start and end of the barcode. If your layout doesn't already provide good margins around the Image, you should use true.

You can get a feel for the effect of these values by playing with the sample application. While you're at it, try printing out some samples to verify that your scanners can read the barcodes you're planning to produce.

Printing

A barcode library is pretty much useless if you don't use it to print. You can't very well scan the screen. It's been quite a long time since I had printed anything from a Windows application, and it took a little while to remember how. If you need a quick reminder like I did, take a look at the event that the demo app's Print button calls.

What you should be aware of

First of all, I don't have any exception handling built into the library itself. For your own safety, you should put try/catch blocks around any calls to the library.

The solution comprises three projects. One is the library itself, one is the demo application, and then there is the unit test code. I used NUnit by way of TestDriven.net. If you don't have that, then Visual Studio is going to complain. Since it's just test code, you can safely drop it and still use the library successfully.

Another point is the required vertical height of the barcode. The spec requires that the image be either 1/4" or 15% of the overall width, whichever is larger. Since I don't have any control of the scaling you're using when outputting the image, I didn't bother implementing the 1/4" minimum. This means that for very short barcode, the height might be illegally small.

Code128's high information density derives partly from intelligently shifting between several alternate codesets. Obtaining the optimal encoding is, as far as I can tell, a "hard" problem (in the sense of discrete math's non-polynomial problems like the Traveling Salesman). The difference between the best possible solution and my pretty good one should be small, and doesn't seem worth the effort.

If the current character can be encoded in the current codeset, then it just goes ahead and does so.

Otherwise, if the next character would be legal in this codeset, it temporarily shifts into the alternate codeset for just this character.

Else, both this character and the next would need a shift, so instead it changes codesets to avoid the shifts.

A similar decision has to be made about which codeset to start the encoding in. To solve this, I check the first two characters of the string, letting them "vote" to see which codeset they prefer. If there's a preference for one codeset, I choose it; otherwise, I default to codeset B. This is because codeset A allows uppercase alpha-numerics plus control characters, while codeset B allows upper and lower alpha-numerics; I assume that you're more likely to want lowercase than control characters.

Finally, there is an optimization in the Code128 spec for numeric-only output that I didn't take advantage of. Long runs of digits can be encoded in a double density codeset. Accounting for this in my already-ugly look-ahead algorithm would have taken a lot more effort -- for a feature that I don't need. But if you have lots of digits and space is tight, you might look at enhancing this.

Points of interest

I suppose that anyone examining my source code will wonder why in the world my table of bar width has two extra columns. In any sane universe, there should be six columns rather than eight. This was a compromise to allow for the oddball STOP code, which has seven bars rather than six. I could have implemented a special case for just this code, but that was too distasteful.

Instead, I added extra zero-width columns to everything else, making the data equivalent in all cases. For every bar that comes up with a zero width, nothing is output, so nothing is harmed.

Of course, the choice between six or eight columns just begs the question: why not seven? This is to accommodate an optimization in the rendering code. By pre-initializing the entire image to white, I can avoid needing to draw the white bars. Thus, I grab bar widths in groups of two. The first one is the black one, and I draw that normally (unless its width is zero). The second one is white, but there's white already there, so I can just skip the area that would have occupied.

If anyone's keeping score, this is my second attempt at truly Test-Driven Development. On the whole, I think this worked out pretty well. Especially, at the lower levels of code, I'm pretty confident of the code. However, the highest level -- where the output is just an Image -- seemed impractical to be tested in this way.

One problem I've got with the TDD, though, is code visibility. Optimally, this library should have exactly one publicly-visible class, with one public method. However, my test code forces me to expose all of the lower-level stuff that the end caller should never know about. If TDD in C# has developed a good answer to that, I haven't yet stumbled upon it.

Share

About the Author

Chris has been developing software since the 80s, and is currently a project manager at SHI in New Jersey where he builds ecommerce applications. Technologically he concentrates primarily on OO and relational databases, and is currently working in .Net technologies. He's also co-author of "Inside ISAPI".

He thinks that programming is easy, the really challenging work is figuring out what an application needs to do in the first place.

Hi Chris, this worked right out of the box! I just have a couple questions and I know precisely nothing about bar codes so bear with me.
1. I'm told I need to generate a code 128 with a 2 in 5 check digit. Does this do that, or is there some way I can modify it to? I don't have the scanners to just test right now, so I thought I'd ask.
2. Being a developer, I get how long it takes to build this stuff and how much of a pain in the butt it is to support it. If you can help me out with the first question (even if I don't have to do anything more), do you have a paypal or some other online account I could send some money too. Using your code will more than likely make me come in under budget on this project and I'd like to shoot some of that money back to you. It won't be a lot, but I'll give what I can.

I'm not familiar with the terminology "2 in 5 check digit". But I can tell you that error detection is an integral part of Code128; a scanner reading this will be able to detect (within certain bounds) if something was read incorrectly.

As far as donations are concerned, there's no need at all. So I'll give you some suggestions:
(a) write an article yourself, so that somebody else will benefit from some of your work;
(b) toss some money to CodeProject for making this available;
(c) support some other development project that needs the resources;
(d) buy your spouse dinner as thanks for putting up with your job.

Thanks for sharing this excellent barcode tool.But I worry about one thing: I have installed one barcode reader in my program. It supports to read Code 128. I was wondering will this Code 128 barcode generator be compatible with my barcode reader? If yes, that would be great!!

A friend's company upgraded their computer systems, resulting in their bespoke Barcode printing software being rendered useless. this source code is perfect for the actual barcode generation (i still have all the other bells and whistles to implement XD)

I use your code in my rdlc report and it works well, but now, i face a problem, please give me some advices.

I use Zebra 105SL barcode printer(304DPI), although the barcode can be recognized, it is too small, not easy to recognize, i try to find a solution and i found there is a software called Label Matrix, it provide a barcode generation parameter called Density can change the barcode width, might i can implement this function in your source code, and how can i do.

If i use the Weight parameter, the barcode is too large to place in my label.

your idea is great, but i can't do, because Zebra printer can't support chinese character, so i have to generate an image and send the byte array to the printer. and i have a lot of chinese characters on a single label.

What I've done for international support is use a graphic for the text portions. And allow the printer to create the bar codes. If you are doing a lot of this Zebra offfers special compression modes for graphics that decrease the size of the total download.

I know your mean, and I also did this. I got an image through Reporting Services, and it contained the barcode, but now, the customer said the barcode size too small to be recognized easily, the label other parts are OK. So I want to custom barcode width, but I found it's difficult, I have to understand fundamentals about the barcode image generated and it's likely to involve some professional knowledges of mathematics, I can't fix it! it's a tricky issue for me!

I'm sorry I don't know how the Reporting Service works. Is there anyway to have it simply report the value of the barcode and then you modify that with embedded ZPL? Otherwise I think you will need to work on the reporting service size to control it.