Barcode with SSRS

In this blog I am going to introduce Barcode with SSRS reports. Before going ahead we need to know what is Barcode. A barcode is a machine readable code that is most common now adays. It is in the form of parallel lines. These parallel lines are generated with the help of number or alphabets or with combination of both (alphanumeric). These parallel lines are separated with some distance between them depending upon need. Barcodes are printed on a commodity and used especially for stock control. Example-: 01-barcode Some days before I got a requirement to make a barcode with the help of SSRS reports, so I decided to share it with all of you. Commercial solutions range from $500 to $1000, so I decided to make it myself with the help of code available on internet. To make a barcode we need two class files that I have used in my code as well. Code for first class-:

#region Namespace
using System;
using System.Drawing;
#endregion

namespace BarcodeClasses
{
 /// 
 /// Summary description for RenderingCode128.
 /// 
 public static class RenderingCode128
 {
 #region Code patterns

// in principle these rows should each have 6 elements
 // however, the last one -- STOP -- has 7. The cost of the
 // extra integers is trivial, and this lets the code flow
 // much more elegantly
 private static readonly int[,] Patterns =
 {
 {2,1,2,2,2,2,0,0}, // 0
 {2,2,2,1,2,2,0,0}, // 1
 {2,2,2,2,2,1,0,0}, // 2
 {1,2,1,2,2,3,0,0}, // 3
 {1,2,1,3,2,2,0,0}, // 4
 {1,3,1,2,2,2,0,0}, // 5
 {1,2,2,2,1,3,0,0}, // 6
 {1,2,2,3,1,2,0,0}, // 7
 {1,3,2,2,1,2,0,0}, // 8
 {2,2,1,2,1,3,0,0}, // 9
 {2,2,1,3,1,2,0,0}, // 10
 {2,3,1,2,1,2,0,0}, // 11
 {1,1,2,2,3,2,0,0}, // 12
 {1,2,2,1,3,2,0,0}, // 13
 {1,2,2,2,3,1,0,0}, // 14
 {1,1,3,2,2,2,0,0}, // 15
 {1,2,3,1,2,2,0,0}, // 16
 {1,2,3,2,2,1,0,0}, // 17
 {2,2,3,2,1,1,0,0}, // 18
 {2,2,1,1,3,2,0,0}, // 19
 {2,2,1,2,3,1,0,0}, // 20
 {2,1,3,2,1,2,0,0}, // 21
 {2,2,3,1,1,2,0,0}, // 22
 {3,1,2,1,3,1,0,0}, // 23
 {3,1,1,2,2,2,0,0}, // 24
 {3,2,1,1,2,2,0,0}, // 25
 {3,2,1,2,2,1,0,0}, // 26
 {3,1,2,2,1,2,0,0}, // 27
 {3,2,2,1,1,2,0,0}, // 28
 {3,2,2,2,1,1,0,0}, // 29
 {2,1,2,1,2,3,0,0}, // 30
 {2,1,2,3,2,1,0,0}, // 31
 {2,3,2,1,2,1,0,0}, // 32
 {1,1,1,3,2,3,0,0}, // 33
 {1,3,1,1,2,3,0,0}, // 34
 {1,3,1,3,2,1,0,0}, // 35
 {1,1,2,3,1,3,0,0}, // 36
 {1,3,2,1,1,3,0,0}, // 37
 {1,3,2,3,1,1,0,0}, // 38
 {2,1,1,3,1,3,0,0}, // 39
 {2,3,1,1,1,3,0,0}, // 40
 {2,3,1,3,1,1,0,0}, // 41
 {1,1,2,1,3,3,0,0}, // 42
 {1,1,2,3,3,1,0,0}, // 43
 {1,3,2,1,3,1,0,0}, // 44
 {1,1,3,1,2,3,0,0}, // 45
 {1,1,3,3,2,1,0,0}, // 46
 {1,3,3,1,2,1,0,0}, // 47
 {3,1,3,1,2,1,0,0}, // 48
 {2,1,1,3,3,1,0,0}, // 49
 {2,3,1,1,3,1,0,0}, // 50
 {2,1,3,1,1,3,0,0}, // 51
 {2,1,3,3,1,1,0,0}, // 52
 {2,1,3,1,3,1,0,0}, // 53
 {3,1,1,1,2,3,0,0}, // 54
 {3,1,1,3,2,1,0,0}, // 55
 {3,3,1,1,2,1,0,0}, // 56
 {3,1,2,1,1,3,0,0}, // 57
 {3,1,2,3,1,1,0,0}, // 58
 {3,3,2,1,1,1,0,0}, // 59
 {3,1,4,1,1,1,0,0}, // 60
 {2,2,1,4,1,1,0,0}, // 61
 {4,3,1,1,1,1,0,0}, // 62
 {1,1,1,2,2,4,0,0}, // 63
 {1,1,1,4,2,2,0,0}, // 64
 {1,2,1,1,2,4,0,0}, // 65
 {1,2,1,4,2,1,0,0}, // 66
 {1,4,1,1,2,2,0,0}, // 67
 {1,4,1,2,2,1,0,0}, // 68
 {1,1,2,2,1,4,0,0}, // 69
 {1,1,2,4,1,2,0,0}, // 70
 {1,2,2,1,1,4,0,0}, // 71
 {1,2,2,4,1,1,0,0}, // 72
 {1,4,2,1,1,2,0,0}, // 73
 {1,4,2,2,1,1,0,0}, // 74
 {2,4,1,2,1,1,0,0}, // 75
 {2,2,1,1,1,4,0,0}, // 76
 {4,1,3,1,1,1,0,0}, // 77
 {2,4,1,1,1,2,0,0}, // 78
 {1,3,4,1,1,1,0,0}, // 79
 {1,1,1,2,4,2,0,0}, // 80
 {1,2,1,1,4,2,0,0}, // 81
 {1,2,1,2,4,1,0,0}, // 82
 {1,1,4,2,1,2,0,0}, // 83
 {1,2,4,1,1,2,0,0}, // 84
 {1,2,4,2,1,1,0,0}, // 85
 {4,1,1,2,1,2,0,0}, // 86
 {4,2,1,1,1,2,0,0}, // 87
 {4,2,1,2,1,1,0,0}, // 88
 {2,1,2,1,4,1,0,0}, // 89
 {2,1,4,1,2,1,0,0}, // 90
 {4,1,2,1,2,1,0,0}, // 91
 {1,1,1,1,4,3,0,0}, // 92
 {1,1,1,3,4,1,0,0}, // 93
 {1,3,1,1,4,1,0,0}, // 94
 {1,1,4,1,1,3,0,0}, // 95
 {1,1,4,3,1,1,0,0}, // 96
 {4,1,1,1,1,3,0,0}, // 97
 {4,1,1,3,1,1,0,0}, // 98
 {1,1,3,1,4,1,0,0}, // 99
 {1,1,4,1,3,1,0,0}, // 100
 {3,1,1,1,4,1,0,0}, // 101
 {4,1,1,1,3,1,0,0}, // 102
 {2,1,1,4,1,2,0,0}, // 103
 {2,1,1,2,1,4,0,0}, // 104
 {2,1,1,2,3,2,0,0}, // 105
 {2,3,3,1,1,1,2,0} // 106
 };

#endregion Code patterns
 #region Method
 /// 
 /// Make an image of a Code128 barcode for a given string
 /// 
 ///Message to be encoded
 ///Add required horizontal margins (use if output is /// tight)
 /// An Image of the Code128 barcode representing the message
 public static Image MakeBarcodeImage(string strUserDefinedData, bool AddZone)
 {
 // get the Code128 codes to represent the message
 ContentCode128 content = new ContentCode128(strUserDefinedData);
 int[] Codes = content.Codes;

int Width, Height;
 Width = ((Codes.Length - 3) * 11 + 35) * 2; //Here 2 is bar weight. For my case I have taken it as 2
 Height = Convert.ToInt32(System.Math.Ceiling(Convert.ToSingle(Width) * .15F));

if (AddZone)
 {
 Width += 2 * 10 * 2; // on both sides(Width = 2*quietwidth(in most cases 10)*Barweight)
 }

Image MyImg = new System.Drawing.Bitmap(Width, Height); // get surface to draw on
 using (Graphics gr = Graphics.FromImage(MyImg))
 {
 gr.FillRectangle(System.Drawing.Brushes.White, 0, 0, Width, Height); // set to white so we don't have to fill the spaces with white
 int Cursor = AddZone ? 10 * 2 : 0; // skip quiet zone( 10 * 2 : 0 = quietwidth * Barweight : 0)

for (int Codeid = 0; Codeid < Codes.Length; Codeid++)
 {
 int Code = Codes[Codeidx];

for (int Bars = 0; Bars < 8; Bars += 2) // take the bars two at a time: a black and a white
 {
 int BarWidth = Patterns[Code, Bars] * 2; // Here 2 shows the Barweight
 int SpcWidth = Patterns[Code, Bars + 1] * 2;

if (BarWidth > 0) // if width is zero, don't try to draw it
 {
 gr.FillRectangle(System.Drawing.Brushes.Black, Cursor, 0, SpcWidth, Height);
 }

// note that we never need to draw the space, since we
 // initialized the graphics to all white
 // advance cursor beyond this pair
 Cursor += (BarWidth + SpcWidth);
 }
 }
 }
 return MyImg;
 }
#endregion
 }
}

