Free Reporting Services Barcodes
Recently I had to integrate Code 39 and Code 128 barcodes into Reporting Services. Commercial solutions range from $500 to $1000 so I looked for free fonts that could do the work for me. It seemed simple but I came across a bunch of problems and thought it might help to explain the troubles I went through. By the end of the post you'll have a complete and free solution that you can cut and paste and know worked and didn't work.
You can download the completed demo project (for SSRS 2008) here: Reporting Services Free Barcodes Demo.
In The Beginning...
I originally came across John T Barton's site where he provides Code 39 and Code 128 fonts along with C# code to format input strings into something the barcode fonts can display. The source code is in here under BarcodeDLL\BarcodeConverter.cs.
However he himself downloaded the fonts from the french site that created it, Grand Zebu, and they have since released newer versions of the font, which require some minor changes to the code. The reference links are here (Code 39) and here (Code 128) respectively.
I ran Barton's code through a free online C# to VB.NET converter at developer Fusion, and modified it as best I could understand Grand Zebu's notes above, it came out with the hideously ugly but functional code below. Disclaimer: I didn't try to tidy it up...:
Public Shared Function StringToBarcode128String(ByVal value As String) As String ' Parameters : a string ' Return : a string which give the bar code when it is dispayed with CODE128.TTF font ' : an empty string if the supplied parameter is no good Dim charPos As Integer, minCharPos As Integer Dim currentChar As Integer, checksum As Integer Dim isTableB As Boolean = True, isValid As Boolean = True Dim returnValue As String = String.Empty If value.Length > 0 Then ' Check for valid characters For charCount As Integer = 0 To value.Length - 1 'currentChar = char.GetNumericValue(value, charPos); currentChar = AscW(Char.Parse(value.Substring(charCount, 1))) If Not (currentChar >= 32 AndAlso currentChar <= 126) Then isValid = False Exit For End If Next ' Barcode is full of ascii characters, we can now process it If isValid Then charPos = 0 While charPos < value.Length If isTableB Then ' See if interesting to switch to table C ' yes for 4 digits at start or end, else if 6 digits If charPos = 0 OrElse charPos + 4 = value.Length Then minCharPos = 4 Else minCharPos = 6 End If minCharPos = IsNumber(value, charPos, minCharPos) If minCharPos < 0 Then ' Choice table C If charPos = 0 Then ' Starting with table C ' char.ConvertFromUtf32(210); returnValue = (ChrW(210)).ToString() Else ' Switch to table C returnValue = returnValue & (ChrW(204)).ToString() End If isTableB = False Else If charPos = 0 Then ' Starting with table B ' char.ConvertFromUtf32(209); returnValue = (ChrW(209)).ToString() End If End If End If If Not isTableB Then ' We are on table C, try to process 2 digits minCharPos = 2 minCharPos = IsNumber(value, charPos, minCharPos) If minCharPos < 0 Then ' OK for 2 digits, process it currentChar = Integer.Parse(value.Substring(charPos, 2)) currentChar = IIf(currentChar < 95, currentChar + 32, currentChar + 105) '' returnValue = returnValue & (ChrW(currentChar)).ToString() charPos += 2 Else ' We haven't 2 digits, switch to table B returnValue = returnValue & (ChrW(205)).ToString() isTableB = True End If End If If isTableB Then ' Process 1 digit with table B returnValue = returnValue & value.Substring(charPos, 1) charPos += 1 End If End While ' Calculation of the checksum checksum = 0 For [loop] As Integer = 0 To returnValue.Length - 1 currentChar = AscW(Char.Parse(returnValue.Substring([loop], 1))) currentChar = IIf(currentChar < 127, currentChar - 32, currentChar - 105) If [loop] = 0 Then checksum = currentChar Else checksum = (checksum + ([loop] * currentChar)) Mod 103 End If Next ' Calculation of the checksum ASCII code checksum = IIf(checksum < 95, checksum + 32, checksum + 105) ' Add the checksum and the STOP returnValue = returnValue & (ChrW(checksum)).ToString() & (ChrW(211)).ToString() End If End If Return returnValue End Function Private Shared Function IsNumber(ByVal InputValue As String, ByVal CharPos As Integer, ByVal MinCharPos As Integer) As Integer ' if the MinCharPos characters from CharPos are numeric, then MinCharPos = -1 MinCharPos -= 1 If CharPos + MinCharPos < InputValue.Length Then While MinCharPos >= 0 If AscW(Char.Parse(InputValue.Substring(CharPos + MinCharPos, 1))) < 48 OrElse AscW(Char.Parse(InputValue.Substring(CharPos + MinCharPos, 1))) > 57 Then Exit While End If MinCharPos -= 1 End While End If Return MinCharPos End Function Public Shared Function StringToBarcode39String(ByVal value As String, Optional ByVal addChecksum As Boolean = False) As String ' Parameters : a string ' Return : a string which give the bar code when it is dispayed with CODE128.TTF font ' : an empty string if the supplied parameter is no good Dim isValid As Boolean = True Dim currentChar As Char Dim returnValue As String = String.Empty Dim checksum As Integer = 0 If value.Length > 0 Then 'Check for valid characters For CharPos As Integer = 0 To value.Length - 1 currentChar = Char.Parse(value.Substring(CharPos, 1)) If Not ((currentChar >= "0"c AndAlso currentChar <= "9"c) OrElse (currentChar >= "A"c AndAlso currentChar <= "Z"c) OrElse currentChar = " "c OrElse currentChar = "-"c OrElse currentChar = "."c OrElse currentChar = "$"c OrElse currentChar = "/"c OrElse currentChar = "+"c OrElse currentChar = "%"c) Then isValid = False Exit For End If Next If isValid Then ' Add start char returnValue = "*" ' Add other chars, and calc checksum For CharPos As Integer = 0 To value.Length - 1 currentChar = Char.Parse(value.Substring(CharPos, 1)) returnValue += currentChar.ToString() If currentChar >= "0"c AndAlso currentChar <= "9"c Then checksum = checksum + AscW(currentChar) - 48 ElseIf currentChar >= "A"c AndAlso currentChar <= "Z"c Then checksum = checksum + AscW(currentChar) - 55 Else Select Case currentChar Case "-"c checksum = checksum + AscW(currentChar) - 9 Exit Select Case "."c checksum = checksum + AscW(currentChar) - 9 Exit Select Case "$"c checksum = checksum + AscW(currentChar) + 3 Exit Select Case "/"c checksum = checksum + AscW(currentChar) - 7 Exit Select Case "+"c checksum = checksum + AscW(currentChar) - 2 Exit Select Case "%"c checksum = checksum + AscW(currentChar) + 5 Exit Select Case " "c checksum = checksum + AscW(currentChar) + 6 Exit Select End Select End If Next ' Calculation of the checksum ASCII code If addChecksum Then checksum = checksum Mod 43 If checksum >= 0 AndAlso checksum <= 9 Then returnValue += (ChrW(checksum + 48)).ToString() ElseIf checksum >= 10 AndAlso checksum <= 35 Then returnValue += (ChrW(checksum + 55)).ToString() Else Select Case checksum Case 36 returnValue += "-" Exit Select Case 37 returnValue += "." Exit Select Case 38 returnValue += " " Exit Select Case 39 returnValue += "$" Exit Select Case 40 returnValue += "/" Exit Select Case 41 returnValue += "+" Exit Select Case 42 returnValue += "%" Exit Select End Select End If End If ' Add stop char returnValue += "*" End If End If Return returnValue End Function
First Attempt
For my first attempt, I installed the two fonts (and later rebooted when the fonts didn't work and I realised this is still necessary as recent as Windows 7), and set to work on a demonstration in BIDS to see if I could use the fonts simply with the code provided to show and print barcodes.
It consists simply of:
- The custom code from above.
- A dummy data set (use anything) and a table with the detail grouping removed.
- Two expressions, one in a table cell each.
=Code.StringToBarcode39String("12345") =Code.StringToBarcode128String("12345")
- Setting the font properties for each table cell to Code 3 de 9 and Code 128 respectively, 36pt (or any other arbitrary size) and resize the cell a little bigger to match.
And after you change the font settings:

And then when you preview the report:

And then when you export the report to PDF:

Wait a minute, that doesn't look right!
What Went Wrong
This is where it gets complicated; the free Code 128 barcode font doesn't work (as of RS2008 R2) when exporting to PDF. It's supposed to work as it's a TrueType font with embed rights and after checking the PDF properties it has embedded the correct font; it just doesn't display properly in Adobe Reader (as of 10.0.1).
Final Attempt
The way I got around this is to render the text using that font as an image then display it in an image control, which accepts a byte array representing the file from some more custom code. As it turns out other people have done this before, but it hasn't been well explained:
Public Shared Function Code39(ByVal stringText As String) As Byte() Dim result As Byte() = Nothing Try result = GenerateImage("Code 3 de 9", StringToBarcode39String(stringText)) Catch ex As Exception End Try Return result End Function Public Shared Function Code128(ByVal stringText As String) As Byte() Dim result As Byte() = Nothing Try result = GenerateImage("Code 128", StringToBarcode128String(stringText)) Catch ex As Exception End Try Return result End Function Public Shared Function GenerateImage(ByVal fontName As String, ByVal stringText As String) As Byte() Dim oGraphics As System.Drawing.Graphics Dim barcodeSize As System.Drawing.SizeF Dim ms As System.IO.MemoryStream Using font As New System.Drawing.Font(New System.Drawing.FontFamily(fontName), 36) Using tmpBitmap As New System.Drawing.Bitmap(1, 1, System.Drawing.Imaging.PixelFormat.Format32bppArgb) oGraphics = System.Drawing.Graphics.FromImage(tmpBitmap) oGraphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixel barcodeSize = oGraphics.MeasureString(stringText, font) oGraphics.Dispose() End Using Using newBitmap As New System.Drawing.Bitmap(barcodeSize.Width, barcodeSize.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb) oGraphics = System.Drawing.Graphics.FromImage(newBitmap) oGraphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixel Using oSolidBrushWhite As New System.Drawing.SolidBrush(System.Drawing.Color.White) Using oSolidBrushBlack As New System.Drawing.SolidBrush(System.Drawing.Color.Black) oGraphics.FillRectangle(oSolidBrushWhite, New System.Drawing.Rectangle(0, 0, barcodeSize.Width, barcodeSize.Height)) oGraphics.DrawString(stringText, font, oSolidBrushBlack, 0, 0) End Using End Using ms = New System.IO.MemoryStream() newBitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png) End Using End Using Return ms.ToArray() End Function
I've now used two wrapper functions Code39 and Code128 which will do all the processing with the right font and return it as an image in a byte array. The steps to get this working, continuing on from before, are:
- Adding the above custom code to the report.
- Going into Report Properties -> References and adding the System.Drawing assembly to the report.
- Replacing the two textboxes with two image controls instead, with their settings as per below:

