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 BarcodeDLLBarcodeConverter.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.

It should look like this:

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.

47 thoughts on “Free Reporting Services Barcodes

  1. Steven Luck

    Hi Cody,
    Seems that the link http://www.zeninteractions.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.

    Reply
  2. Rebekah

    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

    Reply
    1. Cody Konior Post author

      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.

      Reply
          1. Alok

            Rebekkah,
            I am facing the same problem as you faced with barcode. It just shows the barcode in plain text in some encoded form but not in barcode. I reinstalled the font as you mentioned. But still it is not working. Any suggestion?

  3. Lawrence

    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

    Reply
    1. Cody Konior Post author

      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.

      Reply
  4. reyn

    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.

    Reply
  5. Pingback: General SSRS Tips | dorothyjarry

    1. Cody Konior Post author

      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

      Reply
  6. bha

    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.

    Reply
    1. Cody Konior Post author

      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.

      Reply
    2. Bstone

      I can print the Code 128 barcode and it looks fine.. but it’s not scanning for me either. I also made sure it was at least 3.3cm x .75cm. Any ideas out there?

      Reply
  7. Andy

    I’m trying to use this with 2008R2 in Report Builder 3, but I keep on getting single characters before an after my barcode. such as:

    Ñ [barcode] Ó

    …any idea why?

    Reply
    1. Dave

      I have the same issue, barcodes are printed correctly but when I try to scan the code 128 it doesn’t work?
      When I make text fields to see the real string it has also the extra characters.
      Did you solved the problem?

      Reply
  8. Masoud Monazah

    Hello Cody,
    This was great help. Thanks a bunch. Microsoft would not be where it is today if it wasn’t because of developers like yourself helping out.

    Great job

    Reply
  9. Hiren

    I am trying to use this code, but it’s give me error message as follow -
    cannot create a connection to data source ‘Dummy’

    Can you please let me know why it showing this error message.

    Reply
  10. Sasa

    Hello, Cody.

    Great article, I’ve been looking for something like this for a while. But I do have an issue – everything is great, even export to pdf but only from developement studio. Deployed version shows blank image. Any thougths?

    Regards, Saša

    Reply
    1. Tina

      I am running into a similar issue that the reports show the code in BIDS but not in reports manager.

      Anyone find a fix for this?

      Reply
  11. Steve

    Thanks for the solution. I was originally having issues with spaces being rendered between each number in the barcode only when printing from a customers server ( I couldn’t reproduce the bug anywhere else). This solution fixes the bug that I encountered. It does, however, render the barcode images distorted at smaller font sizes (under 72pt). Unfortunately, I can’t go that large in order to fit everything on the page. Hoping I can find a way to render clearer images.

    Reply
    1. Steve

      Changing to…

      SystemDrawing.Text.TextRenderingHint.ClearTypeGridFit

      and adding…

      oGraphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias

      renders the image properly without distorting the barcode at smaller font sizes. I needed to make these changes in order to properly read the barcode.

      Reply
  12. Mohamed Ali

    Dear Cody,

    Thanks you very much for your great effort that helped me a lot……

    You are really a great person.

    Mohamed,

    Reply
  13. Sharon

    Thank you! Thank you! Thank you! Thanks for generously sharing your hard labor. I struggled for days before I came upon your site.

    Thanks!

    Reply
  14. claudio

    in the preview looks good, but when I publish it on the website of reporting, barcode disappears
    can you tell me how to do

    Reply
  15. Anthony Dalton

    Cody,
    First off thanks for the help. Everything works great in the designer and preview mode, but once I actually publish the report, I can’t see the barcode. I can’t even see it locally on the SSRS box. Any tips?

    Reply
  16. Bruce

    Hi,

    I am able to use this fine and the barcode looks ok except there is a weird character at the beginning and end of the barcode, kind of like a long rectangle on its side. Any ideas? If I could get rid of this that would be great.

    Thanks,
    Bruce

    Reply
  17. Bruce

    Hi,

    OK, so now I tried the image method (because I realized that the boxes on each end were a side effect of the font) and now I just get a small square with a red x. Any ideas?

    Thanks,
    Bruce

    Reply
  18. Bruce

    OK, I wasn’t calling the Code128 method in my custom code, so now I am getting output but it is not a barcode, it is some weird jumble of characters like O&’*ER[O`. Any ideas?

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>