Code for second class-:

#region Namespace
using System.Text;
#endregion

#region Barcode Methods
namespace BarcodeClasses
{
 /// 
 /// Description: This page will get content for 128 code barcode.
 /// 
 public enum CodeSet
 {
 CodeA,
 CodeB
 }

#region ContentCode128
 /// 
 /// Represent the set of code values to be output into barcode form
 /// 
 public class ContentCode128
 {
 private int[] CodeList;

/// 
 /// Create content based on a string of ASCII data
 /// 
 ///the string that should be represented
 public ContentCode128(string DataASCII)
 {
 CodeList = StringToCode128(DataASCII);
 }

/// 
 /// Provides the Code128 code values representing the object's string
 /// 
 public int[] Codes
 {
 get
 {
 return CodeList;
 }
 }

/// 
 /// Transform the string into integers representing the Code128 codes
 /// necessary to represent it
 /// 
 ///String to be encoded
 /// Code128 representation
 private int[] StringToCode128(string DataASCII)
 {
 byte[] byteASCII = Encoding.ASCII.GetBytes(DataASCII); // turn the string into ascii byte data

// decide from which codeset to start with
 Code128.CodeSetAllowed csa1 = byteASCII.Length > 0 ? Code128.CodesetAllowedForChar(byteASCII[0]) : Code128.CodeSetAllowed.CodeAorB;
 Code128.CodeSetAllowed csa2 = byteASCII.Length > 0 ? Code128.CodesetAllowedForChar(byteASCII[1]) : Code128.CodeSetAllowed.CodeAorB;
 CodeSet CurrentCS = GetBestStartSet(csa1, csa2);

// set up the beginning for the barcode
 System.Collections.ArrayList Codes = new System.Collections.ArrayList(byteASCII.Length + 3); // assume no codeset changes, account for start, checksum, and stopCodes
 Codes.Add(Code128.StartCodeForCodeSet(CurrentCS));

for (int Count = 0; Count < byteASCII.Length; Count++) // add the codes for each character in the string
 {
 int PresentChar = byteASCII[Count];
 int NextChar = byteASCII.Length > (Count + 1) ? byteASCII[Count + 1] : -1;

Codes.AddRange(Code128.CodesForChar(PresentChar, NextChar, ref CurrentCS));
 }

 int Checksum = (int)(Codes[0]); // calculate the check digit

for (int Codes = 1; Codes < Codes.Count; Codes++)
 {
 Checksum += Codes * (int)(Codes[Codes]);
 }

Codes.Add(Checksum % 103);
 Codes.Add(Code128.StopCode());

int[] Result = Codes.ToArray(typeof(int)) as int[];
 return Result;
 }

/// 
 /// Determines the best starting code set based on the the first two
 /// characters of the string to be encoded
 /// 
 ///First character of input string
 ///Second character of input string
 /// The codeset determined to be best to start with
 private CodeSet GetBestStartSet(Code128.CodeSetAllowed csa1, Code128.CodeSetAllowed csa2)
 {
 int Vote = 0;

Vote += (csa1 == Code128.CodeSetAllowed.CodeA) ? 1 : 0;
 Vote += (csa1 == Code128.CodeSetAllowed.CodeB) ? -1 : 0;
 Vote += (csa2 == Code128.CodeSetAllowed.CodeA) ? 1 : 0;
 Vote += (csa2 == Code128.CodeSetAllowed.CodeB) ? -1 : 0;

return (Vote > 0) ? CodeSet.CodeA : CodeSet.CodeB; // ties go to codeB due to my own prejudices
 }
 }
 #endregion
 #region Code128
 /// 
 /// Static tools for determining codes for individual characters in the content
 /// 
 public static class Code128
 {
 #region Constants

private const int SHIFT = 98;
 private const int CODEA = 101;
 private const int CODEB = 100;

private const int STARTA = 103;
 private const int STARTB = 104;
 private const int STOP = 106;

#endregion

/// 
 /// Get the Code128 code value(s) to represent an ASCII character, with
 /// optional look-ahead for length optimization
 /// 
 ///The ASCII value of the character to translate
 ///The next character in sequence (or -1 if none)
 ///The current codeset, that the returned codes need to follow;
 /// if the returned codes change that, then this value will be changed to reflect it
 /// An array of integers representing the codes that need to be output to produce the
 /// given character
 public static int[] CodesForChar(int CharacterASCII, int LookForASCII, ref CodeSet CurrentCS)
 {
 int[] Result;
 int Shifter = -1;

if (!CharCompatibleWithCodeset(CharacterASCII, CurrentCS))
 {
 // if we have a lookahead character AND if the next character is ALSO not compatible
 if ((LookForASCII != -1) && !CharCompatibleWithCodeset(LookForASCII, CurrentCS))
 {
 switch (CurrentCS) // we need to switch code sets
 {
 case CodeSet.CodeA:
 Shifter = CODEB;
 CurrentCS = CodeSet.CodeB;
 break;
 case CodeSet.CodeB:
 Shifter = CODEA;
 CurrentCS = CodeSet.CodeA;
 break;
 }
 }
 else
 {
 Shifter = SHIFT; // no need to switch code sets, a temporary SHIFT will suffice
 }
 }

if (Shifter != -1)
 {
 Result = new int[2];
 Result[0] = Shifter;
 Result[1] = CodeValueForChar(CharacterASCII);
 }
 else
 {
 Result = new int[1];
 Result[0] = CodeValueForChar(CharacterASCII);
 }

return Result;
 }

/// 
 /// Tells us which codesets a given character value is allowed in
 /// 
 ///ASCII value of character to look at
 /// Which codeset(s) can be used to represent this character
 public static CodeSetAllowed CodesetAllowedForChar(int CharacterASCII)
 {
 if (CharacterASCII >= 32 && CharacterASCII <= 95)
 {
 return CodeSetAllowed.CodeAorB;
 }
 else
 {
 return (CharacterASCII < 32) ? CodeSetAllowed.CodeA : CodeSetAllowed.CodeB;
 }
 }

/// 
 /// Determine if a character can be represented in a given codeset
 /// 
 ///character to check for
 ///codeset context to test
 /// true if the codeset contains a representation for the ASCII character
 public static bool CharCompatibleWithCodeset(int CharacterASCII, CodeSet CurrentCS)
 {
 CodeSetAllowed csa = CodesetAllowedForChar(CharacterASCII);
 return csa == CodeSetAllowed.CodeAorB
 || (csa == CodeSetAllowed.CodeA && CurrentCS == CodeSet.CodeA)
 || (csa == CodeSetAllowed.CodeB && CurrentCS == CodeSet.CodeB);
 }

/// 
 /// Gets the integer code128 code value for a character (assuming the appropriate code set)
 /// 
 ///character to convert
 /// code128 symbol value for the character
 public static int CodeValueForChar(int CharacterASCII)
 {
 return (CharacterASCII >= 32) ? CharacterASCII - 32 : CharacterASCII + 64;
 }

/// 
 /// Return the appropriate START code depending on the codeset we want to be in
 /// 
 ///The codeset you want to start in
 /// The code128 code to start a barcode in that codeset
 public static int StartCodeForCodeSet(CodeSet CodeSet)
 {
 return CodeSet == CodeSet.CodeA ? STARTA : STARTB;
 }

/// 
 /// Return the Code128 stop code
 /// 
 /// the stop code
 public static int StopCode()
 {
 return STOP;
 }

/// 
 /// Indicates which code sets can represent a character -- CodeA, CodeB, or either
 /// 
 public enum CodeSetAllowed
 {
 CodeA,
 CodeB,
 CodeAorB
 }

}
#endregion
}
#endregion

