diff --git a/Source/GenCode128/Code128Code.cs b/Source/GenCode128/Code128Code.cs
index edc41ed..46247f9 100644
--- a/Source/GenCode128/Code128Code.cs
+++ b/Source/GenCode128/Code128Code.cs
@@ -1,20 +1,19 @@
namespace GenCode128
{
+ using System;
+
///
/// Static tools for determining codes for individual characters in the content
///
public static class Code128Code
{
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;
///
@@ -23,15 +22,14 @@ public static class Code128Code
public enum CodeSetAllowed
{
CodeA,
-
CodeB,
-
- CodeAorB
+ CodeC,
+ CodeAorB,
+ CodeAorBorC
}
///
- /// Get the Code128 code value(s) to represent an ASCII character, with
- /// optional look-ahead for length optimization
+ /// Get the Code128 code value(s) to represent an ASCII character
///
/// The ASCII value of the character to translate
/// The next character in sequence (or -1 if none)
@@ -39,51 +37,120 @@ public enum CodeSetAllowed
/// 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 charAscii, int lookAheadAscii, ref CodeSet currentCodeSet)
+ public static int[] CodesForChar(ref int[] charAscii, ref CodeSet currentCodeSet, ref int outerIndex)
{
int[] result;
var shifter = -1;
+ var whatToConvert = -1;
+ CodeSet bestCodeSet;
+
+ // Let's find out which is the best set to use
+ bestCodeSet = BestFitSet(ref charAscii, currentCodeSet, ref shifter);
- if (!CharCompatibleWithCodeset(charAscii, currentCodeSet))
+ // We`re not in the right CodeSet, so we should change it
+ if (currentCodeSet != bestCodeSet)
{
- // if we have a lookahead character AND if the next character is ALSO not compatible
- if ((lookAheadAscii != -1) && !CharCompatibleWithCodeset(lookAheadAscii, currentCodeSet))
+ switch (bestCodeSet)
{
- // we need to switch code sets
- switch (currentCodeSet)
- {
- case CodeSet.CodeA:
- shifter = CCodeB;
- currentCodeSet = CodeSet.CodeB;
- break;
- case CodeSet.CodeB:
- shifter = CCodeA;
- currentCodeSet = CodeSet.CodeA;
- break;
- }
- }
- else
- {
- // no need to switch code sets, a temporary SHIFT will suffice
- shifter = CShift;
+ case CodeSet.CodeA:
+ shifter = CCodeA;
+ currentCodeSet = CodeSet.CodeA;
+ break;
+ case CodeSet.CodeB:
+ shifter = CCodeB;
+ currentCodeSet = CodeSet.CodeB;
+ break;
+ case CodeSet.CodeC:
+ shifter = CCodeC;
+ currentCodeSet = CodeSet.CodeC;
+ break;
}
}
+ // Check if is A/B or C and fill convert, but if it`s CodeSetC, we should code 2 at a time, instead of just one
+ switch (currentCodeSet)
+ {
+ case CodeSet.CodeA:
+ case CodeSet.CodeB:
+ whatToConvert = charAscii[0];
+ break;
+ case CodeSet.CodeC:
+ whatToConvert = (Convert.ToInt32(Char.ConvertFromUtf32(charAscii[0])) * 10) + (Convert.ToInt32(Char.ConvertFromUtf32(charAscii[1])));
+ outerIndex++;
+ break;
+ }
+
if (shifter != -1)
{
result = new int[2];
result[0] = shifter;
- result[1] = CodeValueForChar(charAscii);
+ result[1] = CodeValueForChar(whatToConvert, currentCodeSet);
}
else
{
result = new int[1];
- result[0] = CodeValueForChar(charAscii);
+ result[0] = CodeValueForChar(whatToConvert, currentCodeSet);
}
return result;
}
+ ///
+ /// Determines the best codeset to use, based on Code128 heuristics and optimizations
+ ///
+ /// characters to check for
+ /// codeset context to test
+ /// a reference for the shifter
+ /// the best codeset to be used. Shift is also modified if necessary.
+ public static CodeSet BestFitSet(ref int[] charAscii, CodeSet currentCodeSet, ref int shifter)
+ {
+ bool bestA = false;
+ bool bestC = false;
+ bool commingFromC = false;
+ //bool bestB = false;
+
+ // Optimizing to use CodeSetC. If 6+ are numbers OR we're in the last 4 of the set, and all are numbers
+ // Care that we run from 0 to 5 -- Running through 6 and also checking >=3 which means the 4th ahead
+ if (currentCodeSet != CodeSet.CodeC)
+ {
+ bestC = true;
+ for (int i = 0; i < 6; i++)
+ {
+ bestC = bestC && (CharCompatibleWithCodeset(charAscii[i], CodeSet.CodeC) ? ((charAscii[4] != -1 && charAscii[5] == -1) ? false : true) : ((charAscii[i] == -1 && i > 3) ? true : false));
+ if (!bestC)
+ break;
+ }
+ }
+ else
+ {
+ // if we're already in C, let's check if we can code at least 2 ascii
+ if (CharCompatibleWithCodeset(charAscii[0], CodeSet.CodeC) && CharCompatibleWithCodeset(charAscii[1], CodeSet.CodeC))
+ {
+ bestC = true;
+ }
+ commingFromC = true;
+ }
+
+ if (CharCompatibleWithCodeset(charAscii[0], CodeSet.CodeA))
+ {
+ // if we have a lookahead character AND if the next character is ALSO not compatible
+ if ((charAscii[1] != -1) && (commingFromC || CharCompatibleWithCodeset(charAscii[1], CodeSet.CodeA)))
+ {
+ // we need to switch code sets
+ bestA = true;
+ }
+ else
+ {
+ // no need to switch code sets, a temporary SHIFT will suffice
+ shifter = CShift;
+ }
+ }
+
+ //Since we've already checked C and A, if both are False, we can only use CodeSetB
+ // Select the prefered one, putting CodeSetC as the first, since it's optimized
+ return bestC ? CodeSet.CodeC : (bestA ? CodeSet.CodeA : CodeSet.CodeB);
+ }
+
///
/// Tells us which codesets a given character value is allowed in
///
@@ -91,13 +158,17 @@ public static int[] CodesForChar(int charAscii, int lookAheadAscii, ref CodeSet
/// Which codeset(s) can be used to represent this character
public static CodeSetAllowed CodesetAllowedForChar(int charAscii)
{
- if (charAscii >= 32 && charAscii <= 95)
+ if (charAscii >= 48 && charAscii <= 57)
+ {
+ return CodeSetAllowed.CodeC;
+ }
+ else if (charAscii >= 32 && charAscii <= 95)
{
return CodeSetAllowed.CodeAorB;
}
else
{
- return charAscii < 32 ? CodeSetAllowed.CodeA : CodeSetAllowed.CodeB;
+ return (charAscii < 32) ? CodeSetAllowed.CodeA : CodeSetAllowed.CodeB;
}
}
@@ -110,7 +181,9 @@ public static CodeSetAllowed CodesetAllowedForChar(int charAscii)
public static bool CharCompatibleWithCodeset(int charAscii, CodeSet currentCodeSet)
{
var csa = CodesetAllowedForChar(charAscii);
- return csa == CodeSetAllowed.CodeAorB || (csa == CodeSetAllowed.CodeA && currentCodeSet == CodeSet.CodeA)
+ return (csa == CodeSetAllowed.CodeC && currentCodeSet == CodeSet.CodeC)
+ || (csa == CodeSetAllowed.CodeAorB && (currentCodeSet == CodeSet.CodeA || currentCodeSet == CodeSet.CodeB))
+ || (csa == CodeSetAllowed.CodeA && currentCodeSet == CodeSet.CodeA)
|| (csa == CodeSetAllowed.CodeB && currentCodeSet == CodeSet.CodeB);
}
@@ -119,9 +192,9 @@ public static bool CharCompatibleWithCodeset(int charAscii, CodeSet currentCodeS
///
/// character to convert
/// code128 symbol value for the character
- public static int CodeValueForChar(int charAscii)
+ public static int CodeValueForChar(int charAscii, CodeSet currentCodeSet)
{
- return charAscii >= 32 ? charAscii - 32 : charAscii + 64;
+ return currentCodeSet == CodeSet.CodeC ? charAscii : ((charAscii >= 32) ? charAscii - 32 : charAscii + 64);
}
///
@@ -131,7 +204,7 @@ public static int CodeValueForChar(int charAscii)
/// The code128 code to start a barcode in that codeset
public static int StartCodeForCodeSet(CodeSet cs)
{
- return cs == CodeSet.CodeA ? CStartA : CStartB;
+ return cs == CodeSet.CodeA ? CStartA : (cs == CodeSet.CodeB ? CStartB : CStartC);
}
///
diff --git a/Source/GenCode128/Code128Content.cs b/Source/GenCode128/Code128Content.cs
index 1ef32b6..8a98871 100644
--- a/Source/GenCode128/Code128Content.cs
+++ b/Source/GenCode128/Code128Content.cs
@@ -32,27 +32,44 @@ private int[] StringToCode128(string asciiData)
{
// turn the string into ascii byte data
var asciiBytes = Encoding.ASCII.GetBytes(asciiData);
+
+ // a support array, for our lookahead
+ int[] nextchar = new int[6];
+
+ // a support array for us to choose which is the best starting code
+ Code128Code.CodeSetAllowed[] csa = new Code128Code.CodeSetAllowed[4];
// decide which codeset to start with
- var csa1 = asciiBytes.Length > 0
- ? Code128Code.CodesetAllowedForChar(asciiBytes[0])
- : Code128Code.CodeSetAllowed.CodeAorB;
- var csa2 = asciiBytes.Length > 1
- ? Code128Code.CodesetAllowedForChar(asciiBytes[1])
- : Code128Code.CodeSetAllowed.CodeAorB;
- var currentCodeSet = this.GetBestStartSet(csa1, csa2);
+
+ csa[0] = asciiBytes.Length > 0
+ ? Code128Code.CodesetAllowedForChar(asciiBytes[0])
+ : Code128Code.CodeSetAllowed.CodeAorBorC;
+ csa[1] = asciiBytes.Length > 1
+ ? Code128Code.CodesetAllowedForChar(asciiBytes[1])
+ : Code128Code.CodeSetAllowed.CodeAorBorC;
+ csa[2] = asciiBytes.Length > 2
+ ? Code128Code.CodesetAllowedForChar(asciiBytes[2])
+ : Code128Code.CodeSetAllowed.CodeAorBorC;
+ csa[3] = asciiBytes.Length > 3
+ ? Code128Code.CodesetAllowedForChar(asciiBytes[3])
+ : Code128Code.CodeSetAllowed.CodeAorBorC;
+ var currentCodeSet = this.GetBestStartSet(csa);
// set up the beginning of the barcode
// assume no codeset changes, account for start, checksum, and stop
var codes = new ArrayList(asciiBytes.Length + 3) { Code128Code.StartCodeForCodeSet(currentCodeSet) };
-
- // add the codes for each character in the string
+
+ // add the codes for each character in the string, checking the 6 char lookahead
for (var i = 0; i < asciiBytes.Length; i++)
{
- int thischar = asciiBytes[i];
- var nextchar = asciiBytes.Length > i + 1 ? asciiBytes[i + 1] : -1;
+ nextchar[0] = asciiBytes[i];
+ nextchar[1] = asciiBytes.Length > (i + 1) ? asciiBytes[i + 1] : -1;
+ nextchar[2] = asciiBytes.Length > (i + 2) ? asciiBytes[i + 2] : -1;
+ nextchar[3] = asciiBytes.Length > (i + 3) ? asciiBytes[i + 3] : -1;
+ nextchar[4] = asciiBytes.Length > (i + 4) ? asciiBytes[i + 4] : -1;
+ nextchar[5] = asciiBytes.Length > (i + 5) ? asciiBytes[i + 5] : -1;
- codes.AddRange(Code128Code.CodesForChar(thischar, nextchar, ref currentCodeSet));
+ codes.AddRange(Code128Code.CodesForChar(ref nextchar, ref currentCodeSet, ref i));
}
// calculate the check digit
@@ -71,22 +88,36 @@ private int[] StringToCode128(string asciiData)
}
///
- /// Determines the best starting code set based on the the first two
+ /// Determines the best starting code set based on the the
/// characters of the string to be encoded
///
- /// First character of input string
- /// Second character of input string
+ /// First 4 characters of input string
/// The codeset determined to be best to start with
- private CodeSet GetBestStartSet(Code128Code.CodeSetAllowed csa1, Code128Code.CodeSetAllowed csa2)
+ private CodeSet GetBestStartSet(Code128Code.CodeSetAllowed[] initChars)
{
- var vote = 0;
+ int vote = 0;
+ int votec = 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;
+ for (int i = 0; i < 4; i++)
+ {
+ switch (initChars[i])
+ {
+ case Code128Code.CodeSetAllowed.CodeA:
+ vote += 1;
+ break;
+ case Code128Code.CodeSetAllowed.CodeB:
+ vote -= 1;
+ break;
+ case Code128Code.CodeSetAllowed.CodeC:
+ votec += 2;
+ break;
+ /*default:
+ break;*/
+ }
+ }
- return vote > 0 ? CodeSet.CodeA : CodeSet.CodeB; // ties go to codeB due to my own prejudices
+ //Optimizing: 4+ or only 2 characters codeC. Otherwise, vote for codeA or codeB. Ties go to codeB due to my own prejudices
+ return (votec == 8 || (votec == 4 && vote == 0)) ? CodeSet.CodeC : ((vote > 0) ? CodeSet.CodeA : CodeSet.CodeB);
}
}
}
diff --git a/Source/GenCode128/Code128Rendering.cs b/Source/GenCode128/Code128Rendering.cs
index 0dd7fc1..20944dd 100644
--- a/Source/GenCode128/Code128Rendering.cs
+++ b/Source/GenCode128/Code128Rendering.cs
@@ -15,6 +15,9 @@ public static class Code128Rendering
// however, the last one -- STOP -- has 7. The cost of the
// extra integers is trivial, and this lets the code flow
// much more elegantly
+ // The code representes 1s and 0s, that always change and,
+ // this way, we can representa all with 6 elements.
+ // Reference: http://www.barcodeisland.com/code128.phtml
private static readonly int[,] CPatterns =
{
{ 2, 1, 2, 2, 2, 2, 0, 0 }, // 0
diff --git a/Source/GenCode128/CodeSet.cs b/Source/GenCode128/CodeSet.cs
index 07c7bd1..e56bbcc 100644
--- a/Source/GenCode128/CodeSet.cs
+++ b/Source/GenCode128/CodeSet.cs
@@ -3,7 +3,7 @@ namespace GenCode128
public enum CodeSet
{
CodeA,
- CodeB
- //// CodeC // not supported
+ CodeB,
+ CodeC
}
}
\ No newline at end of file