- It will also look far better to set the image sizing controls to Clip instead of Fit or FitProportional. For this reason you will probably want to experiment with the font sizes above and the longest barcode you're going to reproduce so that it looks right without cutting anything off.
The final report looks like this:

And surprise surprise, the screen renders similar to before and the PDF shows correctly too:

Conclusion
It took a lot of ugly code and work but I had the solution I was looking for, and now hopefully others can use it easily. I should make a few notes though:
- I wrote the part that generates the image, but I'm aware that there might be problems because it uses GDI+ which can leak non-managed Windows resources if they aren't used properly. I wrapped everything in Using blocks which do an automatic .Dispose(), but I'm not a professional programmer and could have missed something.
- Using the plain fonts method showed much clearer barcodes than when drawning on an image. I also couldn't work out why this is a case; I tried different types of font hints, and even changing the GDI+ code for the modern .NET DrawString function, and it only made things even worse.
If anyone ever works out a better plug-and-play way (not using custom assemblies or paid fonts), let me know.
Until next time,
Cody
Update
After using this in the real world, I've found that the Code 39 generally scans okay as provided, but the Code 128 works better generated at 96pt, and then downscaled into the image box with "Fit", so that it's actually longer and thinner than it should be. Sounds crazy, but it works ...
Be sure to do your own testing.
June 13th, 2011 - 04:21
Hi Cody,
Seems that the link http://www.ssrstips.com/wp-content/uploads/2011/03/Reporting-Services-Free-Barcodes-Demo.zip (source code sample for Reporting services) above is not working. Can you update? Do you still have the code? I’ve tried to generate barcode using SSRS for a few days, but to no avail. I’ve searched the internet for samples, ways to do it, samples, but none works, and most of them don’t provide the sample for reporting services, only winforms.
Mind to share your sample?
Thanks.
June 13th, 2011 - 04:54
Hi, sorry for that, I’ve fixed the link, please try again.
June 13th, 2011 - 05:32
Hi, thanks a lot, Pal ^^ The link is working now. Will try it out
August 10th, 2011 - 12:00
Hi,
I’ve tried your demo, and it gives the following output
The First Attempt – gives an output of *12345* O,BI5VO
Final Version – gives a blank output.
No barcodes display.
Please help, what am i doing wrong.
I need to get this working quite urgertly.
Thanks
Rebekah
August 10th, 2011 - 12:31
You have to install the fonts first and reboot; or in some cases you can install the fonts and just restart the Reporting Services service.
August 12th, 2011 - 07:01
Hi Cody,
I see the font files, but how do i install the fonts ?
Thanks
Rebekah
August 12th, 2011 - 08:09
Hi Cody,
I used this site to install the fonts, for others who need to know
http://support.microsoft.com/kb/314960
An wow it works
Thanks a million
Rebekah
August 12th, 2011 - 08:18
Whats the best way to test this barcode ?
August 25th, 2011 - 04:25
I used some free iPhone apps to test, specifically ZBar.
August 24th, 2011 - 13:15
Dear author,
You are AWE-wait for it-SOME!
I looked EVERY-FREAKING-WHERE for this solution!!!
Some problems with SSRS 2008 R2 to display custom True Type Font properly…
Spend more then a week on this issue and thanks to your solution, it’s solved!
Not even MS could answer this issue, so you’re a pro :p
Wished I encountered this page earlier!
I’m making this a dll to pass a custom font, and optionally FontStyle, Size, Weight, Color, BackColor…
Barcode data is rendered when storing it in a table, so I didn’t need the convertion functions.
If you mail me I can send you the result
Thanks again!
Lawrence
August 25th, 2011 - 04:26
I’m glad it worked for you. I really don’t know why SSRS still has so many problems dealing with embedding unicode TT fonts in PDFs and elsewhere, even with Microsoft’s insistence that it all works perfectly.
November 4th, 2011 - 07:08
I tried this but it seemed like it’s not working with more characters/numbers. I tried 10 characters but the scanner cannot read it anymore.
November 19th, 2011 - 00:30
Hi,
I tried this in SSRS 2005 but no luck.
November 19th, 2011 - 02:14
Hi,
Sorry to hear that, though I’m not surprised because 2005->2008 is so different. I haven’t used 2005 in a long time so I can’t give any advice.
Cheers
December 9th, 2011 - 23:31
I tried installing the fonts and printing they work great. But when I try to scan Code 128 barcode it does not scan it. What may be the issue?
I am using a image to create barcode.
What specs. should the image barcode have? Thanks.
December 10th, 2011 - 01:35
Are you scanning with your phone or with a proper barcode scanner?
I noticed that on my phone (using its camera) it’s easy to pick up very small barcodes but on the hand-held laser scanners, they have to be much bigger.
For example a 12 letter barcode in Code 128 has to be at least 3.3cm x 0.75cm to scan. It seems the width is more important than the height.