|
gspadari,
Thank you very much for the updated code. You are right, the original implementation was not recognizable by bcTester also with barcode scanner. With your modification it works perfectly alright.
Thanks,
Govind
|
|
|
|
|
Govind, do you have examples of input that generated unreadable barcodes? I haven't seen this myself, but since we've got customer apps using the library as I originally posted it, I'd like to head off any problems before they're discovered.
|
|
|
|
|
Chris, my input characters are "3578200203952089061510001". After using gspadari's updated code I could generate the bar code which gives me correct result when tested with BCTester. But still my client complains that he could not detect the code by scanning using the bar code scanner machine. Please help me what could be wrong with your original code or gspadari's code which is not working for my input. Thanks, Govind
|
|
|
|
|
I just ran into a problem with the Code C implementation today as well... take away the double quotes and here's my data that doesn't work properly
"2009 w/" - the w scans fine with a hand scanner but corrupts with a common software that recognizes a bar codes
"55sr " - the hand scanner gets this one wrong and drops the s or interprets as a ctrl+s, I'm about to check the software but it's in a separate location so for now I'm assuming it doesn't work either.
"10/29/2009" - works fine....
I'll be wading through the code and will post if I find the problem, but help is definitely appreciated.
|
|
|
|
|
Found it about a week ago... still testing some, but it looks like it's fixed. It was a problem of figuring out which characterset to switch back to and would switch to A when it was supposed to switch to B, or at least that's what it looked like to me...here's what I did and it seems to work now.
if (CurrCodeSet == CodeSet.CodeC || ((LookAheadAscii != -1) && !CharCompatibleWithCodeset(LookAheadAscii, CurrCodeSet)))
{
switch (CurrCodeSet)
{
case CodeSet.CodeA:
shifter = cCODEB;
CurrCodeSet = CodeSet.CodeB;
break;
case CodeSet.CodeB:
shifter = cCODEA;
CurrCodeSet = CodeSet.CodeA;
break;
case CodeSet.CodeC:
{
CodeSet cs = GetBestCodeSetAB(CharAscii, LookAheadAscii);
switch (cs)
{
case CodeSet.CodeA:
shifter = cCODEA;
CurrCodeSet = CodeSet.CodeA;
break;
case CodeSet.CodeB:
shifter = cCODEB;
CurrCodeSet = CodeSet.CodeB;
break;
}
break;
}
}
}
|
|
|
|
|
I've made more modifications to the code. I've also included some "smart" code to know when not to switch to codeC. The noticeable case is a barcode like: "A44A" or "A444" You save a bar by not having to switch twice.
using System;
using System.Collections.Generic;
using System.Text;
namespace GenCode128
{
public enum CodeSet
{
CodeA, CodeB, CodeC
}
/// <summary>
/// Represent the set of code values to be output into barcode form
/// </summary>
public class Code128Content
{
private readonly int[] mCodeList;
/// <summary>
/// Create content based on a string of ASCII data
/// </summary>
/// <param name="AsciiData">the string that should be represented</param>
public Code128Content(string AsciiData)
{
mCodeList = StringToCode128(AsciiData);
}
/// <summary>
/// Provides the Code128 code values representing the object's string
/// </summary>
public int[] Codes
{
get { return mCodeList; }
}
/// <summary>
/// Transform the string into integers representing the Code128 codes
/// necessary to represent it
/// </summary>
/// <param name="AsciiData">String to be encoded</param>
/// <returns>Code128 representation</returns>
private static int[] StringToCode128(string AsciiData)
{
// turn the string into ascii byte data
byte[] asciiBytes = Encoding.ASCII.GetBytes(AsciiData);
// decide which codeset to start with
CodeSet currcs = Code128Code.GetBestCodeSet(asciiBytes, 0);
// set up the beginning of the barcode
List<int> codes = new List<int>();
codes.Add(Code128Code.StartCodeForCodeSet(currcs));
// add the codes for each character in the string
for (int i = 0; i < asciiBytes.Length; i++)
{
codes.AddRange(Code128Code.CodesForChar(asciiBytes, i, ref currcs));
//Jump 2 bytes if Code C is active
if (currcs == CodeSet.CodeC)
i++;
}
// calculate the check digit
int checksum = codes[0];
for (int i = 1; i < codes.Count; i++)
{
checksum += i * codes[i];
}
codes.Add(checksum % 103);
codes.Add(Code128Code.StopCode());
int[] result = codes.ToArray();
return result;
}
}
/// <summary>
/// Static tools for determining codes for individual characters in the content
/// </summary>
public static class Code128Code
{
#region Constants
private const int cSHIFT = 98;
private const int cCODEA = 101;
private const int cCODEB = 100;
private const int cCODEC = 99;
private const int cSTARTA = 103;
private const int cSTARTB = 104;
private const int cSTARTC = 105;
private const int cSTOP = 106;
#endregion
/// <summary>
/// Determines the best starting code set based on the the first two
/// characters of the string to be encoded
/// </summary>
/// <param name="csa1">First character of input string</param>
/// <param name="csa2">Second character of input string</param>
/// <returns>The codeset determined to be best to start with</returns>
private static CodeSet GetBestStartSet(Code128Code.CodeSetAllowed csa1, Code128Code.CodeSetAllowed csa2)
{
int vote = 0;
vote += (csa1 == Code128Code.CodeSetAllowed.CodeA) ? 1 : 0;
vote += (csa1 == Code128Code.CodeSetAllowed.CodeB) ? -1 : 0;
vote += (csa2 == Code128Code.CodeSetAllowed.CodeA) ? 1 : 0;
vote += (csa2 == Code128Code.CodeSetAllowed.CodeB) ? -1 : 0;
return (vote > 0) ? CodeSet.CodeA : CodeSet.CodeB; // ties go to codeB due to my own prejudices
}
/// <summary>
/// Determines the best starting code set based on the the char1 and char2
/// </summary>
/// <returns>The codeset determined to be best to start with</returns>
public static CodeSet GetBestCodeSet(byte[] asciiBytes, int position)
{
int char1 = asciiBytes.Length > position ? asciiBytes[position] : -1;
int char2 = asciiBytes.Length > position+1 ? asciiBytes[position + 1] : -1;
// check for Code C: If first 2 bytes are numeric, then we use Code C
if (asciiBytes.Length > position + 1)
{
if (Code128Code.IsCodeCAllowedForChar(asciiBytes[position], asciiBytes[position+1]))
return CodeSet.CodeC;
}
Code128Code.CodeSetAllowed csa1 = char1 != -1
? Code128Code.CodesetAllowedForChar(char1)
: Code128Code.CodeSetAllowed.CodeAorB;
Code128Code.CodeSetAllowed csa2 = char2 != -1
? Code128Code.CodesetAllowedForChar(char2)
: Code128Code.CodeSetAllowed.CodeAorB;
return GetBestStartSet(csa1, csa2);
}
/// <summary>
/// Get the Code128 code value(s) to represent an ASCII character, with
/// optional look-ahead for length optimization
/// </summary>
/// <param name="position"></param>
/// <param name="asciiBytes"></param>
/// <param name="CurrCodeSet">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</param>
/// <returns>An array of integers representing the codes that need to be output to produce the
/// given character</returns>
public static int[] CodesForChar(byte[] asciiBytes, int position, ref CodeSet CurrCodeSet)
{
int CharAscii = asciiBytes[position];
int LookAheadAscii = asciiBytes.Length > (position + 1) ? asciiBytes[position + 1] : -1;
int LookAheadAscii2 = asciiBytes.Length > (position + 2) ? asciiBytes[position + 2] : -1;
int LookAheadAscii3 = asciiBytes.Length > (position + 3) ? asciiBytes[position + 3] : -1;
int[] result;
int shifter = -1;
// We don't need to switch CodeSet if we are using Code C and the next 2 chars are compatible with it
if (CurrCodeSet == CodeSet.CodeC && IsCodeCAllowedForChar(CharAscii, LookAheadAscii))
{
result = new int[1];
result[0] = CodeCValueForChars(CharAscii, LookAheadAscii);
return result;
}
//If our next 2 chars are compatible with Code C, switch to it.
//Actually... Only make the switch if the next 4 characters are compatable. Here's the cases.
// 00 the cost is 2 characters, once to switch to code C, one for the numbers. 2 vs 2
// 000 It's more expensive, because switch to code c, 00, switch to code a, last number. 4 vs 3
// 00a The cost is more expensive, once to switch to code c, one for the numbers, one to go to code a, then the letter. 4 Vs 3
// 0000 switch to code c, first number, second number. 3 vs 4
// 0000a switch to code c, first number, second number, switch to code a, last letter, 4 vs 5
if (IsCodeCAllowedForChar(CharAscii, LookAheadAscii) && IsCodeCAllowedForChar(LookAheadAscii2, LookAheadAscii3))
{
CurrCodeSet = CodeSet.CodeC;
result = new int[2];
result[0] = cCODEC;
result[1] = CodeCValueForChars(CharAscii, LookAheadAscii);
return result;
}
if (!CharCompatibleWithCodeset(CharAscii, LookAheadAscii, CurrCodeSet))
{
// If we are working with Code C or if we have a lookahead character AND if the next character is ALSO not compatible
if (CurrCodeSet == CodeSet.CodeC
|| ((LookAheadAscii != -1) && !CharCompatibleWithCodeset(LookAheadAscii, -1, CurrCodeSet)))
{
// we need to switch code sets
switch (CurrCodeSet)
{
case CodeSet.CodeA:
shifter = cCODEB;
CurrCodeSet = CodeSet.CodeB;
break;
case CodeSet.CodeB:
shifter = cCODEA;
CurrCodeSet = CodeSet.CodeA;
break;
case CodeSet.CodeC:
CodeSet cs = GetBestCodeSet(asciiBytes, position);
switch (cs)
{
case CodeSet.CodeA:
shifter = cCODEA;
CurrCodeSet = CodeSet.CodeA;
break;
case CodeSet.CodeB:
shifter = cCODEB;
CurrCodeSet = CodeSet.CodeB;
break;
case CodeSet.CodeC:
throw new Exception("We don't want to shift to CodeC if it not allowed.");
}
break;
}
}
else
{
// no need to switch code sets, a temporary SHIFT will suffice
shifter = cSHIFT;
}
}
if (shifter != -1)
{
result = new int[2];
result[0] = shifter;
CodeSet shiftedCodeSet;
switch (shifter)
{
case cCODEA:
shiftedCodeSet = CodeSet.CodeA;
break;
case cCODEB:
shiftedCodeSet = CodeSet.CodeB;
break;
case cSHIFT:
switch (CurrCodeSet)
{
case CodeSet.CodeA:
shiftedCodeSet = CodeSet.CodeB;
break;
case CodeSet.CodeB:
shiftedCodeSet = CodeSet.CodeA;
break;
default:
throw new ArgumentOutOfRangeException();
}
break;
default:
throw new ArgumentOutOfRangeException();
}
result[1] = CodeValueForChar(CharAscii, shiftedCodeSet);
}
else
{
result = new int[1];
result[0] = CodeValueForChar(CharAscii, CurrCodeSet);
}
return result;
}
/// <summary>
/// Tells us which codesets a given character value is allowed in
/// </summary>
/// <param name="CharAscii">ASCII value of character to look at</param>
/// <returns>Which codeset(s) can be used to represent this character</returns>
public static CodeSetAllowed CodesetAllowedForChar(int CharAscii)
{
if (CharAscii >= 32 && CharAscii <= 95)
{
return CodeSetAllowed.CodeAorB;
}
return (CharAscii < 32) ? CodeSetAllowed.CodeA : CodeSetAllowed.CodeB;
}
/// <summary>
/// Tells us if Code C is compatible with the 2 parameter bytes
/// </summary>
/// <param name="CharAscii">First char</param>
/// <param name="NextCharAscii">Second char</param>
/// <returns>Which codeset(s) can be used to represent this character</returns>
public static bool IsCodeCAllowedForChar(int CharAscii, int NextCharAscii)
{
if (CharAscii == -1 && NextCharAscii == -1)
return false;
return CharAscii >= 48 && CharAscii <= 57 && NextCharAscii >= 48 && NextCharAscii <= 57;
}
/// <summary>
/// Determine if a character can be represented in a given codeset
/// </summary>
/// <param name="CharAscii">character to check for</param>
/// <param name="NextCharAscii"></param>
/// <param name="currcs">codeset context to test</param>
/// <returns>true if the codeset contains a representation for the ASCII character</returns>
public static bool CharCompatibleWithCodeset(int CharAscii, int NextCharAscii, CodeSet currcs)
{
if (currcs == CodeSet.CodeC)
{
return IsCodeCAllowedForChar(CharAscii, NextCharAscii);
}
CodeSetAllowed csa = CodesetAllowedForChar(CharAscii);
return csa == CodeSetAllowed.CodeAorB
|| (csa == CodeSetAllowed.CodeA && currcs == CodeSet.CodeA)
|| (csa == CodeSetAllowed.CodeB && currcs == CodeSet.CodeB);
}
/// <summary>
/// Gets the integer code128 code value for a character (assuming the appropriate code set)
/// </summary>
/// <param name="CharAscii">character to convert</param>
/// <param name="currcs">The current Codeset</param>
/// <returns>code128 symbol value for the character</returns>
public static int CodeValueForChar(int CharAscii, CodeSet currcs)
{
if (CharCompatibleWithCodeset(CharAscii, -1, currcs) == false)
throw new Exception("Encoding error. For some reason, we're trying to encode ASCII char " + CharAscii + " in codeset " + currcs);
return (CharAscii >= 32) ? CharAscii - 32 : CharAscii + 64;
}
/// <summary>
/// Gets the integer code128 code value for pair character (assuming Code C)
/// </summary>
/// <param name="CharAscii">First character to convert</param>
/// <param name="NextCharAscii">Second character to convert</param>
/// <returns>code128 symbol value for the character</returns>
public static int CodeCValueForChars(int CharAscii, int NextCharAscii)
{
return (CharAscii - 48) * 10 + NextCharAscii - 48;
}
/// <summary>
/// Return the appropriate START code depending on the codeset we want to be in
/// </summary>
/// <param name="cs">The codeset you want to start in</param>
/// <returns>The code128 code to start a barcode in that codeset</returns>
public static int StartCodeForCodeSet(CodeSet cs)
{
switch (cs)
{
case CodeSet.CodeA:
return cSTARTA;
case CodeSet.CodeB:
return cSTARTB;
case CodeSet.CodeC:
return cSTARTC;
}
throw new Exception("Must be a CodeSet specified");
}
/// <summary>
/// Return the Code128 stop code
/// </summary>
/// <returns>the stop code</returns>
public static int StopCode()
{
return cSTOP;
}
/// <summary>
/// Indicates which code sets can represent a character -- CodeA, CodeB, or either
/// </summary>
public enum CodeSetAllowed
{
CodeA, CodeB, CodeAorB
}
}
}
|
|
|
|
|
using System;
using NUnit.Framework;
using GenCode128;
namespace GenCode128Tests
{
/// <summary>
/// Summary description for Content.
/// </summary>
[TestFixture]
public class ContentTests
{
private const int cSHIFT = 98;
private const int cCODEA = 101;
private const int cCODEB = 100;
[Test]
public void CharRangeTests()
{
Assert.AreEqual(Code128Code.CodeSetAllowed.CodeAorB, Code128Code.CodesetAllowedForChar(66), "Incorrect codeset requirement returned");
Assert.AreEqual(Code128Code.CodeSetAllowed.CodeA, Code128Code.CodesetAllowedForChar(17), "Incorrect codeset requirement returned");
Assert.AreEqual(Code128Code.CodeSetAllowed.CodeB, Code128Code.CodesetAllowedForChar(110), "Incorrect codeset requirement returned");
}
[Test]
public void CharTranslationTests()
{
// in CodeA, thischar Either, nextchar Either
byte thischar = 66;
byte nextchar = 66;
CodeSet currcs = CodeSet.CodeA;
CodeSet origcs = currcs;
int[] resultcodes = Code128Code.CodesForChar(new byte[] { thischar, nextchar }, 0, ref currcs);
Assert.IsNotNull(resultcodes, "No codes returned");
Assert.AreEqual(1, resultcodes.Length, "Incorrect number of codes returned");
Assert.AreEqual(34, resultcodes[0], "Incorrect code returned");
Assert.AreEqual(origcs, currcs, "Incorrect code set returned");
// in CodeA, thischar CodeA, nextchar Either
thischar = 1; // "^A"
nextchar = 66;
currcs = CodeSet.CodeA;
origcs = currcs;
resultcodes = Code128Code.CodesForChar(new byte[] { thischar, nextchar }, 0, ref currcs);
Assert.IsNotNull(resultcodes, "No codes returned");
Assert.AreEqual(1, resultcodes.Length, "Incorrect number of codes returned");
Assert.AreEqual(65, resultcodes[0], "Incorrect code returned");
Assert.AreEqual(origcs, currcs, "Incorrect code set returned");
// in CodeA, thischar CodeB, nextchar Either
thischar = 110; // "n"
nextchar = 66;
currcs = CodeSet.CodeA;
origcs = currcs;
resultcodes = Code128Code.CodesForChar(new byte[] { thischar, nextchar }, 0, ref currcs);
Assert.IsNotNull(resultcodes, "No codes returned");
Assert.AreEqual(2, resultcodes.Length, "Incorrect number of codes returned");
Assert.AreEqual(cSHIFT, resultcodes[0], "Incorrect code returned");
Assert.AreEqual(78, resultcodes[1], "Incorrect code returned");
Assert.AreEqual(origcs, currcs, "Incorrect code set returned");
// in CodeA, thischar Either, nextchar -1
thischar = 66; // "B"
currcs = CodeSet.CodeA;
origcs = currcs;
resultcodes = Code128Code.CodesForChar(new byte[] { thischar }, 0, ref currcs);
Assert.IsNotNull(resultcodes, "No codes returned");
Assert.AreEqual(1, resultcodes.Length, "Incorrect number of codes returned");
Assert.AreEqual(34, resultcodes[0], "Incorrect code returned");
Assert.AreEqual(origcs, currcs, "Incorrect code set returned");
// in CodeA, thischar CodeA, nextchar -1
thischar = 1; // "^A"
currcs = CodeSet.CodeA;
origcs = currcs;
resultcodes = Code128Code.CodesForChar(new byte[] { thischar }, 0, ref currcs);
Assert.IsNotNull(resultcodes, "No codes returned");
Assert.AreEqual(1, resultcodes.Length, "Incorrect number of codes returned");
Assert.AreEqual(65, resultcodes[0], "Incorrect code returned");
Assert.AreEqual(origcs, currcs, "Incorrect code set returned");
// in CodeA, thischar CodeB, nextchar -1
thischar = 110; // "n"
currcs = CodeSet.CodeA;
origcs = currcs;
resultcodes = Code128Code.CodesForChar(new byte[] { thischar }, 0, ref currcs);
Assert.IsNotNull(resultcodes, "No codes returned");
Assert.AreEqual(2, resultcodes.Length, "Incorrect number of codes returned");
Assert.AreEqual(cSHIFT, resultcodes[0], "Incorrect code returned");
Assert.AreEqual(78, resultcodes[1], "Incorrect code returned");
Assert.AreEqual(origcs, currcs, "Incorrect code set returned");
// in CodeA, thischar Either, nextchar CodeA
thischar = 66; // "B"
nextchar = 1;
currcs = CodeSet.CodeA;
origcs = currcs;
resultcodes = Code128Code.CodesForChar(new byte[] { thischar, nextchar }, 0, ref currcs);
Assert.IsNotNull(resultcodes, "No codes returned");
Assert.AreEqual(1, resultcodes.Length, "Incorrect number of codes returned");
Assert.AreEqual(34, resultcodes[0], "Incorrect code returned");
Assert.AreEqual(origcs, currcs, "Incorrect code set returned");
// in CodeA, thischar CodeA, nextchar CodeA
thischar = 1; // "^A"
nextchar = 1;
currcs = CodeSet.CodeA;
origcs = currcs;
resultcodes = Code128Code.CodesForChar(new byte[] { thischar, nextchar }, 0, ref currcs);
Assert.IsNotNull(resultcodes, "No codes returned");
Assert.AreEqual(1, resultcodes.Length, "Incorrect number of codes returned");
Assert.AreEqual(65, resultcodes[0], "Incorrect code returned");
Assert.AreEqual(origcs, currcs, "Incorrect code set returned");
// in CodeA, thischar CodeB, nextchar CodeA
thischar = 110; // "n"
nextchar = 1;
currcs = CodeSet.CodeA;
origcs = currcs;
resultcodes = Code128Code.CodesForChar(new byte[] { thischar, nextchar }, 0, ref currcs);
Assert.IsNotNull(resultcodes, "No codes returned");
Assert.AreEqual(2, resultcodes.Length, "Incorrect number of codes returned");
Assert.AreEqual(cSHIFT, resultcodes[0], "Incorrect code returned");
Assert.AreEqual(78, resultcodes[1], "Incorrect code returned");
Assert.AreEqual(origcs, currcs, "Incorrect code set returned");
// in CodeA, thischar Either, nextchar CodeB
thischar = 66; // "B"
nextchar = 110;
currcs = CodeSet.CodeA;
origcs = currcs;
resultcodes = Code128Code.CodesForChar(new byte[] { thischar, nextchar }, 0, ref currcs);
Assert.IsNotNull(resultcodes, "No codes returned");
Assert.AreEqual(1, resultcodes.Length, "Incorrect number of codes returned");
Assert.AreEqual(34, resultcodes[0], "Incorrect code returned");
Assert.AreEqual(origcs, currcs, "Incorrect code set returned");
// in CodeA, thischar CodeA, nextchar CodeB
thischar = 1; // "^A"
nextchar = 110;
currcs = CodeSet.CodeA;
origcs = currcs;
resultcodes = Code128Code.CodesForChar(new byte[] { thischar, nextchar }, 0, ref currcs);
Assert.IsNotNull(resultcodes, "No codes returned");
Assert.AreEqual(1, resultcodes.Length, "Incorrect number of codes returned");
Assert.AreEqual(65, resultcodes[0], "Incorrect code returned");
Assert.AreEqual(origcs, currcs, "Incorrect code set returned");
// in CodeA, thischar CodeB, nextchar CodeB
thischar = 110; // "n"
nextchar = 110;
currcs = CodeSet.CodeA;
origcs = currcs;
resultcodes = Code128Code.CodesForChar(new byte[] { thischar, nextchar }, 0, ref currcs);
Assert.IsNotNull(resultcodes, "No codes returned");
Assert.AreEqual(2, resultcodes.Length, "Incorrect number of codes returned");
Assert.AreEqual(cCODEB, resultcodes[0], "Incorrect code returned");
Assert.AreEqual(78, resultcodes[1], "Incorrect code returned");
Assert.AreNotEqual(origcs, currcs, "Incorrect code set returned");
// in CodeB, thischar Either, nextchar Either
thischar = 66; // "B"
nextchar = 66;
currcs = CodeSet.CodeB;
origcs = currcs;
resultcodes = Code128Code.CodesForChar(new byte[] { thischar, nextchar }, 0, ref currcs);
Assert.IsNotNull(resultcodes, "No codes returned");
Assert.AreEqual(1, resultcodes.Length, "Incorrect number of codes returned");
Assert.AreEqual(34, resultcodes[0], "Incorrect code returned");
Assert.AreEqual(origcs, currcs, "Incorrect code set returned");
// in CodeB, thischar CodeA, nextchar Either
thischar = 1; // "^A"
nextchar = 66;
currcs = CodeSet.CodeB;
origcs = currcs;
resultcodes = Code128Code.CodesForChar(new byte[] { thischar, nextchar }, 0, ref currcs);
Assert.IsNotNull(resultcodes, "No codes returned");
Assert.AreEqual(2, resultcodes.Length, "Incorrect number of codes returned");
Assert.AreEqual(cSHIFT, resultcodes[0], "Incorrect code returned");
Assert.AreEqual(65, resultcodes[1], "Incorrect code returned");
Assert.AreEqual(origcs, currcs, "Incorrect code set returned");
// in CodeB, thischar CodeB, nextchar Either
thischar = 110; // "n"
nextchar = 66;
currcs = CodeSet.CodeB;
origcs = currcs;
resultcodes = Code128Code.CodesForChar(new byte[] { thischar, nextchar }, 0, ref currcs);
Assert.IsNotNull(resultcodes, "No codes returned");
Assert.AreEqual(1, resultcodes.Length, "Incorrect number of codes returned");
Assert.AreEqual(78, resultcodes[0], "Incorrect code returned");
Assert.AreEqual(origcs, currcs, "Incorrect code set returned");
// in CodeB, thischar Either, nextchar -1
thischar = 66; // "B"
currcs = CodeSet.CodeB;
origcs = currcs;
resultcodes = Code128Code.CodesForChar(new byte[] { thischar }, 0, ref currcs);
Assert.IsNotNull(resultcodes, "No codes returned");
Assert.AreEqual(1, resultcodes.Length, "Incorrect number of codes returned");
Assert.AreEqual(34, resultcodes[0], "Incorrect code returned");
Assert.AreEqual(origcs, currcs, "Incorrect code set returned");
// in CodeB, thischar CodeA, nextchar -1
thischar = 1; // "^A"
currcs = CodeSet.CodeB;
origcs = currcs;
resultcodes = Code128Code.CodesForChar(new byte[] { thischar, nextchar }, 0, ref currcs);
Assert.IsNotNull(resultcodes, "No codes returned");
Assert.AreEqual(2, resultcodes.Length, "Incorrect number of codes returned");
Assert.AreEqual(cSHIFT, resultcodes[0], "Incorrect code returned");
Assert.AreEqual(65, resultcodes[1], "Incorrect code returned");
Assert.AreEqual(origcs, currcs, "Incorrect code set returned");
// in CodeB, thischar CodeB, nextchar -1
thischar = 110; // "n"
currcs = CodeSet.CodeB;
origcs = currcs;
resultcodes = Code128Code.CodesForChar(new byte[] { thischar }, 0, ref currcs);
Assert.IsNotNull(resultcodes, "No codes returned");
Assert.AreEqual(1, resultcodes.Length, "Incorrect number of codes returned");
Assert.AreEqual(78, resultcodes[0], "Incorrect code returned");
Assert.AreEqual(origcs, currcs, "Incorrect code set returned");
// in CodeB, thischar Either, nextchar CodeA
thischar = 66; // "B"
nextchar = 1;
currcs = CodeSet.CodeB;
origcs = currcs;
resultcodes = Code128Code.CodesForChar(new byte[] { thischar, nextchar }, 0, ref currcs);
Assert.IsNotNull(resultcodes, "No codes returned");
Assert.AreEqual(1, resultcodes.Length, "Incorrect number of codes returned");
Assert.AreEqual(34, resultcodes[0], "Incorrect code returned");
Assert.AreEqual(origcs, currcs, "Incorrect code set returned");
// in CodeB, thischar CodeA, nextchar CodeA
thischar = 1; // "^A"
nextchar = 1;
currcs = CodeSet.CodeB;
origcs = currcs;
resultcodes = Code128Code.CodesForChar(new byte[] { thischar, nextchar }, 0, ref currcs);
Assert.IsNotNull(resultcodes, "No codes returned");
Assert.AreEqual(2, resultcodes.Length, "Incorrect number of codes returned");
Assert.AreEqual(cCODEA, resultcodes[0], "Incorrect code returned");
Assert.AreEqual(65, resultcodes[1], "Incorrect code returned");
Assert.AreNotEqual(origcs, currcs, "Incorrect code set returned");
// in CodeB, thischar CodeB, nextchar CodeA
thischar = 110; // "n"
nextchar = 1;
currcs = CodeSet.CodeB;
origcs = currcs;
resultcodes = Code128Code.CodesForChar(new byte[] { thischar, nextchar }, 0, ref currcs);
Assert.IsNotNull(resultcodes, "No codes returned");
Assert.AreEqual(1, resultcodes.Length, "Incorrect number of codes returned");
Assert.AreEqual(78, resultcodes[0], "Incorrect code returned");
Assert.AreEqual(origcs, currcs, "Incorrect code set returned");
// in CodeB, thischar Either, nextchar CodeB
thischar = 66; // "B"
nextchar = 110;
currcs = CodeSet.CodeB;
origcs = currcs;
resultcodes = Code128Code.CodesForChar(new byte[] { thischar, nextchar }, 0, ref currcs);
Assert.IsNotNull(resultcodes, "No codes returned");
Assert.AreEqual(1, resultcodes.Length, "Incorrect number of codes returned");
Assert.AreEqual(34, resultcodes[0], "Incorrect code returned");
Assert.AreEqual(origcs, currcs, "Incorrect code set returned");
// in CodeB, thischar CodeA, nextchar CodeB
thischar = 1; // "^A"
nextchar = 110;
currcs = CodeSet.CodeB;
origcs = currcs;
resultcodes = Code128Code.CodesForChar(new byte[] { thischar, nextchar }, 0, ref currcs);
Assert.IsNotNull(resultcodes, "No codes returned");
Assert.AreEqual(2, resultcodes.Length, "Incorrect number of codes returned");
Assert.AreEqual(cSHIFT, resultcodes[0], "Incorrect code returned");
Assert.AreEqual(65, resultcodes[1], "Incorrect code returned");
Assert.AreEqual(origcs, currcs, "Incorrect code set returned");
// in CodeB, thischar CodeB, nextchar CodeB
thischar = 110; // "n"
nextchar = 110;
currcs = CodeSet.CodeB;
origcs = currcs;
resultcodes = Code128Code.CodesForChar(new byte[] { thischar, nextchar }, 0, ref currcs);
Assert.IsNotNull(resultcodes, "No codes returned");
Assert.AreEqual(1, resultcodes.Length, "Incorrect number of codes returned");
Assert.AreEqual(78, resultcodes[0], "Incorrect code returned");
Assert.AreEqual(origcs, currcs, "Incorrect code set returned");
}
[Test]
public void CharCompatibilityTests()
{
int thischar = 66;
Assert.AreEqual(true, Code128Code.CharCompatibleWithCodeset(thischar, -1, CodeSet.CodeA), "Compat test failed");
thischar = 66; // "B"
Assert.AreEqual(true, Code128Code.CharCompatibleWithCodeset(thischar, -1, CodeSet.CodeB), "Compat test failed");
thischar = 17; // "^Q"
Assert.AreEqual(true, Code128Code.CharCompatibleWithCodeset(thischar, -1, CodeSet.CodeA), "Compat test failed");
thischar = 17; // "^Q"
Assert.AreEqual(false, Code128Code.CharCompatibleWithCodeset(thischar, -1, CodeSet.CodeB), "Compat test failed");
thischar = 110; // "n"
Assert.AreEqual(false, Code128Code.CharCompatibleWithCodeset(thischar, -1, CodeSet.CodeA), "Compat test failed");
thischar = 110; // "n"
Assert.AreEqual(true, Code128Code.CharCompatibleWithCodeset(thischar, -1, CodeSet.CodeB), "Compat test failed");
}
[Test]
public void CharValueTranslationTests()
{
Assert.AreEqual(0, Code128Code.CodeValueForChar(32, CodeSet.CodeA), "Code translation wrong");
Assert.AreEqual(31, Code128Code.CodeValueForChar(63, CodeSet.CodeA), "Code translation wrong");
Assert.AreEqual(32, Code128Code.CodeValueForChar(64, CodeSet.CodeA), "Code translation wrong");
Assert.AreEqual(63, Code128Code.CodeValueForChar(95, CodeSet.CodeA), "Code translation wrong");
Assert.AreEqual(64, Code128Code.CodeValueForChar(96, CodeSet.CodeB), "Code translation wrong");
Assert.AreEqual(64, Code128Code.CodeValueForChar(0, CodeSet.CodeA), "Code translation wrong");
Assert.AreEqual(95, Code128Code.CodeValueForChar(31, CodeSet.CodeA), "Code translation wrong");
}
[Test]
public void FullStringTest()
{
Code128Content content = new Code128Content("BarCode 1");
int[] result = content.Codes;
Assert.AreEqual(12, result.Length, "Wrong number of code values in result");
Assert.AreEqual(104, result[0], "Start code wrong");
Assert.AreEqual(34, result[1], "Code value #1 wrong");
Assert.AreEqual(65, result[2], "Code value #2 wrong");
Assert.AreEqual(82, result[3], "Code value #3 wrong");
Assert.AreEqual(35, result[4], "Code value #4 wrong");
Assert.AreEqual(79, result[5], "Code value #5 wrong");
Assert.AreEqual(68, result[6], "Code value #6 wrong");
Assert.AreEqual(69, result[7], "Code value #7 wrong");
Assert.AreEqual(0, result[8], "Code value #8 wrong");
Assert.AreEqual(17, result[9], "Code value #9 wrong");
Assert.AreEqual(33, result[10], "Checksum wrong");
Assert.AreEqual(106, result[11], "Stop character wrong");
content = new Code128Content("\x11S12345");
result = content.Codes;
Assert.AreEqual(10, result.Length, "Wrong number of code values in result");
}
[Test]
public void KnownBug1()
{
Code128Content content = new Code128Content("55sr ");
int[] result = content.Codes;
Assert.AreEqual(8, result.Length, "Wrong number of code values in result");
Assert.AreEqual(105, result[0], "Start code wrong");
Assert.AreEqual(55, result[1], "Code value #1 wrong");
Assert.AreEqual(100, result[2], "Code value #2 wrong");
Assert.AreEqual(83, result[3], "Code value #3 wrong");
Assert.AreEqual(82, result[4], "Code value #4 wrong");
Assert.AreEqual(0, result[5], "Code value #5 wrong");
Assert.AreEqual(10, result[6], "Checksum wrong");
Assert.AreEqual(106, result[7], "Stop character wrong");
}
[Test]
public void KnownBug2()
{
Code128Content content = new Code128Content("2009 w/");
int[] result = content.Codes;
Assert.AreEqual(9, result.Length, "Wrong number of code values in result");
Assert.AreEqual(105, result[0], "Start code wrong");
Assert.AreEqual(20, result[1], "Code value #1 wrong");
Assert.AreEqual(9, result[2], "Code value #2 wrong");
Assert.AreEqual(100, result[3], "Code value #3 wrong");
Assert.AreEqual(0, result[4], "Code value #4 wrong");
Assert.AreEqual(87, result[5], "Code value #5 wrong");
Assert.AreEqual(15, result[6], "Code value #6 wrong");
Assert.AreEqual(41, result[7], "Checksum wrong");
Assert.AreEqual(106, result[8], "Stop character wrong");
}
[Test]
public void Code3Shorter()
{
Code128Content content = new Code128Content("aa00aa");
int[] result = content.Codes;
Assert.AreEqual(9, result.Length, "Wrong number of code values in result");
Assert.AreEqual(104, result[0], "Start code wrong");
Assert.AreEqual(65, result[1], "Code value #1 wrong");
Assert.AreEqual(65, result[2], "Code value #2 wrong");
Assert.AreEqual(16, result[3], "Code value #3 wrong");
Assert.AreEqual(16, result[4], "Code value #4 wrong");
Assert.AreEqual(65, result[5], "Code value #5 wrong");
Assert.AreEqual(65, result[6], "Code value #6 wrong");
Assert.AreEqual(96, result[7], "Checksum wrong");
Assert.AreEqual(106, result[8], "Stop character wrong");
}
[Test]
public void Code3Shorter2()
{
Code128Content content = new Code128Content("aa0000aa");
int[] result = content.Codes;
Assert.AreEqual(11, result.Length, "Wrong number of code values in result");
Assert.AreEqual(104, result[0], "Start code wrong");
Assert.AreEqual(65, result[1], "Code value #1 wrong");
Assert.AreEqual(65, result[2], "Code value #2 wrong");
Assert.AreEqual(99, result[3], "Code value #3 wrong");
Assert.AreEqual(0, result[4], "Code value #4 wrong");
Assert.AreEqual(0, result[5], "Code value #5 wrong");
Assert.AreEqual(100, result[6], "Code value #6 wrong");
Assert.AreEqual(65, result[7], "Code value #6 wrong");
Assert.AreEqual(65, result[8], "Code value #6 wrong");
Assert.AreEqual(8, result[9], "Checksum wrong");
Assert.AreEqual(106, result[10], "Stop character wrong");
}
[Test]
[ExpectedException(typeof(Exception))]
public void ShouldntBeAbleToDoAnInvalidEncode()
{
//Code A doesn't support lower case... this should throw some form of an exception.
GenCode128.Code128Code.CodeValueForChar(115, CodeSet.CodeA);
}
[Test]
[ExpectedException(typeof(Exception))]
public void ShouldntBeAbleToDoAnInvalidEncode2()
{
//Code B doesn't support non printing characters... this should throw some form of an exception.
GenCode128.Code128Code.CodeValueForChar(16, CodeSet.CodeB);
}
}
}
|
|
|
|
|
Thanks for this excellent article.
Btw, I think I've found a bug. If my barcode is one character length, then I get an IndexOutOfRangeException on line 53:
Code128Code.CodeSetAllowed csa2 = asciiBytes.Length>0 ? Code128Code.CodesetAllowedForChar( asciiBytes[1] ) : Code128Code.CodeSetAllowed.CodeAorB;
If we put this conditional: "asciiBytes.Length>1 " the problem is gone, but I'm not sure if the implementation will be OK.
Thanks.
Gustavo.
|
|
|
|
|
Ouch! You're quite right!
Yes, I'm pretty sure that your proposed solution is the correct one. When the conditional operator using the "1" comparison evaluates false, it would be applying the CodeAorB value, which indicates that we don't care whether it's A or B -- exactly the desired outcome if there's no character for it to represent.
Thanks for taking the time to look into the code to find the solution.
|
|
|
|
|
Hallo i have a question about the lenght ot the code? How many bites can code128 be??
The article is very usefull??
|
|
|
|
|
The length is driven by the practical consideration of what your scanner can read. It's got to have an angle wide enough to view the entire "message" while at a distance that's close enough for it to illuminate the whole thing. This is going to depend on the device you're using, so I would suggest that you just experiment to see what you can get. This library can easily handle anything you'll be able to use in the real world.
|
|
|
|
|
Hi,
First of all: Nice application!
I have tried it, it works very well.
Now I would like to use the printfunction to print the barcode to a label. I am using a Dymo label printer for this. Where should I configure to print the barcode to a label?
|
|
|
|
|
I don't know anything about Dymo label printers, and since the EXE that I included is only intended to be a sample for the barcodes themselves, the printing support is absolutely minimal. In particular, it doesn't even let you select the printer -- it just uses the system's default printer.
You might go to Printers and Faxes in your Control Panel, and set the Dymo device to be the default (you can always switch back later). Then use the application to print and see what happens.
Good luck, but I make no promises.
|
|
|
|
|
You can print to a particular printer by setting the "PrinterName".
<br />
public void PrintToPrinter( string printerName, System.Drawing.Printing.PrintDocument printDocument1 )<br />
{<br />
PrintDialog pd = new PrintDialog();<br />
pd.Document = printDocument1;<br />
pd.PrinterSettings.PrinterName = printerName ;<br />
try<br />
{<br />
pd.Document.Print();<br />
}<br />
catch<br />
{<br />
MessageBox.Show("INVALID PRINTER SPECIFIED");<br />
}<br />
}<br />
http://www.blakerobertson.com
|
|
|
|
|
Just wanted to thank you for your efforts. I am using your application to generate barcodes now.
|
|
|
|
|
I saw
"Error 2 The type or namespace name 'Test' could not be found (are you missing a using directive or an assembly reference?) D:\GenCode128\GenCode128Tests\ContentTest.cs 18 8 GenCode128Tests "
when I compiling your sample code. There was not "NUnit.Framework" in your files. Please help me to solve my problem. I am using Visual 2005.
|
|
|
|
|
That is a good question -- I probably should have noted this in the article.
Solution 1: Just remove the GenCode128Tests project from the solution. They're for testing only, and have no effect on the finished product.
Solution 2: Get NUnit. It's free, and you can download it from http://nunit.org/[^] . It's worth looking at; it might help your code too.
|
|
|
|
|
Hi,
I like this barcode.
However, how can I add in the "Title" at the top of the barcode and the "barcode number" below the barcode?
The "barcode number" is more useful, in-term tat most ppl use it :X then the title
Thanks
-- modified at 1:03 Monday 13th November, 2006
|
|
|
|
|
I finally got some free time after handing over some of my sites to other staff.
I wrote the code to the bottom part of the make image class so I could have the Barcode Number at the bottom, hope these code will help some1...
and i dun think my code is efficent enuf
/*******************************Start of Barcode Number Text*******************************/
Image text = new Bitmap(width, 10);
Font txtFont = new Font("Arial", 8, FontStyle.Regular, GraphicsUnit.Pixel);
using (Graphics txtTool = Graphics.FromImage(text))
{
txtTool.FillRectangle(Brushes.White, 0, 0, width, 10);
int cursor = AddQuietZone ? cQuietWidth * BarWeight : 0;
txtTool.DrawString(InputData.ToUpper(), txtFont, Brushes.Black, cursor, 0);
}
/********************************End of Barcode Number Text********************************/
/*******************************Start of Merging Image*******************************/
Image merged = new Bitmap(width, height + 10);
using (Graphics mergeTool = Graphics.FromImage(merged))
{
mergeTool.DrawImage(myimg, 0, 0);
mergeTool.DrawImage(text, 0, height);
}
/********************************End of Merging Image********************************/
|
|
|
|
|
Cool. Thanks for the contribution. FWIW, what you've done is probably about the same way I'd have approached it. I don't think my code in this library is the optimally efficient, but I tested the performance a bit, and found that even if it might be better, it's still pretty darned fast.
I'm not sure when I'll get around to it, but do you mind if I incorporate your code into the next revision of the library?
|
|
|
|
|
|
Does anyone have a working version of this code that they could possibly send to me please because when I download the zip it will not open, if anyone can post a link or email me the code I would be eternally grateful.
Ian
|
|
|
|
|
Hi,
Thanks for this terrific article!
I have converted your code to VB for an ASP.Net 2.0 project. Only problem is the ASP picturebox does not take an image parameter. It does have an imageurl parameter which works ok if you first write out the barcode image to disk and then plug the path/file ID into the imageurl. Do you know of a way to place the image directly onto a web page? I'd like to avoid the disk I/O.
PS: If you would like a copy of my ASP/VB sample project let me know.
Bill
|
|
|
|
|
That makes sense, as there's no way to put anything but text and (some types of) formatting information "directly on a web page". The web page itself is nothing but HTML. Everything graphic on a page -- banners, etc. -- is acquired by subsequent requests for resources referenced by the main HTML.
So you need a way to return to the browser the image that should be put into that site on the page. I think there are 2 ways to approach this.
- Pre-generate the image when the HTML is being built, so that the request for the image can be trivially handled by retrieving a file that actually exists.
- Encoding barcode content in the image URL without actually generating the image; then generate the image on-the-fly.
I don't like #1 because it forces you to worry about managing the files (e.g., deleting them periodically) as well as worrying about allowing file write permissions to the filesystem.
However, #2 is quite practical. Any reasonable barcode should have a value short enough to easily express as a URL with a GET request. So you always include an image URL of
http://myserver.com/myapp/barcode.aspx?code=abcdef
When your barcode.aspx page is invoked, it just needs to return an image encoding abcdef rather than HTML as you're accustomed. This might sound difficult, but it's pretty easy. A quick search here yields some candidates:
- http://www.codeproject.com/aspnet/aspnet_web_graphics.asp[^]
- http://www.codeproject.com/aspnet/DynamicASPDotNETTextImage.asp[^]
Good luck!
-- modified at 11:37 Thursday 3rd August, 2006
|
|
|
|
|
hi,
I am trying to generate the barcode on a asp.net page.
I am a beginner.
I tried using your code but I was unsuccesful.
Can you please help me out.
thank you
sai
|
|
|
|
|