diff --git a/src/PdfSharp-gdi/PdfSharp-gdi.csproj b/src/PdfSharp-gdi/PdfSharp-gdi.csproj
index bc2a24bc..a29f7a86 100644
--- a/src/PdfSharp-gdi/PdfSharp-gdi.csproj
+++ b/src/PdfSharp-gdi/PdfSharp-gdi.csproj
@@ -132,6 +132,9 @@
Drawing.BarCodes\Code3of9Standard.cs
+
+ Drawing.BarCodes\Code128.cs
+
Drawing.BarCodes\CodeBase.cs
diff --git a/src/PdfSharp-wpf/PdfSharp-wpf.csproj b/src/PdfSharp-wpf/PdfSharp-wpf.csproj
index 123e3bb8..e544f6b4 100644
--- a/src/PdfSharp-wpf/PdfSharp-wpf.csproj
+++ b/src/PdfSharp-wpf/PdfSharp-wpf.csproj
@@ -102,6 +102,9 @@
Drawing.BarCodes\Code3of9Standard.cs
+
+ Drawing.BarCodes\Code128.cs
+
Drawing.BarCodes\CodeBase.cs
diff --git a/src/PdfSharp/Drawing.BarCodes/BcgSR.cs b/src/PdfSharp/Drawing.BarCodes/BcgSR.cs
index c4b5d5f8..9f4a2f43 100644
--- a/src/PdfSharp/Drawing.BarCodes/BcgSR.cs
+++ b/src/PdfSharp/Drawing.BarCodes/BcgSR.cs
@@ -89,5 +89,10 @@ internal static string DataMatrixInvalid(int columns, int rows)
{
return string.Format("'{1}'x'{0}' is an invalid ecc200 DataMatrix size.", columns, rows);
}
+
+ internal static string InvalidCode128(int code)
+ {
+ return string.Format("Contains an valid character for bar code 128 at index: {0}.", code);
+ }
}
}
diff --git a/src/PdfSharp/Drawing.BarCodes/Code128.cs b/src/PdfSharp/Drawing.BarCodes/Code128.cs
new file mode 100644
index 00000000..10aa6971
--- /dev/null
+++ b/src/PdfSharp/Drawing.BarCodes/Code128.cs
@@ -0,0 +1,421 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+using PdfSharp.Drawing;
+using PdfSharp.Drawing.BarCodes;
+
+namespace PdfSharp.Drawing.BarCodes
+{
+ /// A Class to be able to render a Code 128 bar code
+ /// For a more detailed explanation of the Code 128, please visit the following
+ /// web site: http://www.barcodeman.com/info/c128.php3
+ /// or
+ /// http://www.adams1.com/128code.html
+ ///
+ public class Code128 : BarCode
+ {
+ /// A static place holder for the patterns to draw the code 128 barcode
+ public static Dictionary Patterns = null;
+ private Code128CodeType Code128Code = Code128CodeType.CodeB;
+ private byte[] Values = null;
+ private const int CODE128_STOPCODE = 106;
+
+ /// Constructor
+ /// String - The text to be coded
+ /// XSize - The size of the bar code
+ /// CodeDirection - Indicates the direction to draw the bar code
+ public Code128(string text, XSize size, CodeDirection direction)
+ : this(text, size, direction, Code128CodeType.CodeB)
+ {
+ }
+
+ /// Constructor
+ /// String - The text to be coded
+ /// XSize - The size of the bar code
+ /// CodeDirection - Indicates the direction to draw the bar code
+ /// Code_128_Code_Types - Indicates which of the codes to use when rendering the bar code.
+ /// The options are A, B, or buffer.
+ public Code128(string text, XSize size, CodeDirection direction, Code128CodeType code128Code)
+ : this(null, text, size, direction, code128Code)
+ {
+ this.Text = text;
+
+ // Create the array to hold the values to be rendered
+ if (Code128Code == Code128CodeType.CodeC)
+ {
+ // Ensure that the text is an even length
+ //if ((text.Length % 2) == 1) throw new ArgumentOutOfRangeException("Parameter text (string) must have an even length for Code 128 - Code C");
+ if ((text.Length % 2) == 1)
+ text = "0" + text;
+
+ Values = new byte[text.Length / 2];
+ }
+ else
+ {
+ Values = new byte[text.Length];
+ }
+
+
+ string buffer = "";
+ for (int x = 0; x < text.Length; x++)
+ {
+ switch (Code128Code)
+ {
+ case Code128CodeType.CodeA:
+ if (text[x] < 32)
+ {
+ Values[x] = (byte)(text[x] + 64);
+ }
+ else if ((text[x] >= 32) && (text[x] < 64))
+ {
+ Values[x] = (byte)(text[x] - 32);
+ }
+ else
+ {
+ Values[x] = (byte)text[x];
+ }
+ break;
+
+ case Code128CodeType.CodeB:
+ Values[x] = (byte)(text[x] - 32);
+ break;
+
+ case Code128CodeType.CodeC:
+ if ((text[x] >= '0') && (text[x] <= '9'))
+ {
+ buffer += text[x];
+ if (buffer.Length == 2)
+ {
+ Values[x / 2] = byte.Parse(buffer);
+ buffer = "";
+ }
+ }
+ else
+ {
+ throw new ArgumentOutOfRangeException("Parameter text (string) can only contain numeric characters for Code 128 - Code C");
+ }
+ break;
+ }
+ }
+ CheckValues();
+ }
+
+
+ private void CheckValues()
+ {
+ if (Values == null) throw new InvalidOperationException("Text or Values must be set");
+ if (Values.Length == 0) throw new InvalidOperationException("Text or Values must have content");
+
+ for (int x = 0; x < Values.Length; x++)
+ {
+ if (Values[x] > 102) throw new ArgumentOutOfRangeException(BcgSR.InvalidCode128(x));
+ }
+ }
+
+ /// Constructor
+ /// byte[] - The values to be rendered
+ /// string - The text to be rendered
+ /// XSize - The size of the bar code
+ /// CodeDirection - Indicates the direction to draw the bar code
+ /// Code_128_Code_Types - Indicates which of the codes to use when rendering the bar code.
+ /// The options are A, B, or buffer.
+ public Code128(byte[] values, string text, XSize size, CodeDirection direction, Code128CodeType code128Code)
+ : base(text, size, direction)
+ {
+ if (!Enum.IsDefined(typeof(Code128CodeType), code128Code)) throw new ArgumentOutOfRangeException("Parameter code128Code (Code_128_Code_Types) is invalid");
+ if (Patterns == null) Load();
+ Code128Code = code128Code;
+ Values = values;
+ }
+
+ /// Creates a new instance of the Patterns field and populates it with the appropriate
+ /// pattern to draw a code 128 bar code
+ private void Load()
+ {
+ Patterns = new Dictionary();
+ Patterns.Add(0, new byte[] { 2, 1, 2, 2, 2, 2 });
+ Patterns.Add(1, new byte[] { 2, 2, 2, 1, 2, 2 });
+ Patterns.Add(2, new byte[] { 2, 2, 2, 2, 2, 1 });
+ Patterns.Add(3, new byte[] { 1, 2, 1, 2, 2, 3 });
+ Patterns.Add(4, new byte[] { 1, 2, 1, 3, 2, 2 });
+ Patterns.Add(5, new byte[] { 1, 3, 1, 2, 2, 2 });
+ Patterns.Add(6, new byte[] { 1, 2, 2, 2, 1, 3 });
+ Patterns.Add(7, new byte[] { 1, 2, 2, 3, 1, 2 });
+ Patterns.Add(8, new byte[] { 1, 3, 2, 2, 1, 2 });
+ Patterns.Add(9, new byte[] { 2, 2, 1, 2, 1, 3 });
+ Patterns.Add(10, new byte[] { 2, 2, 1, 3, 1, 2 });
+ Patterns.Add(11, new byte[] { 2, 3, 1, 2, 1, 2 });
+ Patterns.Add(12, new byte[] { 1, 1, 2, 2, 3, 2 });
+ Patterns.Add(13, new byte[] { 1, 2, 2, 1, 3, 2 });
+ Patterns.Add(14, new byte[] { 1, 2, 2, 2, 3, 1 });
+ Patterns.Add(15, new byte[] { 1, 1, 3, 2, 2, 2 });
+ Patterns.Add(16, new byte[] { 1, 2, 3, 1, 2, 2 });
+ Patterns.Add(17, new byte[] { 1, 2, 3, 2, 2, 1 });
+ Patterns.Add(18, new byte[] { 2, 2, 3, 2, 1, 1 });
+ Patterns.Add(19, new byte[] { 2, 2, 1, 1, 3, 2 });
+ Patterns.Add(20, new byte[] { 2, 2, 1, 2, 3, 1 });
+ Patterns.Add(21, new byte[] { 2, 1, 3, 2, 1, 2 });
+ Patterns.Add(22, new byte[] { 2, 2, 3, 1, 1, 2 });
+ Patterns.Add(23, new byte[] { 3, 1, 2, 1, 3, 1 });
+ Patterns.Add(24, new byte[] { 3, 1, 1, 2, 2, 2 });
+ Patterns.Add(25, new byte[] { 3, 2, 1, 1, 2, 2 });
+ Patterns.Add(26, new byte[] { 3, 2, 1, 2, 2, 1 });
+ Patterns.Add(27, new byte[] { 3, 1, 2, 2, 1, 2 });
+ Patterns.Add(28, new byte[] { 3, 2, 2, 1, 1, 2 });
+ Patterns.Add(29, new byte[] { 3, 2, 2, 2, 1, 1 });
+ Patterns.Add(30, new byte[] { 2, 1, 2, 1, 2, 3 });
+ Patterns.Add(31, new byte[] { 2, 1, 2, 3, 2, 1 });
+ Patterns.Add(32, new byte[] { 2, 3, 2, 1, 2, 1 });
+ Patterns.Add(33, new byte[] { 1, 1, 1, 3, 2, 3 });
+ Patterns.Add(34, new byte[] { 1, 3, 1, 1, 2, 3 });
+ Patterns.Add(35, new byte[] { 1, 3, 1, 3, 2, 1 });
+ Patterns.Add(36, new byte[] { 1, 1, 2, 3, 1, 3 });
+ Patterns.Add(37, new byte[] { 1, 3, 2, 1, 1, 3 });
+ Patterns.Add(38, new byte[] { 1, 3, 2, 3, 1, 1 });
+ Patterns.Add(39, new byte[] { 2, 1, 1, 3, 1, 3 });
+ Patterns.Add(40, new byte[] { 2, 3, 1, 1, 1, 3 });
+ Patterns.Add(41, new byte[] { 2, 3, 1, 3, 1, 1 });
+ Patterns.Add(42, new byte[] { 1, 1, 2, 1, 3, 3 });
+ Patterns.Add(43, new byte[] { 1, 1, 2, 3, 3, 1 });
+ Patterns.Add(44, new byte[] { 1, 3, 2, 1, 3, 1 });
+ Patterns.Add(45, new byte[] { 1, 1, 3, 1, 2, 3 });
+ Patterns.Add(46, new byte[] { 1, 1, 3, 3, 2, 1 });
+ Patterns.Add(47, new byte[] { 1, 3, 3, 1, 2, 1 });
+ Patterns.Add(48, new byte[] { 3, 1, 3, 1, 2, 1 });
+ Patterns.Add(49, new byte[] { 2, 1, 1, 3, 3, 1 });
+ Patterns.Add(50, new byte[] { 2, 3, 1, 1, 3, 1 });
+ Patterns.Add(51, new byte[] { 2, 1, 3, 1, 1, 3 });
+ Patterns.Add(52, new byte[] { 2, 1, 3, 3, 1, 1 });
+ Patterns.Add(53, new byte[] { 2, 1, 3, 1, 3, 1 });
+ Patterns.Add(54, new byte[] { 3, 1, 1, 1, 2, 3 });
+ Patterns.Add(55, new byte[] { 3, 1, 1, 3, 2, 1 });
+ Patterns.Add(56, new byte[] { 3, 3, 1, 1, 2, 1 });
+ Patterns.Add(57, new byte[] { 3, 1, 2, 1, 1, 3 });
+ Patterns.Add(58, new byte[] { 3, 1, 2, 3, 1, 1 });
+ Patterns.Add(59, new byte[] { 3, 3, 2, 1, 1, 1 });
+ Patterns.Add(60, new byte[] { 3, 1, 4, 1, 1, 1 });
+ Patterns.Add(61, new byte[] { 2, 2, 1, 4, 1, 1 });
+ Patterns.Add(62, new byte[] { 4, 3, 1, 1, 1, 1 });
+ Patterns.Add(63, new byte[] { 1, 1, 1, 2, 2, 4 });
+ Patterns.Add(64, new byte[] { 1, 1, 1, 4, 2, 2 });
+ Patterns.Add(65, new byte[] { 1, 2, 1, 1, 2, 4 });
+ Patterns.Add(66, new byte[] { 1, 2, 1, 4, 2, 1 });
+ Patterns.Add(67, new byte[] { 1, 4, 1, 1, 2, 2 });
+ Patterns.Add(68, new byte[] { 1, 4, 1, 2, 2, 1 });
+ Patterns.Add(69, new byte[] { 1, 1, 2, 2, 1, 4 });
+ Patterns.Add(70, new byte[] { 1, 1, 2, 4, 1, 2 });
+ Patterns.Add(71, new byte[] { 1, 2, 2, 1, 1, 4 });
+ Patterns.Add(72, new byte[] { 1, 2, 2, 4, 1, 1 });
+ Patterns.Add(73, new byte[] { 1, 4, 2, 1, 1, 2 });
+ Patterns.Add(74, new byte[] { 1, 4, 2, 2, 1, 1 });
+ Patterns.Add(75, new byte[] { 2, 4, 1, 2, 1, 1 });
+ Patterns.Add(76, new byte[] { 2, 2, 1, 1, 1, 4 });
+ Patterns.Add(77, new byte[] { 4, 1, 3, 1, 1, 1 });
+ Patterns.Add(78, new byte[] { 2, 4, 1, 1, 1, 2 });
+ Patterns.Add(79, new byte[] { 1, 3, 4, 1, 1, 1 });
+ Patterns.Add(80, new byte[] { 1, 1, 1, 2, 4, 2 });
+ Patterns.Add(81, new byte[] { 1, 2, 1, 1, 4, 2 });
+ Patterns.Add(82, new byte[] { 1, 2, 1, 2, 4, 1 });
+ Patterns.Add(83, new byte[] { 1, 1, 4, 2, 1, 2 });
+ Patterns.Add(84, new byte[] { 1, 2, 4, 1, 1, 2 });
+ Patterns.Add(85, new byte[] { 1, 2, 4, 2, 1, 1 });
+ Patterns.Add(86, new byte[] { 4, 1, 1, 2, 1, 2 });
+ Patterns.Add(87, new byte[] { 4, 2, 1, 1, 1, 2 });
+ Patterns.Add(88, new byte[] { 4, 2, 1, 2, 1, 1 });
+ Patterns.Add(89, new byte[] { 2, 1, 2, 1, 4, 1 });
+ Patterns.Add(90, new byte[] { 2, 1, 4, 1, 2, 1 });
+ Patterns.Add(91, new byte[] { 4, 1, 2, 1, 2, 1 });
+ Patterns.Add(92, new byte[] { 1, 1, 1, 1, 4, 3 });
+ Patterns.Add(93, new byte[] { 1, 1, 1, 3, 4, 1 });
+ Patterns.Add(94, new byte[] { 1, 3, 1, 1, 4, 1 });
+ Patterns.Add(95, new byte[] { 1, 1, 4, 1, 1, 3 });
+ Patterns.Add(96, new byte[] { 1, 1, 4, 3, 1, 1 });
+ Patterns.Add(97, new byte[] { 4, 1, 1, 1, 1, 3 });
+ Patterns.Add(98, new byte[] { 4, 1, 1, 3, 1, 1 });
+ Patterns.Add(99, new byte[] { 1, 1, 3, 1, 4, 1 });
+ Patterns.Add(100, new byte[] { 1, 1, 4, 1, 3, 1 });
+ Patterns.Add(101, new byte[] { 3, 1, 1, 1, 4, 1 });
+ Patterns.Add(102, new byte[] { 4, 1, 1, 1, 3, 1 });
+ Patterns.Add(103, new byte[] { 2, 1, 1, 4, 1, 2 });
+ Patterns.Add(104, new byte[] { 2, 1, 1, 2, 1, 4 });
+ Patterns.Add(105, new byte[] { 2, 1, 1, 2, 3, 2 });
+ Patterns.Add(106, new byte[] { 2, 3, 3, 1, 1, 1, 2 });
+ }
+
+ /// Validates the text string to be coded
+ /// String - The text string to be coded
+ protected override void CheckCode(string text)
+ {
+ if (text == null) throw new ArgumentNullException("Parameter text (string) can not be null");
+ if (text.Length == 0) throw new ArgumentException("Parameter text (string) can not be empty");
+ }
+
+ /// Renders the content found in Text
+ /// XGraphics - Instance of the drawing surface
+ /// XBrush - Line and Color to draw the bar code
+ /// XFont - Font to use to draw the text string
+ /// XPoint - Location to render the bar code
+ protected internal override void Render(XGraphics gfx, XBrush brush, XFont font, XPoint position)
+ {
+ XGraphicsState state = gfx.Save();
+
+ BarCodeRenderInfo info = new BarCodeRenderInfo(gfx, brush, font, position);
+ InitRendering(info);
+ info.CurrPosInString = 0;
+ info.CurrPos = position - CodeBase.CalcDistance(AnchorType.TopLeft, this.Anchor, this.Size);
+
+ RenderStart(info);
+ foreach (byte c in Values)
+ {
+ RenderValue(info, (int)c);
+ }
+ RenderStop(info);
+ if (TextLocation != TextLocation.None) RenderText(info);
+
+ gfx.Restore(state);
+ }
+
+ private void RenderStart(BarCodeRenderInfo info)
+ {
+ RenderValue(info, (int)Code128Code);
+ }
+
+ private void RenderStop(BarCodeRenderInfo info)
+ {
+ RenderValue(info, CalculateParity());
+ RenderValue(info, CODE128_STOPCODE);
+ }
+
+ private void RenderValue(BarCodeRenderInfo info, int chVal)
+ {
+ byte[] pattern = GetPattern(chVal);
+ XBrush space = XBrushes.White;
+ for (int idx = 0; idx < pattern.Length; idx++)
+ {
+ if ((idx % 2) == 0)
+ {
+ RenderBar(info, info.ThinBarWidth * pattern[idx]);
+ }
+ else
+ {
+ RenderBar(info, info.ThinBarWidth * pattern[idx], space);
+ }
+ }
+ }
+
+ private void RenderText(BarCodeRenderInfo info)
+ {
+ if (info.Font == null) info.Font = new XFont("Courier New", Size.Height / 6);
+ XPoint center = info.Position + CodeBase.CalcDistance(this.Anchor, AnchorType.TopLeft, this.Size);
+ if (TextLocation == TextLocation.Above)
+ {
+ info.Gfx.DrawString(this.Text, info.Font, info.Brush, new XRect(center, Size), XStringFormats.TopCenter);
+ }
+ else if (TextLocation == TextLocation.AboveEmbedded)
+ {
+ XSize textSize = info.Gfx.MeasureString(this.Text, info.Font);
+ textSize.Width += this.Size.Width * .15;
+ XPoint point = info.Position;
+ point.X += (this.Size.Width - textSize.Width) / 2;
+ XRect rect = new XRect(point, textSize);
+ info.Gfx.DrawRectangle(XBrushes.White, rect);
+ info.Gfx.DrawString(this.Text, info.Font, info.Brush, new XRect(center, Size), XStringFormats.TopCenter);
+ }
+ else if (TextLocation == TextLocation.Below)
+ {
+ info.Gfx.DrawString(this.Text, info.Font, info.Brush, new XRect(center, Size), XStringFormats.BottomCenter);
+ }
+ else if (TextLocation == TextLocation.BelowEmbedded)
+ {
+ XSize textSize = info.Gfx.MeasureString(this.Text, info.Font);
+ textSize.Width += this.Size.Width * .15;
+ XPoint point = info.Position;
+ point.X += (this.Size.Width - textSize.Width) / 2;
+ point.Y += Size.Height - textSize.Height;
+ XRect rect = new XRect(point, textSize);
+ info.Gfx.DrawRectangle(XBrushes.White, rect);
+ info.Gfx.DrawString(this.Text, info.Font, info.Brush, new XRect(center, Size), XStringFormats.BottomCenter);
+ }
+ }
+
+ private byte[] GetPattern(int codeValue)
+ {
+ if (codeValue < 0) throw new ArgumentOutOfRangeException("Parameter ch (int) can not be less than 32 (space).");
+ if (codeValue > 106) throw new ArgumentOutOfRangeException("Parameter ch (int) can not be greater than 138.");
+ return Patterns[(byte)codeValue];
+ }
+
+ private int CalculateParity()
+ {
+ long parityValue = (int)Code128Code;
+ for (int x = 1; x <= Values.Length; x++)
+ {
+ parityValue += ((Values[x - 1]) * x);
+ }
+ parityValue %= 103;
+ return (int)parityValue;
+ }
+
+ /// Renders a single line of the character. Each character has three lines and three spaces
+ ///
+ /// Indicates the thickness of the line/bar to be rendered.
+ internal void RenderBar(BarCodeRenderInfo info, double barWidth)
+ {
+ RenderBar(info, barWidth, info.Brush);
+ }
+
+ /// Renders a single line of the character. Each character has three lines and three spaces
+ ///
+ /// Indicates the thickness of the line/bar to be rendered.
+ /// Indicates the brush to use to render the line/bar.
+ private void RenderBar(BarCodeRenderInfo info, double barWidth, XBrush brush)
+ {
+ double height = Size.Height;
+ double yPos = info.CurrPos.Y;
+
+ switch (TextLocation)
+ {
+ case TextLocation.Above:
+ yPos = info.CurrPos.Y + (height / 5);
+ height *= 4.0 / 5;
+ break;
+ case TextLocation.Below:
+ height *= 4.0 / 5;
+ break;
+ case TextLocation.AboveEmbedded:
+ case TextLocation.BelowEmbedded:
+ case TextLocation.None:
+ break;
+ }
+ XRect rect = new XRect(info.CurrPos.X, yPos, barWidth, height);
+ info.Gfx.DrawRectangle(brush, rect);
+ info.CurrPos.X += barWidth;
+ }
+
+ internal override void InitRendering(BarCodeRenderInfo info)
+ {
+ if (Values == null) throw new InvalidOperationException(BcgSR.BarCodeNotSet);
+ if (Values.Length == 0) throw new InvalidOperationException(BcgSR.EmptyBarCodeSize);
+
+ int numberOfBars = Values.Length + 3; // The length of the string plus the start, stop, and parity value
+ numberOfBars *= 11; // Each character has 11 bars
+ numberOfBars += 2; // Add two more because the stop bit has two extra bars
+
+ // Calculating the width of a bar
+ info.ThinBarWidth = ((double)this.Size.Width / (double)numberOfBars);
+ }
+ }
+
+
+ /// Code types for Code 128 bar code
+ public enum Code128CodeType
+ {
+ /// Code A
+ CodeA = 103,
+ /// Code B
+ CodeB = 104,
+ /// Code buffer
+ CodeC = 105,
+ }
+}
\ No newline at end of file