From 7ba7e5519a8e952f1a41790bc98ee646a6214b57 Mon Sep 17 00:00:00 2001 From: Dan Ports Date: Tue, 20 Feb 2024 17:02:19 -0500 Subject: [PATCH 1/2] MigraDoc support for rendering barcodes and PDFSharp support for Code 128 barcodes. --- .../Rendering/BarcodeFormatInfo.cs | 21 + .../Rendering/BarcodeRenderInfo.cs | 24 ++ .../Rendering/BarcodeRenderer.cs | 96 +++++ .../MigraDoc.Rendering/Rendering/Renderer.cs | 4 + .../src/PdfSharp/Drawing.BarCodes/BcgSR.cs | 5 + .../src/PdfSharp/Drawing.BarCodes/Code128.cs | 383 ++++++++++++++++++ .../PdfSharp/Drawing.BarCodes/Code128Type.cs | 20 + 7 files changed, 553 insertions(+) create mode 100644 src/foundation/src/MigraDoc/src/MigraDoc.Rendering/Rendering/BarcodeFormatInfo.cs create mode 100644 src/foundation/src/MigraDoc/src/MigraDoc.Rendering/Rendering/BarcodeRenderInfo.cs create mode 100644 src/foundation/src/MigraDoc/src/MigraDoc.Rendering/Rendering/BarcodeRenderer.cs create mode 100644 src/foundation/src/PDFsharp/src/PdfSharp/Drawing.BarCodes/Code128.cs create mode 100644 src/foundation/src/PDFsharp/src/PdfSharp/Drawing.BarCodes/Code128Type.cs diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.Rendering/Rendering/BarcodeFormatInfo.cs b/src/foundation/src/MigraDoc/src/MigraDoc.Rendering/Rendering/BarcodeFormatInfo.cs new file mode 100644 index 00000000..13ac7bde --- /dev/null +++ b/src/foundation/src/MigraDoc/src/MigraDoc.Rendering/Rendering/BarcodeFormatInfo.cs @@ -0,0 +1,21 @@ +// PDFsharp - A .NET library for processing PDF +// See the LICENSE file in the solution root for more information. + +using System; +using PdfSharp.Drawing; + +namespace MigraDoc.Rendering +{ + /// + /// Formatting information for an barcode. + /// + internal class BarcodeFormatInfo : ShapeFormatInfo + { + internal BarcodeFormatInfo() + { + } + + internal XUnit Width; + internal XUnit Height; + } +} diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.Rendering/Rendering/BarcodeRenderInfo.cs b/src/foundation/src/MigraDoc/src/MigraDoc.Rendering/Rendering/BarcodeRenderInfo.cs new file mode 100644 index 00000000..63823317 --- /dev/null +++ b/src/foundation/src/MigraDoc/src/MigraDoc.Rendering/Rendering/BarcodeRenderInfo.cs @@ -0,0 +1,24 @@ +// PDFsharp - A .NET library for processing PDF +// See the LICENSE file in the solution root for more information. + +using System; + +namespace MigraDoc.Rendering +{ + /// + /// Represents rendering information for barcodes. + /// + internal class BarcodeRenderInfo : ShapeRenderInfo + { + public BarcodeRenderInfo() + { + } + + public override FormatInfo FormatInfo + { + get => _formatInfo; + internal set => _formatInfo = (BarcodeFormatInfo)value; + } + BarcodeFormatInfo _formatInfo = new(); + } +} diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.Rendering/Rendering/BarcodeRenderer.cs b/src/foundation/src/MigraDoc/src/MigraDoc.Rendering/Rendering/BarcodeRenderer.cs new file mode 100644 index 00000000..e1fbb95c --- /dev/null +++ b/src/foundation/src/MigraDoc/src/MigraDoc.Rendering/Rendering/BarcodeRenderer.cs @@ -0,0 +1,96 @@ +// PDFsharp - A .NET library for processing PDF +// See the LICENSE file in the solution root for more information. + +using System; +using System.IO; +using System.Diagnostics; +using MigraDoc.DocumentObjectModel; +using PdfSharp.Drawing; +using PdfSharp.Drawing.BarCodes; +using MigraDoc.DocumentObjectModel.Shapes; +using MigraDoc.Rendering.Resources; + +namespace MigraDoc.Rendering +{ + /// + /// Renders barcodes. + /// + // Adapted from https://forum.pdfsharp.net/viewtopic.php?p=3332#p3332 + internal class BarcodeRenderer : ShapeRenderer + { + internal BarcodeRenderer(XGraphics gfx, Barcode barcode, FieldInfos fieldInfos) + : base(gfx, barcode, fieldInfos) + { + this._barcode = barcode; + BarcodeRenderInfo renderInfo = new BarcodeRenderInfo(); + renderInfo.DocumentObject = this._shape; + this._renderInfo = renderInfo; + } + + internal BarcodeRenderer(XGraphics gfx, RenderInfo renderInfo, FieldInfos fieldInfos) + : base(gfx, renderInfo, fieldInfos) + { + this._barcode = (Barcode)renderInfo.DocumentObject; + } + + internal override void Format(Area area, FormatInfo previousFormatInfo) + { + BarcodeFormatInfo formatInfo = (BarcodeFormatInfo)this._renderInfo.FormatInfo; + + formatInfo.Height = this._barcode.Height.Point; + formatInfo.Width = this._barcode.Width.Point; + + base.Format(area, previousFormatInfo); + } + + protected override XUnit ShapeHeight + { + get + { + BarcodeFormatInfo formatInfo = (BarcodeFormatInfo)this._renderInfo.FormatInfo; + return formatInfo.Height + this._lineFormatRenderer.GetWidth(); + } + } + + protected override XUnit ShapeWidth + { + get + { + BarcodeFormatInfo formatInfo = (BarcodeFormatInfo)this._renderInfo.FormatInfo; + return formatInfo.Width + this._lineFormatRenderer.GetWidth(); + } + } + + internal override void Render() + { + RenderFilling(); + + BarcodeFormatInfo formatInfo = (BarcodeFormatInfo)this._renderInfo.FormatInfo; + Area contentArea = this._renderInfo.LayoutInfo.ContentArea; + XRect destRect = new XRect(contentArea.X, contentArea.Y, formatInfo.Width, formatInfo.Height); + + BarCode gfxBarcode = null; + + if (this._barcode.Type == BarcodeType.Barcode39) + gfxBarcode = new Code3of9Standard(); + else if (this._barcode.Type == BarcodeType.Barcode25i) + gfxBarcode = new Code2of5Interleaved(); + else if (this._barcode.Type == BarcodeType.Barcode128) + gfxBarcode = new Code128(); + + // if gfxBarcode is null, the barcode type is not supported + if (gfxBarcode != null) + { + gfxBarcode.Text = this._barcode.Code; + gfxBarcode.Direction = CodeDirection.LeftToRight; + gfxBarcode.Size = new XSize(ShapeWidth, ShapeHeight); + + this._gfx.DrawBarCode(gfxBarcode, XBrushes.Black, destRect.Location); + } + + RenderLine(); + } + + Barcode _barcode; + } +} diff --git a/src/foundation/src/MigraDoc/src/MigraDoc.Rendering/Rendering/Renderer.cs b/src/foundation/src/MigraDoc/src/MigraDoc.Rendering/Rendering/Renderer.cs index 5542c9eb..90e5368e 100644 --- a/src/foundation/src/MigraDoc/src/MigraDoc.Rendering/Rendering/Renderer.cs +++ b/src/foundation/src/MigraDoc/src/MigraDoc.Rendering/Rendering/Renderer.cs @@ -135,6 +135,8 @@ internal FieldInfos FieldInfos renderer = new ChartRenderer(gfx, chart, fieldInfos); else if (documentObject is Image image) renderer = new ImageRenderer(gfx, image, fieldInfos); + else if (documentObject is Barcode) + renderer = new BarcodeRenderer(gfx, (Barcode)documentObject, fieldInfos); if (renderer != null) renderer._documentRenderer = documentRenderer; @@ -172,6 +174,8 @@ internal static Renderer Create(XGraphics gfx, DocumentRenderer documentRenderer // renderer = new ChartRenderer(gfx, renderInfo, fieldInfos); else if (renderInfo.DocumentObject is Image) renderer = new ImageRenderer(gfx, renderInfo, fieldInfos); + else if (renderInfo.DocumentObject is Barcode) + renderer = new BarcodeRenderer(gfx, renderInfo, fieldInfos); if (renderer != null) renderer._documentRenderer = documentRenderer; diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.BarCodes/BcgSR.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.BarCodes/BcgSR.cs index deb29c78..adcd6482 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.BarCodes/BcgSR.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.BarCodes/BcgSR.cs @@ -42,5 +42,10 @@ internal static string DataMatrixInvalid(int columns, int rows) { return $"'{rows}'x'{columns}' is an invalid ecc200 DataMatrix size."; } + + internal static string InvalidCode128(int index) + { + return $"Invalid character for Code 128 at index {index}."; + } } } diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.BarCodes/Code128.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.BarCodes/Code128.cs new file mode 100644 index 00000000..7d97b268 --- /dev/null +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.BarCodes/Code128.cs @@ -0,0 +1,383 @@ +using System; +using System.Collections.Generic; +using System.Text; + +using PdfSharp.Drawing; +using PdfSharp.Drawing.BarCodes; + +namespace PdfSharp.Drawing.BarCodes +{ + /// A class 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 + /// + // Adapted from http://forum.pdfsharp.com/viewtopic.php?f=4&t=1089#p2978 + public class Code128 : BarCode + { + private static Dictionary Patterns; + private const int CODE128_STOPCODE = 106; + private byte[] _values = null; + private Code128Type _type = Code128Type.CodeC; + + /// Creates a new instance of the Patterns field and populates it with the appropriate + /// pattern to draw a code 128 bar code + static Code128() + { + 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 }); + } + + /// Constructor + public Code128() + : base("", XSize.Empty, CodeDirection.LeftToRight) + { } + + /// 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, Code128Type.CodeC) + { + } + + /// 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. + public Code128(string text, XSize size, CodeDirection direction, Code128Type code128Code) + : base(text, size, direction) + { + _type = code128Code; + } + + private void GenerateValues() + { + // Create the array to hold the values to be rendered + if (_type == Code128Type.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"); + _values = new byte[Text.Length / 2]; + } + else + { + _values = new byte[Text.Length]; + } + + string buffer = string.Empty; + for (int x = 0; x < Text.Length; x++) + { + switch (_type) + { + case Code128Type.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 Code128Type.CodeB: + _values[x] = (byte)(Text[x] - 32); + break; + + case Code128Type.CodeC: + if ((Text[x] >= '0') && (Text[x] <= '9')) + { + buffer += Text[x]; + if (buffer.Length == 2) + { + _values[x / 2] = byte.Parse(buffer); + buffer = string.Empty; + } + } + else + { + throw new ArgumentOutOfRangeException("Parameter text (string) can only contain numeric characters for Code 128 - Code C"); + } + break; + } + } + + for (int x = 0; x < _values.Length; x++) + { + if (_values[x] > 102) throw new ArgumentOutOfRangeException(BcgSR.InvalidCode128(x)); + } + } + + /// 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, Anchor, 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)_type); + } + + 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(Anchor, AnchorType.TopLeft, Size); + if (TextLocation == TextLocation.Above) + { + info.Gfx.DrawString(Text, info.Font, info.Brush, new XRect(center, Size), XStringFormat.TopCenter); + } + else if (TextLocation == TextLocation.AboveEmbedded) + { + XSize textSize = info.Gfx.MeasureString(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(Text, info.Font, info.Brush, new XRect(center, Size), XStringFormat.TopCenter); + } + else if (TextLocation == TextLocation.Below) + { + info.Gfx.DrawString(Text, info.Font, info.Brush, new XRect(center, Size), XStringFormat.BottomCenter); + } + else if (TextLocation == TextLocation.BelowEmbedded) + { + XSize textSize = info.Gfx.MeasureString(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(Text, info.Font, info.Brush, new XRect(center, Size), XStringFormat.BottomCenter); + } + } + + private byte[] GetPattern(int codeValue) + { + if (codeValue < 0) throw new ArgumentOutOfRangeException("Parameter ch (int) can not be less than 0."); + if (codeValue > 106) throw new ArgumentOutOfRangeException("Parameter ch (int) can not be greater than 106."); + return Patterns[(byte)codeValue]; + } + + private int CalculateParity() + { + long parityValue = (int)_type; + 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 (Text == null) throw new InvalidOperationException(BcgSR.BarCodeNotSet); + if (Text.Length == 0) throw new InvalidOperationException(BcgSR.EmptyBarCodeSize); + + GenerateValues(); + + 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 + info.ThinBarWidth = ((double)this.Size.Width / (double)numberOfBars); + } + + protected override void CheckCode(String text) + { + } + } +} \ No newline at end of file diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.BarCodes/Code128Type.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.BarCodes/Code128Type.cs new file mode 100644 index 00000000..71dce428 --- /dev/null +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.BarCodes/Code128Type.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Text; + +using PdfSharp.Drawing; +using PdfSharp.Drawing.BarCodes; + +namespace PdfSharp.Drawing.BarCodes +{ + /// Code types for Code 128 bar code + public enum Code128Type + { + /// Code A + CodeA = 103, + /// Code B + CodeB = 104, + /// Code C + CodeC = 105, + } +} \ No newline at end of file From 9b81f8e72a189d489be07fc50c22f67d9a2d200f Mon Sep 17 00:00:00 2001 From: Dan Ports Date: Sat, 24 Feb 2024 22:40:14 -0500 Subject: [PATCH 2/2] Better to default to subtype B for Code 128 as was done in the original code. --- .../src/PdfSharp/Drawing.BarCodes/Code128.cs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.BarCodes/Code128.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.BarCodes/Code128.cs index 7d97b268..266b57c9 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.BarCodes/Code128.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Drawing.BarCodes/Code128.cs @@ -17,8 +17,8 @@ public class Code128 : BarCode { private static Dictionary Patterns; private const int CODE128_STOPCODE = 106; - private byte[] _values = null; - private Code128Type _type = Code128Type.CodeC; + private byte[] _values; + private Code128Type _type; /// Creates a new instance of the Patterns field and populates it with the appropriate /// pattern to draw a code 128 bar code @@ -136,7 +136,7 @@ static Code128() /// Constructor public Code128() - : base("", XSize.Empty, CodeDirection.LeftToRight) + : this("", XSize.Empty, CodeDirection.LeftToRight) { } /// Constructor @@ -144,7 +144,7 @@ public Code128() /// 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, Code128Type.CodeC) + : this(text, size, direction, Code128Type.CodeB) { } @@ -161,11 +161,10 @@ public Code128(string text, XSize size, CodeDirection direction, Code128Type cod private void GenerateValues() { - // Create the array to hold the values to be rendered if (_type == Code128Type.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) + throw new ArgumentOutOfRangeException("Parameter text (string) must have an even length for Code 128 - Code C"); _values = new byte[Text.Length / 2]; } else