Now, you got your two files that are used to make a barcode. Your 80% work is done. Now you just need to call this barcode classes in your project. What I have done is I called this classes from my files and made a image and than saved that image into DB and than called that image on my reports. Steps that I took are as follows-: 1. Making image and saving it in DB.

byte[] byteImage;
 MemoryStream ms = new MemoryStream();
 //This function calls first class i.e. your renderingcode128 class with
 //a string that we need the barcode for.
 //This will return an image
 Image img = RenderingCode128.MakeBarcodeImage(yourstring, true);
 // Now saving image as bytes
 img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
 byteImage = ms.ToArray();
 Image = byteImage;
 ProductID = Id //Id for which Barcode will be generated
 AddBarcodeImage(); //This function saves image to DB

AddBarcodeImage() is my function to save image in DB. You can make your own function to insert image into DB. 2. Now open your SSRS reports and add image into it. 3. Right click on image, a dialog will open set properties as shown in image. 02-step3 Name field can differ. For getting value of this image we need to create a logic to get that image bytes from DB with the help of store procedure and call in “Use this field” text box and make an expression there as shown in image. 03-step4 Here Barcode.Value refers to the name of variable in which we are getting Barcode image bytes from the DB, and I am returning it in Dataset1 so I used this line-: First(Fields!Barcode.Value , ”DataSet1”) That’s it. Now, you just need to pass value to your function of which you need to make Barcode for and your Barcode will be ready and ready to scan. Hope it helps you. Should you have any questions please feel free to add a comment below. Written By : Himanshu Dora, ASP.NET Developer, Mindfire Solutions

Advertisements

Posted on March 20, 2014, in ASP.Net, C# and tagged , , , , , . Bookmark the permalink. Leave a comment.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: